diff options
author | Andreas Färber <andreas.faerber@web.de> | 2013-01-10 21:52:28 +0100 |
---|---|---|
committer | Andreas Färber <andreas.faerber@web.de> | 2013-01-10 21:52:28 +0100 |
commit | 63e3555e80c31776285accbb4d0c14ae91c457dc (patch) | |
tree | 89907c82724d6519c8bbad7acc15c0198c6f902f /hw | |
parent | 52a71bff6085398fbb8602718af228cd6339c02d (diff) | |
parent | a6308bc2224db238e72c570482717b68246a7ce0 (diff) |
Merge branch 'master' of git://git.qemu.org/qemu into prep-up
Conflicts:
hw/Makefile.objs
hw/ppc_prep.c
Signed-off-by: Andreas Färber <andreas.faerber@web.de>
Diffstat (limited to 'hw')
646 files changed, 32412 insertions, 12708 deletions
diff --git a/hw/9pfs/Makefile.objs b/hw/9pfs/Makefile.objs index 972df24050..1e9b595cb4 100644 --- a/hw/9pfs/Makefile.objs +++ b/hw/9pfs/Makefile.objs @@ -1,9 +1,9 @@ -hw-obj-y = virtio-9p.o -hw-obj-y += virtio-9p-local.o virtio-9p-xattr.o -hw-obj-y += virtio-9p-xattr-user.o virtio-9p-posix-acl.o -hw-obj-y += virtio-9p-coth.o cofs.o codir.o cofile.o -hw-obj-y += coxattr.o virtio-9p-synth.o -hw-obj-$(CONFIG_OPEN_BY_HANDLE) += virtio-9p-handle.o -hw-obj-y += virtio-9p-proxy.o +common-obj-y = virtio-9p.o +common-obj-y += virtio-9p-local.o virtio-9p-xattr.o +common-obj-y += virtio-9p-xattr-user.o virtio-9p-posix-acl.o +common-obj-y += virtio-9p-coth.o cofs.o codir.o cofile.o +common-obj-y += coxattr.o virtio-9p-synth.o +common-obj-$(CONFIG_OPEN_BY_HANDLE) += virtio-9p-handle.o +common-obj-y += virtio-9p-proxy.o obj-y += virtio-9p-device.o diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c index 3d188284ba..65ad3298be 100644 --- a/hw/9pfs/codir.c +++ b/hw/9pfs/codir.c @@ -13,8 +13,8 @@ */ #include "fsdev/qemu-fsdev.h" -#include "qemu-thread.h" -#include "qemu-coroutine.h" +#include "qemu/thread.h" +#include "block/coroutine.h" #include "virtio-9p-coth.h" int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent *dent, diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c index 9345aaeb2e..2efebf3571 100644 --- a/hw/9pfs/cofile.c +++ b/hw/9pfs/cofile.c @@ -13,8 +13,8 @@ */ #include "fsdev/qemu-fsdev.h" -#include "qemu-thread.h" -#include "qemu-coroutine.h" +#include "qemu/thread.h" +#include "block/coroutine.h" #include "virtio-9p-coth.h" int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode, diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c index 83f125bd47..3891050748 100644 --- a/hw/9pfs/cofs.c +++ b/hw/9pfs/cofs.c @@ -13,8 +13,8 @@ */ #include "fsdev/qemu-fsdev.h" -#include "qemu-thread.h" -#include "qemu-coroutine.h" +#include "qemu/thread.h" +#include "block/coroutine.h" #include "virtio-9p-coth.h" int v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf) diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c index 8a48228702..18ee08df0f 100644 --- a/hw/9pfs/coxattr.c +++ b/hw/9pfs/coxattr.c @@ -13,8 +13,8 @@ */ #include "fsdev/qemu-fsdev.h" -#include "qemu-thread.h" -#include "qemu-coroutine.h" +#include "qemu/thread.h" +#include "block/coroutine.h" #include "virtio-9p-coth.h" int v9fs_co_llistxattr(V9fsPDU *pdu, V9fsPath *path, void *value, size_t size) diff --git a/hw/9pfs/virtio-9p-coth.c b/hw/9pfs/virtio-9p-coth.c index 25556cc6a7..ae6cde8005 100644 --- a/hw/9pfs/virtio-9p-coth.c +++ b/hw/9pfs/virtio-9p-coth.c @@ -12,10 +12,9 @@ * */ -#include "qemu-char.h" #include "fsdev/qemu-fsdev.h" -#include "qemu-thread.h" -#include "qemu-coroutine.h" +#include "qemu/thread.h" +#include "block/coroutine.h" #include "virtio-9p-coth.h" /* v9fs glib thread pool */ diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h index c31c96578b..86d5ed4169 100644 --- a/hw/9pfs/virtio-9p-coth.h +++ b/hw/9pfs/virtio-9p-coth.h @@ -15,8 +15,8 @@ #ifndef _QEMU_VIRTIO_9P_COTH_H #define _QEMU_VIRTIO_9P_COTH_H -#include "qemu-thread.h" -#include "qemu-coroutine.h" +#include "qemu/thread.h" +#include "block/coroutine.h" #include "virtio-9p.h" #include <glib.h> diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index b8220abae7..6761bce9dc 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -13,7 +13,7 @@ #include "hw/virtio.h" #include "hw/pc.h" -#include "qemu_socket.h" +#include "qemu/sockets.h" #include "hw/virtio-pci.h" #include "virtio-9p.h" #include "fsdev/qemu-fsdev.h" diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c index f96d17a974..e30fdb6730 100644 --- a/hw/9pfs/virtio-9p-handle.c +++ b/hw/9pfs/virtio-9p-handle.c @@ -19,7 +19,7 @@ #include <grp.h> #include <sys/socket.h> #include <sys/un.h> -#include "qemu-xattr.h" +#include "qemu/xattr.h" #include <unistd.h> #include <linux/fs.h> #ifdef CONFIG_LINUX_MAGIC_H diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c index 33a41d2e18..113602144c 100644 --- a/hw/9pfs/virtio-9p-local.c +++ b/hw/9pfs/virtio-9p-local.c @@ -19,7 +19,7 @@ #include <grp.h> #include <sys/socket.h> #include <sys/un.h> -#include "qemu-xattr.h" +#include "qemu/xattr.h" #include <libgen.h> #include <linux/fs.h> #ifdef CONFIG_LINUX_MAGIC_H diff --git a/hw/9pfs/virtio-9p-posix-acl.c b/hw/9pfs/virtio-9p-posix-acl.c index a1948e3aff..08bb0e8bca 100644 --- a/hw/9pfs/virtio-9p-posix-acl.c +++ b/hw/9pfs/virtio-9p-posix-acl.c @@ -12,7 +12,7 @@ */ #include <sys/types.h> -#include "qemu-xattr.h" +#include "qemu/xattr.h" #include "hw/virtio.h" #include "virtio-9p.h" #include "fsdev/file-op-9p.h" @@ -44,7 +44,8 @@ static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path, return -1; } - strncpy(value, ACL_ACCESS, len); + /* len includes the trailing NUL */ + memcpy(value, ACL_ACCESS, len); return 0; } @@ -95,7 +96,8 @@ static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path, return -1; } - strncpy(value, ACL_DEFAULT, len); + /* len includes the trailing NUL */ + memcpy(value, ACL_ACCESS, len); return 0; } diff --git a/hw/9pfs/virtio-9p-synth.c b/hw/9pfs/virtio-9p-synth.c index 92e0b09d38..e95a856d25 100644 --- a/hw/9pfs/virtio-9p-synth.c +++ b/hw/9pfs/virtio-9p-synth.c @@ -58,7 +58,7 @@ static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode, node->attr->read = NULL; } node->private = node; - strncpy(node->name, name, sizeof(node->name)); + pstrcpy(node->name, sizeof(node->name), name); QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling); return node; } @@ -132,7 +132,7 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, node->attr->write = write; node->attr->mode = mode; node->private = arg; - strncpy(node->name, name, sizeof(node->name)); + pstrcpy(node->name, sizeof(node->name), name); QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling); ret = 0; err_out: diff --git a/hw/9pfs/virtio-9p-synth.h b/hw/9pfs/virtio-9p-synth.h index e03f434633..ab05a8e78c 100644 --- a/hw/9pfs/virtio-9p-synth.h +++ b/hw/9pfs/virtio-9p-synth.h @@ -10,6 +10,8 @@ * the COPYING file in the top-level directory. * */ +#ifndef HW_9PFS_VIRTIO9P_SYNTH_H +#define HW_9PFS_VIRTIO9P_SYNTH_H 1 #include <unistd.h> #include <sys/types.h> @@ -48,3 +50,5 @@ extern int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode, extern int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, const char *name, v9fs_synth_read read, v9fs_synth_write write, void *arg); + +#endif diff --git a/hw/9pfs/virtio-9p-xattr-user.c b/hw/9pfs/virtio-9p-xattr-user.c index 5044a3e5ab..5bb6020070 100644 --- a/hw/9pfs/virtio-9p-xattr-user.c +++ b/hw/9pfs/virtio-9p-xattr-user.c @@ -61,7 +61,8 @@ static ssize_t mp_user_listxattr(FsContext *ctx, const char *path, return -1; } - strncpy(value, name, name_size); + /* name_size includes the trailing NUL. */ + memcpy(value, name, name_size); return name_size; } diff --git a/hw/9pfs/virtio-9p-xattr.c b/hw/9pfs/virtio-9p-xattr.c index 7f08f6e176..a83960676d 100644 --- a/hw/9pfs/virtio-9p-xattr.c +++ b/hw/9pfs/virtio-9p-xattr.c @@ -53,7 +53,8 @@ ssize_t pt_listxattr(FsContext *ctx, const char *path, return -1; } - strncpy(value, name, name_size); + /* no need for strncpy: name_size is strlen(name)+1 */ + memcpy(value, name, name_size); return name_size; } diff --git a/hw/9pfs/virtio-9p-xattr.h b/hw/9pfs/virtio-9p-xattr.h index 9437280c99..41cc6cbc7b 100644 --- a/hw/9pfs/virtio-9p-xattr.h +++ b/hw/9pfs/virtio-9p-xattr.h @@ -13,7 +13,7 @@ #ifndef _QEMU_VIRTIO_9P_XATTR_H #define _QEMU_VIRTIO_9P_XATTR_H -#include "qemu-xattr.h" +#include "qemu/xattr.h" typedef struct xattr_operations { diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index 4b52540116..0aaf0d2de0 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -13,14 +13,14 @@ #include "hw/virtio.h" #include "hw/pc.h" -#include "qemu_socket.h" +#include "qemu/sockets.h" #include "hw/virtio-pci.h" #include "virtio-9p.h" #include "fsdev/qemu-fsdev.h" #include "virtio-9p-xattr.h" #include "virtio-9p-coth.h" #include "trace.h" -#include "migration.h" +#include "migration/migration.h" int open_fd_hw; int total_open_fd; @@ -505,7 +505,6 @@ static void virtfs_reset(V9fsPDU *pdu) error_report("9pfs:%s: One or more uncluncked fids " "found during reset", __func__); } - return; } #define P9_QID_TYPE_DIR 0x80 @@ -934,7 +933,6 @@ static void v9fs_version(void *opaque) out: complete_pdu(s, pdu, offset); v9fs_string_free(&version); - return; } static void v9fs_attach(void *opaque) @@ -1314,7 +1312,6 @@ out_nofid: g_free(wnames); g_free(qids); } - return; } static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path) @@ -2257,7 +2254,6 @@ static void v9fs_flush(void *opaque) free_pdu(pdu->s, cancel_pdu); } complete_pdu(s, pdu, 7); - return; } static void v9fs_link(void *opaque) @@ -2763,7 +2759,6 @@ out: put_fid(pdu, fidp); out_nofid: complete_pdu(s, pdu, retval); - return; } static void v9fs_mknod(void *opaque) diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 579794404b..406fe522db 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -9,8 +9,8 @@ #include "hw/virtio.h" #include "fsdev/file-op-9p.h" #include "fsdev/virtio-9p-marshal.h" -#include "qemu-thread.h" -#include "qemu-coroutine.h" +#include "qemu/thread.h" +#include "block/coroutine.h" /* The feature bitmap for virtio 9P */ diff --git a/hw/Makefile.objs b/hw/Makefile.objs index aab0a469bb..d8671847fe 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -1,139 +1,148 @@ -hw-obj-y = usb/ ide/ -hw-obj-y += loader.o -hw-obj-$(CONFIG_VIRTIO) += virtio-console.o -hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o -hw-obj-y += fw_cfg.o -hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o pci_bridge_dev.o -hw-obj-$(CONFIG_PCI) += msix.o msi.o -hw-obj-$(CONFIG_PCI) += shpc.o -hw-obj-$(CONFIG_PCI) += slotid_cap.o -hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o -hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o -hw-obj-y += watchdog.o -hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o -hw-obj-$(CONFIG_ECC) += ecc.o -hw-obj-$(CONFIG_NAND) += nand.o -hw-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o -hw-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o - -hw-obj-$(CONFIG_M48T59) += m48t59.o -hw-obj-$(CONFIG_ESCC) += escc.o -hw-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o - -hw-obj-$(CONFIG_SERIAL) += serial.o -hw-obj-$(CONFIG_PARALLEL) += parallel.o -hw-obj-$(CONFIG_I8254) += i8254_common.o i8254.o -hw-obj-$(CONFIG_PCSPK) += pcspk.o -hw-obj-$(CONFIG_PCKBD) += pckbd.o -hw-obj-$(CONFIG_FDC) += fdc.o -hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o -hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o -hw-obj-$(CONFIG_DMA) += dma.o -hw-obj-$(CONFIG_I82374) += i82374.o -hw-obj-$(CONFIG_HPET) += hpet.o -hw-obj-$(CONFIG_APPLESMC) += applesmc.o -hw-obj-$(CONFIG_SMARTCARD) += ccid-card-passthru.o -hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o -hw-obj-$(CONFIG_I8259) += i8259_common.o i8259.o +# core qdev-related obj files, also used by *-user: +hw-core-obj-y += qdev.o qdev-properties.o +# irq.o needed for qdev GPIO handling: +hw-core-obj-y += irq.o + + +common-obj-y = usb/ ide/ pci/ +common-obj-y += loader.o +common-obj-$(CONFIG_VIRTIO) += virtio-console.o +common-obj-$(CONFIG_VIRTIO) += virtio-rng.o +common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o +common-obj-y += fw_cfg.o +common-obj-$(CONFIG_PCI) += pci_bridge_dev.o +common-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o +common-obj-$(CONFIG_PCI) += i82801b11.o +common-obj-y += watchdog.o +common-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o +common-obj-$(CONFIG_ECC) += ecc.o +common-obj-$(CONFIG_NAND) += nand.o +common-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o +common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o + +common-obj-$(CONFIG_M48T59) += m48t59.o +common-obj-$(CONFIG_ESCC) += escc.o +common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o + +common-obj-$(CONFIG_SERIAL) += serial.o serial-isa.o +common-obj-$(CONFIG_SERIAL_PCI) += serial-pci.o +common-obj-$(CONFIG_PARALLEL) += parallel.o +common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o +common-obj-$(CONFIG_PCSPK) += pcspk.o +common-obj-$(CONFIG_PCKBD) += pckbd.o +common-obj-$(CONFIG_FDC) += fdc.o +common-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o acpi_ich9.o smbus_ich9.o +common-obj-$(CONFIG_APM) += pm_smbus.o apm.o +common-obj-$(CONFIG_DMA) += dma.o +common-obj-$(CONFIG_I82374) += i82374.o +common-obj-$(CONFIG_HPET) += hpet.o +common-obj-$(CONFIG_APPLESMC) += applesmc.o +common-obj-$(CONFIG_SMARTCARD) += ccid-card-passthru.o +common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o +common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o +common-obj-y += fifo.o +common-obj-y += pam.o + +extra-obj-y += pci/ # PPC devices -hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o -hw-obj-$(CONFIG_I82378) += i82378.o -hw-obj-$(CONFIG_PC87312) += pc87312.o +common-obj-$(CONFIG_PREP_PCI) += prep_pci.o +common-obj-$(CONFIG_I82378) += i82378.o +common-obj-$(CONFIG_PC87312) += pc87312.o # Mac shared devices -hw-obj-$(CONFIG_MACIO) += macio.o -hw-obj-$(CONFIG_CUDA) += cuda.o -hw-obj-$(CONFIG_ADB) += adb.o -hw-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o -hw-obj-$(CONFIG_MAC_DBDMA) += mac_dbdma.o +common-obj-$(CONFIG_MACIO) += macio.o +common-obj-$(CONFIG_CUDA) += cuda.o +common-obj-$(CONFIG_ADB) += adb.o +common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o +common-obj-$(CONFIG_MAC_DBDMA) += mac_dbdma.o # OldWorld PowerMac -hw-obj-$(CONFIG_HEATHROW_PIC) += heathrow_pic.o -hw-obj-$(CONFIG_GRACKLE_PCI) += grackle_pci.o +common-obj-$(CONFIG_HEATHROW_PIC) += heathrow_pic.o +common-obj-$(CONFIG_GRACKLE_PCI) += grackle_pci.o # NewWorld PowerMac -hw-obj-$(CONFIG_UNIN_PCI) += unin_pci.o -hw-obj-$(CONFIG_DEC_PCI) += dec_pci.o +common-obj-$(CONFIG_UNIN_PCI) += unin_pci.o +common-obj-$(CONFIG_DEC_PCI) += dec_pci.o # PowerPC E500 boards -hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o +common-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o # MIPS devices -hw-obj-$(CONFIG_PIIX4) += piix4.o -hw-obj-$(CONFIG_G364FB) += g364fb.o -hw-obj-$(CONFIG_JAZZ_LED) += jazz_led.o +common-obj-$(CONFIG_PIIX4) += piix4.o +common-obj-$(CONFIG_G364FB) += g364fb.o +common-obj-$(CONFIG_JAZZ_LED) += jazz_led.o # Xilinx devices -hw-obj-$(CONFIG_XILINX) += xilinx_intc.o -hw-obj-$(CONFIG_XILINX) += xilinx_timer.o -hw-obj-$(CONFIG_XILINX) += xilinx_uartlite.o -hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o -hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o -hw-obj-$(CONFIG_XILINX_AXI) += stream.o +common-obj-$(CONFIG_XILINX) += xilinx_intc.o +common-obj-$(CONFIG_XILINX) += xilinx_timer.o +common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o +common-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o +common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o +common-obj-$(CONFIG_XILINX_AXI) += stream.o # PKUnity SoC devices -hw-obj-$(CONFIG_PUV3) += puv3_intc.o -hw-obj-$(CONFIG_PUV3) += puv3_ost.o -hw-obj-$(CONFIG_PUV3) += puv3_gpio.o -hw-obj-$(CONFIG_PUV3) += puv3_pm.o -hw-obj-$(CONFIG_PUV3) += puv3_dma.o +common-obj-$(CONFIG_PUV3) += puv3_intc.o +common-obj-$(CONFIG_PUV3) += puv3_ost.o +common-obj-$(CONFIG_PUV3) += puv3_gpio.o +common-obj-$(CONFIG_PUV3) += puv3_pm.o +common-obj-$(CONFIG_PUV3) += puv3_dma.o # ARM devices -hw-obj-$(CONFIG_ARM_TIMER) += arm_timer.o -hw-obj-$(CONFIG_PL011) += pl011.o -hw-obj-$(CONFIG_PL022) += pl022.o -hw-obj-$(CONFIG_PL031) += pl031.o -hw-obj-$(CONFIG_PL041) += pl041.o lm4549.o -hw-obj-$(CONFIG_PL050) += pl050.o -hw-obj-$(CONFIG_PL061) += pl061.o -hw-obj-$(CONFIG_PL080) += pl080.o -hw-obj-$(CONFIG_PL110) += pl110.o -hw-obj-$(CONFIG_PL181) += pl181.o -hw-obj-$(CONFIG_PL190) += pl190.o -hw-obj-$(CONFIG_PL310) += arm_l2x0.o -hw-obj-$(CONFIG_VERSATILE_PCI) += versatile_pci.o -hw-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o -hw-obj-$(CONFIG_CADENCE) += cadence_uart.o -hw-obj-$(CONFIG_CADENCE) += cadence_ttc.o -hw-obj-$(CONFIG_CADENCE) += cadence_gem.o -hw-obj-$(CONFIG_XGMAC) += xgmac.o +common-obj-$(CONFIG_ARM_TIMER) += arm_timer.o +common-obj-$(CONFIG_PL011) += pl011.o +common-obj-$(CONFIG_PL022) += pl022.o +common-obj-$(CONFIG_PL031) += pl031.o +common-obj-$(CONFIG_PL041) += pl041.o lm4549.o +common-obj-$(CONFIG_PL050) += pl050.o +common-obj-$(CONFIG_PL061) += pl061.o +common-obj-$(CONFIG_PL080) += pl080.o +common-obj-$(CONFIG_PL110) += pl110.o +common-obj-$(CONFIG_PL181) += pl181.o +common-obj-$(CONFIG_PL190) += pl190.o +common-obj-$(CONFIG_PL310) += arm_l2x0.o +common-obj-$(CONFIG_VERSATILE_PCI) += versatile_pci.o +common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o +common-obj-$(CONFIG_CADENCE) += cadence_uart.o +common-obj-$(CONFIG_CADENCE) += cadence_ttc.o +common-obj-$(CONFIG_CADENCE) += cadence_gem.o +common-obj-$(CONFIG_XGMAC) += xgmac.o # PCI watchdog devices -hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o - -hw-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o +common-obj-$(CONFIG_PCI) += wdt_i6300esb.o # PCI network cards -hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o -hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o -hw-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o -hw-obj-$(CONFIG_PCNET_COMMON) += pcnet.o -hw-obj-$(CONFIG_E1000_PCI) += e1000.o -hw-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o - -hw-obj-$(CONFIG_SMC91C111) += smc91c111.o -hw-obj-$(CONFIG_LAN9118) += lan9118.o -hw-obj-$(CONFIG_NE2000_ISA) += ne2000-isa.o -hw-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.o +common-obj-$(CONFIG_NE2000_PCI) += ne2000.o +common-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o +common-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o +common-obj-$(CONFIG_PCNET_COMMON) += pcnet.o +common-obj-$(CONFIG_E1000_PCI) += e1000.o +common-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o + +common-obj-$(CONFIG_SMC91C111) += smc91c111.o +common-obj-$(CONFIG_LAN9118) += lan9118.o +common-obj-$(CONFIG_NE2000_ISA) += ne2000-isa.o +common-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.o # SCSI layer -hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o -hw-obj-$(CONFIG_MEGASAS_SCSI_PCI) += megasas.o -hw-obj-$(CONFIG_ESP) += esp.o -hw-obj-$(CONFIG_ESP_PCI) += esp-pci.o +common-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o +common-obj-$(CONFIG_MEGASAS_SCSI_PCI) += megasas.o +common-obj-$(CONFIG_ESP) += esp.o +common-obj-$(CONFIG_ESP_PCI) += esp-pci.o -hw-obj-y += sysbus.o isa-bus.o -hw-obj-y += qdev-addr.o +common-obj-y += sysbus.o isa-bus.o +common-obj-y += qdev-addr.o # VGA -hw-obj-$(CONFIG_VGA_PCI) += vga-pci.o -hw-obj-$(CONFIG_VGA_ISA) += vga-isa.o -hw-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o -hw-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o -hw-obj-$(CONFIG_VMMOUSE) += vmmouse.o -hw-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o - -hw-obj-$(CONFIG_RC4030) += rc4030.o -hw-obj-$(CONFIG_DP8393X) += dp8393x.o -hw-obj-$(CONFIG_DS1225Y) += ds1225y.o -hw-obj-$(CONFIG_MIPSNET) += mipsnet.o +common-obj-$(CONFIG_VGA_PCI) += vga-pci.o +common-obj-$(CONFIG_VGA_ISA) += vga-isa.o +common-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o +common-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o +common-obj-$(CONFIG_VMMOUSE) += vmmouse.o +common-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o + +common-obj-$(CONFIG_RC4030) += rc4030.o +common-obj-$(CONFIG_DP8393X) += dp8393x.o +common-obj-$(CONFIG_DS1225Y) += ds1225y.o +common-obj-$(CONFIG_MIPSNET) += mipsnet.o + +common-obj-y += null-machine.o # Sound sound-obj-y = @@ -147,12 +156,11 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o $(obj)/adlib.o $(obj)/fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0 -hw-obj-$(CONFIG_SOUND) += $(sound-obj-y) +common-obj-$(CONFIG_SOUND) += $(sound-obj-y) -hw-obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/ +common-obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/ common-obj-y += usb/ -common-obj-y += irq.o common-obj-$(CONFIG_PTIMER) += ptimer.o common-obj-$(CONFIG_MAX7310) += max7310.o common-obj-$(CONFIG_WM8750) += wm8750.o @@ -172,12 +180,14 @@ common-obj-y += scsi-disk.o cdrom.o hd-geometry.o block-common.o common-obj-y += scsi-generic.o scsi-bus.o common-obj-y += hid.o common-obj-$(CONFIG_SSI) += ssi.o +common-obj-$(CONFIG_SSI_M25P80) += m25p80.o common-obj-$(CONFIG_SSI_SD) += ssi-sd.o common-obj-$(CONFIG_SD) += sd.o common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o common-obj-y += bt-hci-csr.o common-obj-y += msmouse.o ps2.o -common-obj-y += qdev.o qdev-properties.o qdev-monitor.o +common-obj-y += qdev-monitor.o +common-obj-y += qdev-properties-system.o common-obj-$(CONFIG_BRLAPI) += baum.o # xen backend driver support @@ -187,17 +197,20 @@ common-obj-$(CONFIG_XEN_BACKEND) += xen_console.o xenfb.o xen_disk.o xen_nic.o # Per-target files # virtio has to be here due to weird dependency between PCI and virtio-net. # need to fix this properly +obj-$(CONFIG_VIRTIO) += dataplane/ obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o virtio-scsi.o obj-$(CONFIG_SOFTMMU) += vhost_net.o obj-$(CONFIG_VHOST_NET) += vhost.o obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/ -obj-$(CONFIG_NO_PCI) += pci-stub.o obj-$(CONFIG_VGA) += vga.o obj-$(CONFIG_SOFTMMU) += device-hotplug.o obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o -# Inter-VM PCI shared memory +# Inter-VM PCI shared memory & VFIO PCI device assignment ifeq ($(CONFIG_PCI), y) obj-$(CONFIG_KVM) += ivshmem.o +obj-$(CONFIG_LINUX) += vfio_pci.o endif + +$(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS) diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index ebd5b29173..f802de0824 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -19,14 +19,13 @@ typedef struct a9mp_priv_state { uint32_t old_timer_status[8]; uint32_t num_cpu; MemoryRegion scu_iomem; - MemoryRegion ptimer_iomem; MemoryRegion container; DeviceState *mptimer; DeviceState *gic; uint32_t num_irq; } a9mp_priv_state; -static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset, +static uint64_t a9_scu_read(void *opaque, hwaddr offset, unsigned size) { a9mp_priv_state *s = (a9mp_priv_state *)opaque; @@ -57,7 +56,7 @@ static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset, } } -static void a9_scu_write(void *opaque, target_phys_addr_t offset, +static void a9_scu_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { a9mp_priv_state *s = (a9mp_priv_state *)opaque; @@ -20,8 +20,8 @@ #include "hw.h" #include "audiodev.h" #include "audio/audio.h" -#include "pci.h" -#include "dma.h" +#include "pci/pci.h" +#include "sysemu/dma.h" enum { AC97_Reset = 0x00, @@ -1226,32 +1226,101 @@ static const VMStateDescription vmstate_ac97 = { } }; -static const MemoryRegionPortio nam_portio[] = { - { 0, 256 * 1, 1, .read = nam_readb, }, - { 0, 256 * 2, 2, .read = nam_readw, }, - { 0, 256 * 4, 4, .read = nam_readl, }, - { 0, 256 * 1, 1, .write = nam_writeb, }, - { 0, 256 * 2, 2, .write = nam_writew, }, - { 0, 256 * 4, 4, .write = nam_writel, }, - PORTIO_END_OF_LIST (), -}; +static uint64_t nam_read(void *opaque, hwaddr addr, unsigned size) +{ + if ((addr / size) > 256) { + return -1; + } + + switch (size) { + case 1: + return nam_readb(opaque, addr); + case 2: + return nam_readw(opaque, addr); + case 4: + return nam_readl(opaque, addr); + default: + return -1; + } +} + +static void nam_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + if ((addr / size) > 256) { + return; + } + + switch (size) { + case 1: + nam_writeb(opaque, addr, val); + break; + case 2: + nam_writew(opaque, addr, val); + break; + case 4: + nam_writel(opaque, addr, val); + break; + } +} static const MemoryRegionOps ac97_io_nam_ops = { - .old_portio = nam_portio, + .read = nam_read, + .write = nam_write, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; -static const MemoryRegionPortio nabm_portio[] = { - { 0, 64 * 1, 1, .read = nabm_readb, }, - { 0, 64 * 2, 2, .read = nabm_readw, }, - { 0, 64 * 4, 4, .read = nabm_readl, }, - { 0, 64 * 1, 1, .write = nabm_writeb, }, - { 0, 64 * 2, 2, .write = nabm_writew, }, - { 0, 64 * 4, 4, .write = nabm_writel, }, - PORTIO_END_OF_LIST () -}; +static uint64_t nabm_read(void *opaque, hwaddr addr, unsigned size) +{ + if ((addr / size) > 64) { + return -1; + } + + switch (size) { + case 1: + return nabm_readb(opaque, addr); + case 2: + return nabm_readw(opaque, addr); + case 4: + return nabm_readl(opaque, addr); + default: + return -1; + } +} + +static void nabm_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + if ((addr / size) > 64) { + return; + } + + switch (size) { + case 1: + nabm_writeb(opaque, addr, val); + break; + case 2: + nabm_writew(opaque, addr, val); + break; + case 4: + nabm_writel(opaque, addr, val); + break; + } +} + static const MemoryRegionOps ac97_io_nabm_ops = { - .old_portio = nabm_portio, + .read = nabm_read, + .write = nabm_write, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static void ac97_on_reset (void *opaque) @@ -18,11 +18,11 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "hw.h" #include "pc.h" #include "acpi.h" -#include "monitor.h" +#include "monitor/monitor.h" struct acpi_table_header { uint16_t _length; /* our length, not actual part of the hdr */ @@ -61,18 +61,6 @@ static int acpi_checksum(const uint8_t *data, int len) return (-sum) & 0xff; } -/* like strncpy() but zero-fills the tail of destination */ -static void strzcpy(char *dst, const char *src, size_t size) -{ - size_t len = strlen(src); - if (len >= size) { - len = size; - } else { - memset(dst + len, 0, size - len); - } - memcpy(dst, src, len); -} - /* XXX fixme: this function uses obsolete argument parsing interface */ int acpi_table_add(const char *t) { @@ -157,7 +145,8 @@ int acpi_table_add(const char *t) hdr._length = cpu_to_le16(len); if (get_param_value(buf, sizeof(buf), "sig", t)) { - strzcpy(hdr.sig, buf, sizeof(hdr.sig)); + /* strncpy is justified: the field need not be NUL-terminated. */ + strncpy(hdr.sig, buf, sizeof(hdr.sig)); ++changed; } @@ -187,12 +176,14 @@ int acpi_table_add(const char *t) } if (get_param_value(buf, sizeof(buf), "oem_id", t)) { - strzcpy(hdr.oem_id, buf, sizeof(hdr.oem_id)); + /* strncpy is justified: the field need not be NUL-terminated. */ + strncpy(hdr.oem_id, buf, sizeof(hdr.oem_id)); ++changed; } if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) { - strzcpy(hdr.oem_table_id, buf, sizeof(hdr.oem_table_id)); + /* strncpy is justified: the field need not be NUL-terminated. */ + strncpy(hdr.oem_table_id, buf, sizeof(hdr.oem_table_id)); ++changed; } @@ -207,7 +198,8 @@ int acpi_table_add(const char *t) } if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) { - strzcpy(hdr.asl_compiler_id, buf, sizeof(hdr.asl_compiler_id)); + /* strncpy is justified: the field need not be NUL-terminated. */ + strncpy(hdr.asl_compiler_id, buf, sizeof(hdr.asl_compiler_id)); ++changed; } @@ -283,7 +275,7 @@ uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar) return ar->pm1.evt.sts; } -void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val) +static void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val) { uint16_t pm1_sts = acpi_pm1_evt_get_sts(ar); if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) { @@ -293,7 +285,7 @@ void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val) ar->pm1.evt.sts &= ~val; } -void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val) +static void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val) { ar->pm1.evt.en = val; qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC, @@ -318,6 +310,51 @@ void acpi_pm1_evt_reset(ACPIREGS *ar) qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER, 0); } +static uint64_t acpi_pm_evt_read(void *opaque, hwaddr addr, unsigned width) +{ + ACPIREGS *ar = opaque; + switch (addr) { + case 0: + return acpi_pm1_evt_get_sts(ar); + case 2: + return ar->pm1.evt.en; + default: + return 0; + } +} + +static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val, + unsigned width) +{ + ACPIREGS *ar = opaque; + switch (addr) { + case 0: + acpi_pm1_evt_write_sts(ar, val); + ar->pm1.evt.update_sci(ar); + break; + case 2: + acpi_pm1_evt_write_en(ar, val); + ar->pm1.evt.update_sci(ar); + break; + } +} + +static const MemoryRegionOps acpi_pm_evt_ops = { + .read = acpi_pm_evt_read, + .write = acpi_pm_evt_write, + .valid.min_access_size = 2, + .valid.max_access_size = 2, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +void acpi_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, + MemoryRegion *parent) +{ + ar->pm1.evt.update_sci = update_sci; + memory_region_init_io(&ar->pm1.evt.io, &acpi_pm_evt_ops, ar, "acpi-evt", 4); + memory_region_add_subregion(parent, 0, &ar->pm1.evt.io); +} + /* ACPI PM_TMR */ void acpi_pm_tmr_update(ACPIREGS *ar, bool enable) { @@ -339,7 +376,7 @@ void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar) ar->tmr.overflow_time = (d + 0x800000LL) & ~0x7fffffLL; } -uint32_t acpi_pm_tmr_get(ACPIREGS *ar) +static uint32_t acpi_pm_tmr_get(ACPIREGS *ar) { uint32_t d = acpi_pm_tmr_get_clock(); return d & 0xffffff; @@ -352,10 +389,25 @@ static void acpi_pm_tmr_timer(void *opaque) ar->tmr.update_sci(ar); } -void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci) +static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width) +{ + return acpi_pm_tmr_get(opaque); +} + +static const MemoryRegionOps acpi_pm_tmr_ops = { + .read = acpi_pm_tmr_read, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, + MemoryRegion *parent) { ar->tmr.update_sci = update_sci; ar->tmr.timer = qemu_new_timer_ns(vm_clock, acpi_pm_tmr_timer, ar); + memory_region_init_io(&ar->tmr.io, &acpi_pm_tmr_ops, ar, "acpi-tmr", 4); + memory_region_add_subregion(parent, 8, &ar->tmr.io); } void acpi_pm_tmr_reset(ACPIREGS *ar) @@ -365,13 +417,7 @@ void acpi_pm_tmr_reset(ACPIREGS *ar) } /* ACPI PM1aCNT */ -void acpi_pm1_cnt_init(ACPIREGS *ar) -{ - ar->wakeup.notify = acpi_notify_wakeup; - qemu_register_wakeup_notifier(&ar->wakeup); -} - -void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val, char s4) +static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val) { ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); @@ -386,7 +432,7 @@ void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val, char s4) qemu_system_suspend_request(); break; default: - if (sus_typ == s4) { /* S4 request */ + if (sus_typ == ar->pm1.cnt.s4_val) { /* S4 request */ monitor_protocol_event(QEVENT_SUSPEND_DISK, NULL); qemu_system_shutdown_request(); } @@ -406,6 +452,34 @@ void acpi_pm1_cnt_update(ACPIREGS *ar, } } +static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width) +{ + ACPIREGS *ar = opaque; + return ar->pm1.cnt.cnt; +} + +static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val, + unsigned width) +{ + acpi_pm1_cnt_write(opaque, val); +} + +static const MemoryRegionOps acpi_pm_cnt_ops = { + .read = acpi_pm_cnt_read, + .write = acpi_pm_cnt_write, + .valid.min_access_size = 2, + .valid.max_access_size = 2, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent) +{ + ar->wakeup.notify = acpi_notify_wakeup; + qemu_register_wakeup_notifier(&ar->wakeup); + memory_region_init_io(&ar->pm1.cnt.io, &acpi_pm_cnt_ops, ar, "acpi-cnt", 2); + memory_region_add_subregion(parent, 4, &ar->pm1.cnt.io); +} + void acpi_pm1_cnt_reset(ACPIREGS *ar) { ar->pm1.cnt.cnt = 0; @@ -419,11 +493,6 @@ void acpi_gpe_init(ACPIREGS *ar, uint8_t len) ar->gpe.en = g_malloc0(len / 2); } -void acpi_gpe_blk(ACPIREGS *ar, uint32_t blk) -{ - ar->gpe.blk = blk; -} - void acpi_gpe_reset(ACPIREGS *ar) { memset(ar->gpe.sts, 0, ar->gpe.len / 2); @@ -449,7 +518,6 @@ void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val) { uint8_t *cur; - addr -= ar->gpe.blk; cur = acpi_gpe_ioport_get_ptr(ar, addr); if (addr < ar->gpe.len / 2) { /* GPE_STS */ @@ -467,7 +535,6 @@ uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr) uint8_t *cur; uint32_t val; - addr -= ar->gpe.blk; cur = acpi_gpe_ioport_get_ptr(ar, addr); val = 0; if (cur != NULL) { @@ -84,22 +84,26 @@ typedef void (*acpi_update_sci_fn)(ACPIREGS *ar); struct ACPIPMTimer { QEMUTimer *timer; + MemoryRegion io; int64_t overflow_time; acpi_update_sci_fn update_sci; }; struct ACPIPM1EVT { + MemoryRegion io; uint16_t sts; uint16_t en; + acpi_update_sci_fn update_sci; }; struct ACPIPM1CNT { + MemoryRegion io; uint16_t cnt; + uint8_t s4_val; }; struct ACPIGPE { - uint32_t blk; uint8_t len; uint8_t *sts; @@ -119,11 +123,11 @@ struct ACPIREGS { /* PM_TMR */ void acpi_pm_tmr_update(ACPIREGS *ar, bool enable); void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar); -uint32_t acpi_pm_tmr_get(ACPIREGS *ar); -void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci); +void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, + MemoryRegion *parent); void acpi_pm_tmr_reset(ACPIREGS *ar); -#include "qemu-timer.h" +#include "qemu/timer.h" static inline int64_t acpi_pm_tmr_get_clock(void) { return muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, @@ -132,21 +136,19 @@ static inline int64_t acpi_pm_tmr_get_clock(void) /* PM1a_EVT: piix and ich9 don't implement PM1b. */ uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar); -void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val); -void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val); void acpi_pm1_evt_power_down(ACPIREGS *ar); void acpi_pm1_evt_reset(ACPIREGS *ar); +void acpi_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci, + MemoryRegion *parent); /* PM1a_CNT: piix and ich9 don't implement PM1b CNT. */ -void acpi_pm1_cnt_init(ACPIREGS *ar); -void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val, char s4); +void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent); void acpi_pm1_cnt_update(ACPIREGS *ar, bool sci_enable, bool sci_disable); void acpi_pm1_cnt_reset(ACPIREGS *ar); /* GPE0 */ void acpi_gpe_init(ACPIREGS *ar, uint8_t len); -void acpi_gpe_blk(ACPIREGS *ar, uint32_t blk); void acpi_gpe_reset(ACPIREGS *ar); void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val); diff --git a/hw/acpi_ich9.c b/hw/acpi_ich9.c new file mode 100644 index 0000000000..d2f9808242 --- /dev/null +++ b/hw/acpi_ich9.c @@ -0,0 +1,230 @@ +/* + * ACPI implementation + * + * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * Copyright (C) 2012 Jason Baron <jbaron@redhat.com> + * + * This is based on acpi.c. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/> + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ +#include "hw.h" +#include "pc.h" +#include "pci/pci.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" +#include "acpi.h" +#include "sysemu/kvm.h" +#include "exec/address-spaces.h" + +#include "ich9.h" + +//#define DEBUG + +#ifdef DEBUG +#define ICH9_DEBUG(fmt, ...) \ +do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while (0) +#else +#define ICH9_DEBUG(fmt, ...) do { } while (0) +#endif + +static void pm_update_sci(ICH9LPCPMRegs *pm) +{ + int sci_level, pm1a_sts; + + pm1a_sts = acpi_pm1_evt_get_sts(&pm->acpi_regs); + + sci_level = (((pm1a_sts & pm->acpi_regs.pm1.evt.en) & + (ACPI_BITMASK_RT_CLOCK_ENABLE | + ACPI_BITMASK_POWER_BUTTON_ENABLE | + ACPI_BITMASK_GLOBAL_LOCK_ENABLE | + ACPI_BITMASK_TIMER_ENABLE)) != 0); + qemu_set_irq(pm->irq, sci_level); + + /* schedule a timer interruption if needed */ + acpi_pm_tmr_update(&pm->acpi_regs, + (pm->acpi_regs.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) && + !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS)); +} + +static void ich9_pm_update_sci_fn(ACPIREGS *regs) +{ + ICH9LPCPMRegs *pm = container_of(regs, ICH9LPCPMRegs, acpi_regs); + pm_update_sci(pm); +} + +static uint64_t ich9_gpe_readb(void *opaque, hwaddr addr, unsigned width) +{ + ICH9LPCPMRegs *pm = opaque; + return acpi_gpe_ioport_readb(&pm->acpi_regs, addr); +} + +static void ich9_gpe_writeb(void *opaque, hwaddr addr, uint64_t val, + unsigned width) +{ + ICH9LPCPMRegs *pm = opaque; + acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val); +} + +static const MemoryRegionOps ich9_gpe_ops = { + .read = ich9_gpe_readb, + .write = ich9_gpe_writeb, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static uint64_t ich9_smi_readl(void *opaque, hwaddr addr, unsigned width) +{ + ICH9LPCPMRegs *pm = opaque; + switch (addr) { + case 0: + return pm->smi_en; + case 4: + return pm->smi_sts; + default: + return 0; + } +} + +static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val, + unsigned width) +{ + ICH9LPCPMRegs *pm = opaque; + switch (addr) { + case 0: + pm->smi_en = val; + break; + } +} + +static const MemoryRegionOps ich9_smi_ops = { + .read = ich9_smi_readl, + .write = ich9_smi_writel, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base) +{ + ICH9_DEBUG("to 0x%x\n", pm_io_base); + + assert((pm_io_base & ICH9_PMIO_MASK) == 0); + + pm->pm_io_base = pm_io_base; + memory_region_transaction_begin(); + memory_region_set_enabled(&pm->io, pm->pm_io_base != 0); + memory_region_set_address(&pm->io, pm->pm_io_base); + memory_region_transaction_commit(); +} + +static int ich9_pm_post_load(void *opaque, int version_id) +{ + ICH9LPCPMRegs *pm = opaque; + uint32_t pm_io_base = pm->pm_io_base; + pm->pm_io_base = 0; + ich9_pm_iospace_update(pm, pm_io_base); + return 0; +} + +#define VMSTATE_GPE_ARRAY(_field, _state) \ + { \ + .name = (stringify(_field)), \ + .version_id = 0, \ + .num = ICH9_PMIO_GPE0_LEN, \ + .info = &vmstate_info_uint8, \ + .size = sizeof(uint8_t), \ + .flags = VMS_ARRAY | VMS_POINTER, \ + .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ + } + +const VMStateDescription vmstate_ich9_pm = { + .name = "ich9_pm", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = ich9_pm_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs), + VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs), + VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs), + VMSTATE_TIMER(acpi_regs.tmr.timer, ICH9LPCPMRegs), + VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs), + VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs), + VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs), + VMSTATE_UINT32(smi_en, ICH9LPCPMRegs), + VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs), + VMSTATE_END_OF_LIST() + } +}; + +static void pm_reset(void *opaque) +{ + ICH9LPCPMRegs *pm = opaque; + ich9_pm_iospace_update(pm, 0); + + acpi_pm1_evt_reset(&pm->acpi_regs); + acpi_pm1_cnt_reset(&pm->acpi_regs); + acpi_pm_tmr_reset(&pm->acpi_regs); + acpi_gpe_reset(&pm->acpi_regs); + + if (kvm_enabled()) { + /* Mark SMM as already inited to prevent SMM from running. KVM does not + * support SMM mode. */ + pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN; + } + + pm_update_sci(pm); +} + +static void pm_powerdown_req(Notifier *n, void *opaque) +{ + ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, powerdown_notifier); + + acpi_pm1_evt_power_down(&pm->acpi_regs); +} + +void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, + qemu_irq sci_irq, qemu_irq cmos_s3) +{ + memory_region_init(&pm->io, "ich9-pm", ICH9_PMIO_SIZE); + memory_region_set_enabled(&pm->io, false); + memory_region_add_subregion(pci_address_space_io(lpc_pci), + 0, &pm->io); + + acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io); + acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io); + acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io); + + acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN); + memory_region_init_io(&pm->io_gpe, &ich9_gpe_ops, pm, "apci-gpe0", + ICH9_PMIO_GPE0_LEN); + memory_region_add_subregion(&pm->io, ICH9_PMIO_GPE0_STS, &pm->io_gpe); + + memory_region_init_io(&pm->io_smi, &ich9_smi_ops, pm, "apci-smi", + 8); + memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi); + + pm->irq = sci_irq; + qemu_register_reset(pm_reset, pm); + pm->powerdown_notifier.notify = pm_powerdown_req; + qemu_register_powerdown_notifier(&pm->powerdown_notifier); +} diff --git a/hw/acpi_ich9.h b/hw/acpi_ich9.h new file mode 100644 index 0000000000..ecb82abc65 --- /dev/null +++ b/hw/acpi_ich9.h @@ -0,0 +1,52 @@ +/* + * QEMU GMCH/ICH9 LPC PM Emulation + * + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/> + */ + +#ifndef HW_ACPI_ICH9_H +#define HW_ACPI_ICH9_H + +#include "acpi.h" + +typedef struct ICH9LPCPMRegs { + /* + * In ich9 spec says that pm1_cnt register is 32bit width and + * that the upper 16bits are reserved and unused. + * PM1a_CNT_BLK = 2 in FADT so it is defined as uint16_t. + */ + ACPIREGS acpi_regs; + + MemoryRegion io; + MemoryRegion io_gpe; + MemoryRegion io_smi; + + uint32_t smi_en; + uint32_t smi_sts; + + qemu_irq irq; /* SCI */ + + uint32_t pm_io_base; + Notifier powerdown_notifier; +} ICH9LPCPMRegs; + +void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, + qemu_irq sci_irq, qemu_irq cmos_s3_resume); +void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base); +extern const VMStateDescription vmstate_ich9_pm; + +#endif /* HW_ACPI_ICH9_H */ diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 0aace60f24..06a8aca9cb 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -22,12 +22,13 @@ #include "pc.h" #include "apm.h" #include "pm_smbus.h" -#include "pci.h" +#include "pci/pci.h" #include "acpi.h" -#include "sysemu.h" -#include "range.h" -#include "ioport.h" +#include "sysemu/sysemu.h" +#include "qemu/range.h" +#include "exec/ioport.h" #include "fw_cfg.h" +#include "exec/address-spaces.h" //#define DEBUG @@ -37,10 +38,11 @@ # define PIIX4_DPRINTF(format, ...) do { } while (0) #endif -#define ACPI_DBG_IO_ADDR 0xb044 - #define GPE_BASE 0xafe0 #define GPE_LEN 4 + +#define PCI_HOTPLUG_ADDR 0xae00 +#define PCI_HOTPLUG_SIZE 0x000f #define PCI_UP_BASE 0xae00 #define PCI_DOWN_BASE 0xae04 #define PCI_EJ_BASE 0xae08 @@ -55,7 +57,10 @@ struct pci_status { typedef struct PIIX4PMState { PCIDevice dev; - IORange ioport; + + MemoryRegion io; + MemoryRegion io_gpe; + MemoryRegion io_pci; ACPIREGS ar; APMState apm; @@ -67,6 +72,7 @@ typedef struct PIIX4PMState { qemu_irq smi_irq; int kvm_enabled; Notifier machine_ready; + Notifier powerdown_notifier; /* for pci hotplug */ struct pci_status pci0_status; @@ -78,7 +84,8 @@ typedef struct PIIX4PMState { uint8_t s4_val; } PIIX4PMState; -static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s); +static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, + PCIBus *bus, PIIX4PMState *s); #define ACPI_ENABLE 0xf1 #define ACPI_DISABLE 0xf0 @@ -108,67 +115,6 @@ static void pm_tmr_timer(ACPIREGS *ar) pm_update_sci(s); } -static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width, - uint64_t val) -{ - PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport); - - if (width != 2) { - PIIX4_DPRINTF("PM write port=0x%04x width=%d val=0x%08x\n", - (unsigned)addr, width, (unsigned)val); - } - - switch(addr) { - case 0x00: - acpi_pm1_evt_write_sts(&s->ar, val); - pm_update_sci(s); - break; - case 0x02: - acpi_pm1_evt_write_en(&s->ar, val); - pm_update_sci(s); - break; - case 0x04: - acpi_pm1_cnt_write(&s->ar, val, s->s4_val); - break; - default: - break; - } - PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", (unsigned int)addr, - (unsigned int)val); -} - -static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width, - uint64_t *data) -{ - PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport); - uint32_t val; - - switch(addr) { - case 0x00: - val = acpi_pm1_evt_get_sts(&s->ar); - break; - case 0x02: - val = s->ar.pm1.evt.en; - break; - case 0x04: - val = s->ar.pm1.cnt.cnt; - break; - case 0x08: - val = acpi_pm_tmr_get(&s->ar); - break; - default: - val = 0; - break; - } - PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", (unsigned int)addr, val); - *data = val; -} - -static const IORangeOps pm_iorange_ops = { - .read = pm_ioport_read, - .write = pm_ioport_write, -}; - static void apm_ctrl_changed(uint32_t val, void *arg) { PIIX4PMState *s = arg; @@ -183,32 +129,42 @@ static void apm_ctrl_changed(uint32_t val, void *arg) } } -static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) -{ - PIIX4_DPRINTF("ACPI: DBG: 0x%08x\n", val); -} - static void pm_io_space_update(PIIX4PMState *s) { uint32_t pm_io_base; - if (s->dev.config[0x80] & 1) { - pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40)); - pm_io_base &= 0xffc0; + pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40)); + pm_io_base &= 0xffc0; - /* XXX: need to improve memory and ioport allocation */ - PIIX4_DPRINTF("PM: mapping to 0x%x\n", pm_io_base); - iorange_init(&s->ioport, &pm_iorange_ops, pm_io_base, 64); - ioport_register(&s->ioport); - } + memory_region_transaction_begin(); + memory_region_set_enabled(&s->io, s->dev.config[0x80] & 1); + memory_region_set_address(&s->io, pm_io_base); + memory_region_transaction_commit(); +} + +static void smbus_io_space_update(PIIX4PMState *s) +{ + s->smb_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x90)); + s->smb_io_base &= 0xffc0; + + memory_region_transaction_begin(); + memory_region_set_enabled(&s->smb.io, s->dev.config[0xd2] & 1); + memory_region_set_address(&s->smb.io, s->smb_io_base); + memory_region_transaction_commit(); } static void pm_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { pci_default_write_config(d, address, val, len); - if (range_covers_byte(address, len, 0x80)) + if (range_covers_byte(address, len, 0x80) || + ranges_overlap(address, len, 0x40, 4)) { pm_io_space_update((PIIX4PMState *)d); + } + if (range_covers_byte(address, len, 0xd2) || + ranges_overlap(address, len, 0x90, 4)) { + smbus_io_space_update((PIIX4PMState *)d); + } } static void vmstate_pci_status_pre_save(void *opaque) @@ -234,10 +190,9 @@ static int vmstate_acpi_post_load(void *opaque, int version_id) { \ .name = (stringify(_field)), \ .version_id = 0, \ - .num = GPE_LEN, \ .info = &vmstate_info_uint16, \ .size = sizeof(uint16_t), \ - .flags = VMS_ARRAY | VMS_POINTER, \ + .flags = VMS_SINGLE | VMS_POINTER, \ .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ } @@ -266,11 +221,54 @@ static const VMStateDescription vmstate_pci_status = { } }; +static int acpi_load_old(QEMUFile *f, void *opaque, int version_id) +{ + PIIX4PMState *s = opaque; + int ret, i; + uint16_t temp; + + ret = pci_device_load(&s->dev, f); + if (ret < 0) { + return ret; + } + qemu_get_be16s(f, &s->ar.pm1.evt.sts); + qemu_get_be16s(f, &s->ar.pm1.evt.en); + qemu_get_be16s(f, &s->ar.pm1.cnt.cnt); + + ret = vmstate_load_state(f, &vmstate_apm, opaque, 1); + if (ret) { + return ret; + } + + qemu_get_timer(f, s->ar.tmr.timer); + qemu_get_sbe64s(f, &s->ar.tmr.overflow_time); + + qemu_get_be16s(f, (uint16_t *)s->ar.gpe.sts); + for (i = 0; i < 3; i++) { + qemu_get_be16s(f, &temp); + } + + qemu_get_be16s(f, (uint16_t *)s->ar.gpe.en); + for (i = 0; i < 3; i++) { + qemu_get_be16s(f, &temp); + } + + ret = vmstate_load_state(f, &vmstate_pci_status, opaque, 1); + return ret; +} + +/* qemu-kvm 1.2 uses version 3 but advertised as 2 + * To support incoming qemu-kvm 1.2 migration, change version_id + * and minimum_version_id to 2 below (which breaks migration from + * qemu 1.2). + * + */ static const VMStateDescription vmstate_acpi = { .name = "piix4_pm", - .version_id = 2, - .minimum_version_id = 1, + .version_id = 3, + .minimum_version_id = 3, .minimum_version_id_old = 1, + .load_state_old = acpi_load_old, .post_load = vmstate_acpi_post_load, .fields = (VMStateField []) { VMSTATE_PCI_DEVICE(dev, PIIX4PMState), @@ -305,7 +303,6 @@ static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots) if (pc->no_hotplug) { slot_free = false; } else { - object_unparent(OBJECT(dev)); qdev_free(qdev); } } @@ -353,6 +350,9 @@ static void piix4_reset(void *opaque) pci_conf[0x5a] = 0; pci_conf[0x5b] = 0; + pci_conf[0x40] = 0x01; /* PM io base read only bit */ + pci_conf[0x80] = 0; + if (s->kvm_enabled) { /* Mark SMM as already inited (until KVM supports SMM). */ pci_conf[0x5B] = 0x02; @@ -360,9 +360,9 @@ static void piix4_reset(void *opaque) piix4_update_hotplug(s); } -static void piix4_powerdown(void *opaque, int irq, int power_failing) +static void piix4_pm_powerdown_req(Notifier *n, void *opaque) { - PIIX4PMState *s = opaque; + PIIX4PMState *s = container_of(n, PIIX4PMState, powerdown_notifier); assert(s != NULL); acpi_pm1_evt_power_down(&s->ar); @@ -392,12 +392,8 @@ static int piix4_pm_initfn(PCIDevice *dev) pci_conf[0x09] = 0x00; pci_conf[0x3d] = 0x01; // interrupt pin 1 - pci_conf[0x40] = 0x01; /* PM io base read only bit */ - /* APM */ - apm_init(&s->apm, apm_ctrl_changed, s); - - register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s); + apm_init(dev, &s->apm, apm_ctrl_changed, s); if (s->kvm_enabled) { /* Mark SMM as already inited to prevent SMM from running. KVM does not @@ -410,19 +406,29 @@ static int piix4_pm_initfn(PCIDevice *dev) pci_conf[0x90] = s->smb_io_base | 1; pci_conf[0x91] = s->smb_io_base >> 8; pci_conf[0xd2] = 0x09; - register_ioport_write(s->smb_io_base, 64, 1, smb_ioport_writeb, &s->smb); - register_ioport_read(s->smb_io_base, 64, 1, smb_ioport_readb, &s->smb); - - acpi_pm_tmr_init(&s->ar, pm_tmr_timer); + pm_smbus_init(&s->dev.qdev, &s->smb); + memory_region_set_enabled(&s->smb.io, pci_conf[0xd2] & 1); + memory_region_add_subregion(pci_address_space_io(dev), + s->smb_io_base, &s->smb.io); + + memory_region_init(&s->io, "piix4-pm", 64); + memory_region_set_enabled(&s->io, false); + memory_region_add_subregion(pci_address_space_io(dev), + 0, &s->io); + + acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io); + acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io); + acpi_pm1_cnt_init(&s->ar, &s->io); acpi_gpe_init(&s->ar, GPE_LEN); - qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1); + s->powerdown_notifier.notify = piix4_pm_powerdown_req; + qemu_register_powerdown_notifier(&s->powerdown_notifier); - pm_smbus_init(&s->dev.qdev, &s->smb); s->machine_ready.notify = piix4_pm_machine_ready; qemu_add_machine_init_done_notifier(&s->machine_ready); qemu_register_reset(piix4_reset, s); - piix4_acpi_system_hot_add_init(dev->bus, s); + + piix4_acpi_system_hot_add_init(pci_address_space_io(dev), dev->bus, s); return 0; } @@ -439,7 +445,6 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, s = DO_UPCAST(PIIX4PMState, dev, dev); s->irq = sci_irq; - acpi_pm1_cnt_init(&s->ar); s->smi_irq = smi_irq; s->kvm_enabled = kvm_enabled; @@ -496,7 +501,7 @@ static void piix4_pm_register_types(void) type_init(piix4_pm_register_types) -static uint32_t gpe_readb(void *opaque, uint32_t addr) +static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width) { PIIX4PMState *s = opaque; uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr); @@ -505,7 +510,8 @@ static uint32_t gpe_readb(void *opaque, uint32_t addr) return val; } -static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val) +static void gpe_writeb(void *opaque, hwaddr addr, uint64_t val, + unsigned width) { PIIX4PMState *s = opaque; @@ -515,6 +521,16 @@ static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val) PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val); } +static const MemoryRegionOps piix4_gpe_ops = { + .read = gpe_readb, + .write = gpe_writeb, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + static uint32_t pci_up_read(void *opaque, uint32_t addr) { PIIX4PMState *s = opaque; @@ -558,24 +574,41 @@ static uint32_t pcirmv_read(void *opaque, uint32_t addr) return s->pci0_hotplug_enable; } +static const MemoryRegionOps piix4_pci_ops = { + .old_portio = (MemoryRegionPortio[]) { + { + .offset = PCI_UP_BASE - PCI_HOTPLUG_ADDR, .len = 4, .size = 4, + .read = pci_up_read, + },{ + .offset = PCI_DOWN_BASE - PCI_HOTPLUG_ADDR, .len = 4, .size = 4, + .read = pci_down_read, + },{ + .offset = PCI_EJ_BASE - PCI_HOTPLUG_ADDR, .len = 4, .size = 4, + .read = pci_features_read, + .write = pciej_write, + },{ + .offset = PCI_RMV_BASE - PCI_HOTPLUG_ADDR, .len = 4, .size = 4, + .read = pcirmv_read, + }, + PORTIO_END_OF_LIST() + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, PCIHotplugState state); -static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) +static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, + PCIBus *bus, PIIX4PMState *s) { - - register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s); - register_ioport_read(GPE_BASE, GPE_LEN, 1, gpe_readb, s); - acpi_gpe_blk(&s->ar, GPE_BASE); - - register_ioport_read(PCI_UP_BASE, 4, 4, pci_up_read, s); - register_ioport_read(PCI_DOWN_BASE, 4, 4, pci_down_read, s); - - register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, s); - register_ioport_read(PCI_EJ_BASE, 4, 4, pci_features_read, s); - - register_ioport_read(PCI_RMV_BASE, 4, 4, pcirmv_read, s); - + memory_region_init_io(&s->io_gpe, &piix4_gpe_ops, s, "apci-gpe0", + GPE_LEN); + memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe); + + memory_region_init_io(&s->io_pci, &piix4_pci_ops, s, "apci-pci-hotplug", + PCI_HOTPLUG_SIZE); + memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR, + &s->io_pci); pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev); } @@ -23,7 +23,7 @@ */ #include "hw.h" #include "adb.h" -#include "console.h" +#include "ui/console.h" /* debug ADB */ //#define DEBUG_ADB @@ -108,10 +108,10 @@ int adb_poll(ADBBusState *s, uint8_t *obuf) return olen; } -ADBDevice *adb_register_device(ADBBusState *s, int devaddr, - ADBDeviceRequest *devreq, - ADBDeviceReset *devreset, - void *opaque) +static ADBDevice *adb_register_device(ADBBusState *s, int devaddr, + ADBDeviceRequest *devreq, + ADBDeviceReset *devreset, + void *opaque) { ADBDevice *d; if (s->nb_devices >= MAX_ADB_DEVICES) @@ -56,10 +56,6 @@ int adb_request(ADBBusState *s, uint8_t *buf_out, const uint8_t *buf, int len); int adb_poll(ADBBusState *s, uint8_t *buf_out); -ADBDevice *adb_register_device(ADBBusState *s, int devaddr, - ADBDeviceRequest *devreq, - ADBDeviceReset *devreset, - void *opaque); void adb_kbd_init(ADBBusState *bus); void adb_mouse_init(ADBBusState *bus); diff --git a/hw/adlib.c b/hw/adlib.c index d39cd97384..07c69fc967 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -32,7 +32,7 @@ #define ADLIB_KILL_TIMERS 1 #ifdef DEBUG -#include "qemu-timer.h" +#include "qemu/timer.h" #endif #define dolog(...) AUD_log ("adlib", __VA_ARGS__) diff --git a/hw/ads7846.c b/hw/ads7846.c index 41c7f101c4..fa137e628e 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -11,7 +11,7 @@ */ #include "ssi.h" -#include "console.h" +#include "ui/console.h" typedef struct { SSISlave ssidev; @@ -119,11 +119,12 @@ static int ads7856_post_load(void *opaque, int version_id) static const VMStateDescription vmstate_ads7846 = { .name = "ads7846", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, .post_load = ads7856_post_load, .fields = (VMStateField[]) { + VMSTATE_SSI_SLAVE(ssidev, ADS7846State), VMSTATE_INT32_ARRAY(input, ADS7846State, 8), VMSTATE_INT32(noise, ADS7846State), VMSTATE_INT32(cycle, ADS7846State), diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c index 9eb939f383..e2980e9893 100644 --- a/hw/alpha_dp264.c +++ b/hw/alpha_dp264.c @@ -11,10 +11,11 @@ #include "loader.h" #include "boards.h" #include "alpha_sys.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "mc146818rtc.h" #include "ide.h" #include "i8254.h" +#include "serial.h" #define MAX_IDE_BUS 2 @@ -42,14 +43,14 @@ static int clipper_pci_map_irq(PCIDevice *d, int irq_num) return (slot + 1) * 4 + irq_num; } -static void clipper_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void clipper_init(QEMUMachineInitArgs *args) { - CPUAlphaState *cpus[4]; + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + AlphaCPU *cpus[4]; PCIBus *pci_bus; ISABus *isa_bus; qemu_irq rtc_irq; @@ -61,12 +62,12 @@ static void clipper_init(ram_addr_t ram_size, /* Create up to 4 cpus. */ memset(cpus, 0, sizeof(cpus)); for (i = 0; i < smp_cpus; ++i) { - cpus[i] = cpu_init(cpu_model ? cpu_model : "ev67"); + cpus[i] = cpu_alpha_init(cpu_model ? cpu_model : "ev67"); } - cpus[0]->trap_arg0 = ram_size; - cpus[0]->trap_arg1 = 0; - cpus[0]->trap_arg2 = smp_cpus; + cpus[0]->env.trap_arg0 = ram_size; + cpus[0]->env.trap_arg1 = 0; + cpus[0]->env.trap_arg2 = smp_cpus; /* Init the chipset. */ pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus, @@ -77,7 +78,7 @@ static void clipper_init(ram_addr_t ram_size, isa_create_simple(isa_bus, "i8042"); /* VGA setup. Don't bother loading the bios. */ - alpha_pci_vga_setup(pci_bus); + pci_vga_init(pci_bus); /* Serial code setup. */ for (i = 0; i < MAX_SERIAL_PORTS; ++i) { @@ -118,9 +119,9 @@ static void clipper_init(ram_addr_t ram_size, /* Start all cpus at the PALcode RESET entry point. */ for (i = 0; i < smp_cpus; ++i) { - cpus[i]->pal_mode = 1; - cpus[i]->pc = palcode_entry; - cpus[i]->palbr = palcode_entry; + cpus[i]->env.pal_mode = 1; + cpus[i]->env.pc = palcode_entry; + cpus[i]->env.palbr = palcode_entry; } /* Load a kernel. */ @@ -135,7 +136,7 @@ static void clipper_init(ram_addr_t ram_size, exit(1); } - cpus[0]->trap_arg1 = kernel_entry; + cpus[0]->env.trap_arg1 = kernel_entry; param_offset = kernel_low - 0x6000; diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c index 673557781e..7327d488fd 100644 --- a/hw/alpha_pci.c +++ b/hw/alpha_pci.c @@ -8,15 +8,14 @@ #include "config.h" #include "alpha_sys.h" -#include "qemu-log.h" -#include "sysemu.h" -#include "vmware_vga.h" +#include "qemu/log.h" +#include "sysemu/sysemu.h" /* PCI IO reads/writes, to byte-word addressable memory. */ /* ??? Doesn't handle multiple PCI busses. */ -static uint64_t bw_io_read(void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t bw_io_read(void *opaque, hwaddr addr, unsigned size) { switch (size) { case 1: @@ -29,7 +28,7 @@ static uint64_t bw_io_read(void *opaque, target_phys_addr_t addr, unsigned size) abort(); } -static void bw_io_write(void *opaque, target_phys_addr_t addr, +static void bw_io_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { switch (size) { @@ -58,14 +57,14 @@ const MemoryRegionOps alpha_pci_bw_io_ops = { }; /* PCI config space reads/writes, to byte-word addressable memory. */ -static uint64_t bw_conf1_read(void *opaque, target_phys_addr_t addr, +static uint64_t bw_conf1_read(void *opaque, hwaddr addr, unsigned size) { PCIBus *b = opaque; return pci_data_read(b, addr, size); } -static void bw_conf1_write(void *opaque, target_phys_addr_t addr, +static void bw_conf1_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { PCIBus *b = opaque; @@ -84,12 +83,12 @@ const MemoryRegionOps alpha_pci_conf1_ops = { /* PCI/EISA Interrupt Acknowledge Cycle. */ -static uint64_t iack_read(void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t iack_read(void *opaque, hwaddr addr, unsigned size) { return pic_read_irq(isa_pic); } -static void special_write(void *opaque, target_phys_addr_t addr, +static void special_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { qemu_log("pci: special write cycle"); @@ -108,25 +107,3 @@ const MemoryRegionOps alpha_pci_iack_ops = { .max_access_size = 4, }, }; - -void alpha_pci_vga_setup(PCIBus *pci_bus) -{ - switch (vga_interface_type) { -#ifdef CONFIG_SPICE - case VGA_QXL: - pci_create_simple(pci_bus, -1, "qxl-vga"); - return; -#endif - case VGA_CIRRUS: - pci_cirrus_vga_init(pci_bus); - return; - case VGA_VMWARE: - pci_vmsvga_init(pci_bus); - return; - } - /* If VGA is enabled at all, and one of the above didn't work, then - fallback to Standard VGA. */ - if (vga_interface_type != VGA_NONE) { - pci_vga_init(pci_bus); - } -} diff --git a/hw/alpha_sys.h b/hw/alpha_sys.h index de40f8b613..233a71ecdb 100644 --- a/hw/alpha_sys.h +++ b/hw/alpha_sys.h @@ -3,15 +3,14 @@ #ifndef HW_ALPHA_H #define HW_ALPHA_H 1 -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" #include "ide.h" -#include "net.h" #include "pc.h" #include "irq.h" -PCIBus *typhoon_init(ram_addr_t, ISABus **, qemu_irq *, CPUAlphaState *[4], +PCIBus *typhoon_init(ram_addr_t, ISABus **, qemu_irq *, AlphaCPU *[4], pci_map_irq_fn); /* alpha_pci.c. */ @@ -19,6 +18,4 @@ extern const MemoryRegionOps alpha_pci_bw_io_ops; extern const MemoryRegionOps alpha_pci_conf1_ops; extern const MemoryRegionOps alpha_pci_iack_ops; -void alpha_pci_vga_setup(PCIBus *pci_bus); - #endif diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c index 872e1122e8..dafb35ddd1 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -7,21 +7,23 @@ */ #include "cpu.h" -#include "exec-all.h" +#include "exec/exec-all.h" #include "hw.h" #include "devices.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "alpha_sys.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" +#define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost" + typedef struct TyphoonCchip { MemoryRegion region; uint64_t misc; uint64_t drir; uint64_t dim[4]; uint32_t iic[4]; - CPUAlphaState *cpu[4]; + AlphaCPU *cpu[4]; } TyphoonCchip; typedef struct TyphoonWindow { @@ -40,8 +42,12 @@ typedef struct TyphoonPchip { TyphoonWindow win[4]; } TyphoonPchip; +#define TYPHOON_PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(TyphoonState, (obj), TYPE_TYPHOON_PCI_HOST_BRIDGE) + typedef struct TyphoonState { - PCIHostState host; + PCIHostState parent_obj; + TyphoonCchip cchip; TyphoonPchip pchip; MemoryRegion dchip_region; @@ -52,10 +58,11 @@ typedef struct TyphoonState { } TyphoonState; /* Called when one of DRIR or DIM changes. */ -static void cpu_irq_change(CPUAlphaState *env, uint64_t req) +static void cpu_irq_change(AlphaCPU *cpu, uint64_t req) { /* If there are any non-masked interrupts, tell the cpu. */ - if (env) { + if (cpu != NULL) { + CPUAlphaState *env = &cpu->env; if (req) { cpu_interrupt(env, CPU_INTERRUPT_HARD); } else { @@ -64,7 +71,7 @@ static void cpu_irq_change(CPUAlphaState *env, uint64_t req) } } -static uint64_t cchip_read(void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size) { CPUAlphaState *env = cpu_single_env; TyphoonState *s = opaque; @@ -197,13 +204,13 @@ static uint64_t cchip_read(void *opaque, target_phys_addr_t addr, unsigned size) return ret; } -static uint64_t dchip_read(void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size) { /* Skip this. It's all related to DRAM timing and setup. */ return 0; } -static uint64_t pchip_read(void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size) { TyphoonState *s = opaque; uint64_t ret = 0; @@ -300,7 +307,7 @@ static uint64_t pchip_read(void *opaque, target_phys_addr_t addr, unsigned size) return ret; } -static void cchip_write(void *opaque, target_phys_addr_t addr, +static void cchip_write(void *opaque, hwaddr addr, uint64_t v32, unsigned size) { TyphoonState *s = opaque; @@ -347,8 +354,9 @@ static void cchip_write(void *opaque, target_phys_addr_t addr, if ((newval ^ oldval) & 0xff0) { int i; for (i = 0; i < 4; ++i) { - CPUAlphaState *env = s->cchip.cpu[i]; - if (env) { + AlphaCPU *cpu = s->cchip.cpu[i]; + if (cpu != NULL) { + CPUAlphaState *env = &cpu->env; /* IPI can be either cleared or set by the write. */ if (newval & (1 << (i + 8))) { cpu_interrupt(env, CPU_INTERRUPT_SMP); @@ -457,13 +465,13 @@ static void cchip_write(void *opaque, target_phys_addr_t addr, } } -static void dchip_write(void *opaque, target_phys_addr_t addr, +static void dchip_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { /* Skip this. It's all related to DRAM timing and setup. */ } -static void pchip_write(void *opaque, target_phys_addr_t addr, +static void pchip_write(void *opaque, hwaddr addr, uint64_t v32, unsigned size) { TyphoonState *s = opaque; @@ -655,8 +663,8 @@ static void typhoon_set_timer_irq(void *opaque, int irq, int level) /* Deliver the interrupt to each CPU, considering each CPU's IIC. */ for (i = 0; i < 4; ++i) { - CPUAlphaState *env = s->cchip.cpu[i]; - if (env) { + AlphaCPU *cpu = s->cchip.cpu[i]; + if (cpu != NULL) { uint32_t iic = s->cchip.iic[i]; /* ??? The verbage in Section 10.2.2.10 isn't 100% clear. @@ -675,7 +683,7 @@ static void typhoon_set_timer_irq(void *opaque, int irq, int level) /* Set the ITI bit for this cpu. */ s->cchip.misc |= 1 << (i + 4); /* And signal the interrupt. */ - cpu_interrupt(env, CPU_INTERRUPT_TIMER); + cpu_interrupt(&cpu->env, CPU_INTERRUPT_TIMER); } } } @@ -688,35 +696,35 @@ static void typhoon_alarm_timer(void *opaque) /* Set the ITI bit for this cpu. */ s->cchip.misc |= 1 << (cpu + 4); - cpu_interrupt(s->cchip.cpu[cpu], CPU_INTERRUPT_TIMER); + cpu_interrupt(&s->cchip.cpu[cpu]->env, CPU_INTERRUPT_TIMER); } PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, qemu_irq *p_rtc_irq, - CPUAlphaState *cpus[4], pci_map_irq_fn sys_map_irq) + AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq) { const uint64_t MB = 1024 * 1024; const uint64_t GB = 1024 * MB; MemoryRegion *addr_space = get_system_memory(); MemoryRegion *addr_space_io = get_system_io(); DeviceState *dev; - PCIHostState *p; TyphoonState *s; + PCIHostState *phb; PCIBus *b; int i; - dev = qdev_create(NULL, "typhoon-pcihost"); + dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE); qdev_init_nofail(dev); - p = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev)); - s = container_of(p, TyphoonState, host); + s = TYPHOON_PCI_HOST_BRIDGE(dev); + phb = PCI_HOST_BRIDGE(dev); /* Remember the CPUs so that we can deliver interrupts to them. */ for (i = 0; i < 4; i++) { - CPUAlphaState *env = cpus[i]; - s->cchip.cpu[i] = env; - if (env) { - env->alarm_timer = qemu_new_timer_ns(rtc_clock, + AlphaCPU *cpu = cpus[i]; + s->cchip.cpu[i] = cpu; + if (cpu != NULL) { + cpu->alarm_timer = qemu_new_timer_ns(rtc_clock, typhoon_alarm_timer, (void *)((uintptr_t)s + i)); } @@ -763,10 +771,10 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, memory_region_add_subregion(addr_space, 0x801fc000000ULL, &s->pchip.reg_io); - b = pci_register_bus(&s->host.busdev.qdev, "pci", + b = pci_register_bus(dev, "pci", typhoon_set_irq, sys_map_irq, s, &s->pchip.reg_mem, addr_space_io, 0, 64); - s->host.bus = b; + phb->bus = b; /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */ memory_region_init_io(&s->pchip.reg_iack, &alpha_pci_iack_ops, b, @@ -817,9 +825,9 @@ static void typhoon_pcihost_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo typhoon_pcihost_info = { - .name = "typhoon-pcihost", - .parent = TYPE_SYS_BUS_DEVICE, +static const TypeInfo typhoon_pcihost_info = { + .name = TYPE_TYPHOON_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(TyphoonState), .class_init = typhoon_pcihost_class_init, }; diff --git a/hw/an5206.c b/hw/an5206.c index 25407c0f50..dcfe34b3ae 100644 --- a/hw/an5206.c +++ b/hw/an5206.c @@ -11,7 +11,7 @@ #include "boards.h" #include "loader.h" #include "elf.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #define KERNEL_LOAD_ADDR 0x10000 #define AN5206_MBAR_ADDR 0x10000000 @@ -19,15 +19,15 @@ /* Board init. */ -static void an5206_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void an5206_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; CPUM68KState *env; int kernel_size; uint64_t elf_entry; - target_phys_addr_t entry; + hwaddr entry; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *sram = g_new(MemoryRegion, 1); diff --git a/hw/apb_pci.c b/hw/apb_pci.c index c28411a460..c22e2b0fc3 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -27,13 +27,13 @@ the secondary PCI bridge. */ #include "sysbus.h" -#include "pci.h" -#include "pci_host.h" -#include "pci_bridge.h" -#include "pci_internals.h" +#include "pci/pci.h" +#include "pci/pci_host.h" +#include "pci/pci_bridge.h" +#include "pci/pci_bus.h" #include "apb_pci.h" -#include "sysemu.h" -#include "exec-memory.h" +#include "sysemu/sysemu.h" +#include "exec/address-spaces.h" /* debug APB */ //#define DEBUG_APB @@ -87,7 +87,7 @@ typedef struct APBState { static void pci_apb_set_irq(void *opaque, int irq_num, int level); -static void apb_config_writel (void *opaque, target_phys_addr_t addr, +static void apb_config_writel (void *opaque, hwaddr addr, uint64_t val, unsigned size) { APBState *s = opaque; @@ -152,7 +152,7 @@ static void apb_config_writel (void *opaque, target_phys_addr_t addr, } static uint64_t apb_config_readl (void *opaque, - target_phys_addr_t addr, unsigned size) + hwaddr addr, unsigned size) { APBState *s = opaque; uint32_t val; @@ -212,7 +212,7 @@ static const MemoryRegionOps apb_config_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void apb_pci_config_write(void *opaque, target_phys_addr_t addr, +static void apb_pci_config_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { APBState *s = opaque; @@ -222,7 +222,7 @@ static void apb_pci_config_write(void *opaque, target_phys_addr_t addr, pci_data_write(s->bus, addr, val, size); } -static uint64_t apb_pci_config_read(void *opaque, target_phys_addr_t addr, +static uint64_t apb_pci_config_read(void *opaque, hwaddr addr, unsigned size) { uint32_t ret; @@ -234,25 +234,25 @@ static uint64_t apb_pci_config_read(void *opaque, target_phys_addr_t addr, return ret; } -static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr, +static void pci_apb_iowriteb (void *opaque, hwaddr addr, uint32_t val) { cpu_outb(addr & IOPORTS_MASK, val); } -static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr, +static void pci_apb_iowritew (void *opaque, hwaddr addr, uint32_t val) { cpu_outw(addr & IOPORTS_MASK, bswap16(val)); } -static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr, +static void pci_apb_iowritel (void *opaque, hwaddr addr, uint32_t val) { cpu_outl(addr & IOPORTS_MASK, bswap32(val)); } -static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr) +static uint32_t pci_apb_ioreadb (void *opaque, hwaddr addr) { uint32_t val; @@ -260,7 +260,7 @@ static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr) return val; } -static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr) +static uint32_t pci_apb_ioreadw (void *opaque, hwaddr addr) { uint32_t val; @@ -268,7 +268,7 @@ static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr) return val; } -static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr) +static uint32_t pci_apb_ioreadl (void *opaque, hwaddr addr) { uint32_t val; @@ -351,8 +351,8 @@ static int apb_pci_bridge_initfn(PCIDevice *dev) return 0; } -PCIBus *pci_apb_init(target_phys_addr_t special_base, - target_phys_addr_t mem_base, +PCIBus *pci_apb_init(hwaddr special_base, + hwaddr mem_base, qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3, qemu_irq **pbm_irqs) { diff --git a/hw/apb_pci.h b/hw/apb_pci.h index 55f7c4c3b2..736db6118e 100644 --- a/hw/apb_pci.h +++ b/hw/apb_pci.h @@ -3,8 +3,8 @@ #include "qemu-common.h" -PCIBus *pci_apb_init(target_phys_addr_t special_base, - target_phys_addr_t mem_base, +PCIBus *pci_apb_init(hwaddr special_base, + hwaddr mem_base, qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3, qemu_irq **pbm_irqs); #endif @@ -16,12 +16,12 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see <http://www.gnu.org/licenses/> */ -#include "qemu-thread.h" +#include "qemu/thread.h" #include "apic_internal.h" #include "apic.h" #include "ioapic.h" -#include "msi.h" -#include "host-utils.h" +#include "pci/msi.h" +#include "qemu/host-utils.h" #include "trace.h" #include "pc.h" #include "apic-msidef.h" @@ -107,7 +107,7 @@ static void apic_sync_vapic(APICCommonState *s, int sync_type) length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr); if (sync_type & SYNC_TO_VAPIC) { - assert(qemu_cpu_is_self(s->cpu_env)); + assert(qemu_cpu_is_self(CPU(s->cpu))); vapic_state.tpr = s->tpr; vapic_state.enabled = 1; @@ -151,15 +151,15 @@ static void apic_local_deliver(APICCommonState *s, int vector) switch ((lvt >> 8) & 7) { case APIC_DM_SMI: - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_SMI); + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_SMI); break; case APIC_DM_NMI: - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_NMI); + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_NMI); break; case APIC_DM_EXTINT: - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); break; case APIC_DM_FIXED: @@ -187,7 +187,7 @@ void apic_deliver_pic_intr(DeviceState *d, int level) reset_bit(s->irr, lvt & 0xff); /* fall through */ case APIC_DM_EXTINT: - cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); break; } } @@ -248,18 +248,22 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask, case APIC_DM_SMI: foreach_apic(apic_iter, deliver_bitmask, - cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_SMI) ); + cpu_interrupt(&apic_iter->cpu->env, CPU_INTERRUPT_SMI) + ); return; case APIC_DM_NMI: foreach_apic(apic_iter, deliver_bitmask, - cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_NMI) ); + cpu_interrupt(&apic_iter->cpu->env, CPU_INTERRUPT_NMI) + ); return; case APIC_DM_INIT: /* normal INIT IPI sent to processors */ foreach_apic(apic_iter, deliver_bitmask, - cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_INIT) ); + cpu_interrupt(&apic_iter->cpu->env, + CPU_INTERRUPT_INIT) + ); return; case APIC_DM_EXTINT: @@ -293,7 +297,7 @@ static void apic_set_base(APICCommonState *s, uint64_t val) /* if disabled, cannot be enabled again */ if (!(val & MSR_IA32_APICBASE_ENABLE)) { s->apicbase &= ~MSR_IA32_APICBASE_ENABLE; - cpu_clear_apic_feature(s->cpu_env); + cpu_clear_apic_feature(&s->cpu->env); s->spurious_vec &= ~APIC_SV_ENABLE; } } @@ -359,13 +363,15 @@ static int apic_irq_pending(APICCommonState *s) /* signal the CPU if an irq is pending */ static void apic_update_irq(APICCommonState *s) { + CPUState *cpu = CPU(s->cpu); + if (!(s->spurious_vec & APIC_SV_ENABLE)) { return; } - if (!qemu_cpu_is_self(s->cpu_env)) { - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_POLL); + if (!qemu_cpu_is_self(cpu)) { + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_POLL); } else if (apic_irq_pending(s) > 0) { - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); } } @@ -472,18 +478,18 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, static void apic_startup(APICCommonState *s, int vector_num) { s->sipi_vector = vector_num; - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI); + cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_SIPI); } void apic_sipi(DeviceState *d) { APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); - cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI); + cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_SIPI); if (!s->wait_for_sipi) return; - cpu_x86_load_seg_cache_sipi(s->cpu_env, s->sipi_vector); + cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector); s->wait_for_sipi = 0; } @@ -630,25 +636,25 @@ static void apic_timer(void *opaque) apic_timer_update(s, s->next_time); } -static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr) +static uint32_t apic_mem_readb(void *opaque, hwaddr addr) { return 0; } -static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr) +static uint32_t apic_mem_readw(void *opaque, hwaddr addr) { return 0; } -static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void apic_mem_writeb(void *opaque, hwaddr addr, uint32_t val) { } -static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +static void apic_mem_writew(void *opaque, hwaddr addr, uint32_t val) { } -static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr) +static uint32_t apic_mem_readl(void *opaque, hwaddr addr) { DeviceState *d; APICCommonState *s; @@ -672,7 +678,7 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr) case 0x08: apic_sync_vapic(s, SYNC_FROM_VAPIC); if (apic_report_tpr_access) { - cpu_report_tpr_access(s->cpu_env, TPR_ACCESS_READ); + cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_READ); } val = s->tpr; break; @@ -732,7 +738,7 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr) return val; } -static void apic_send_msi(target_phys_addr_t addr, uint32_t data) +static void apic_send_msi(hwaddr addr, uint32_t data) { uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; @@ -743,7 +749,7 @@ static void apic_send_msi(target_phys_addr_t addr, uint32_t data) apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode); } -static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val) { DeviceState *d; APICCommonState *s; @@ -774,7 +780,7 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) break; case 0x08: if (apic_report_tpr_access) { - cpu_report_tpr_access(s->cpu_env, TPR_ACCESS_WRITE); + cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_WRITE); } s->tpr = val; apic_sync_vapic(s, SYNC_TO_VAPIC); diff --git a/hw/apic_common.c b/hw/apic_common.c index 371f95d909..0658be93c1 100644 --- a/hw/apic_common.c +++ b/hw/apic_common.c @@ -20,7 +20,7 @@ #include "apic.h" #include "apic_internal.h" #include "trace.h" -#include "kvm.h" +#include "sysemu/kvm.h" static int apic_irq_delivered; bool apic_report_tpr_access; @@ -89,7 +89,7 @@ void apic_enable_tpr_access_reporting(DeviceState *d, bool enable) } } -void apic_enable_vapic(DeviceState *d, target_phys_addr_t paddr) +void apic_enable_vapic(DeviceState *d, hwaddr paddr) { APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); APICCommonClass *info = APIC_COMMON_GET_CLASS(s); @@ -103,7 +103,7 @@ void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip, { APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); - vapic_report_tpr_access(s->vapic, s->cpu_env, ip, access); + vapic_report_tpr_access(s->vapic, &s->cpu->env, ip, access); } void apic_report_irq_delivered(int delivered) @@ -217,7 +217,7 @@ static void apic_reset_common(DeviceState *d) APICCommonClass *info = APIC_COMMON_GET_CLASS(s); bool bsp; - bsp = cpu_is_bsp(x86_env_get_cpu(s->cpu_env)); + bsp = cpu_is_bsp(s->cpu); s->apicbase = 0xfee00000 | (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE; @@ -368,7 +368,6 @@ static const VMStateDescription vmstate_apic_common = { static Property apic_properties_common[] = { DEFINE_PROP_UINT8("id", APICCommonState, id, -1), - DEFINE_PROP_PTR("cpu_env", APICCommonState, cpu_env), DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT, true), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/apic_internal.h b/hw/apic_internal.h index 4d8ff490ce..dcbbfd41cb 100644 --- a/hw/apic_internal.h +++ b/hw/apic_internal.h @@ -20,9 +20,9 @@ #ifndef QEMU_APIC_INTERNAL_H #define QEMU_APIC_INTERNAL_H -#include "memory.h" +#include "exec/memory.h" #include "sysbus.h" -#include "qemu-timer.h" +#include "qemu/timer.h" /* APIC Local Vector Table */ #define APIC_LVT_TIMER 0 @@ -95,8 +95,9 @@ typedef struct APICCommonClass struct APICCommonState { SysBusDevice busdev; + MemoryRegion io_memory; - void *cpu_env; + X86CPU *cpu; uint32_t apicbase; uint8_t id; uint8_t arb_id; @@ -124,7 +125,7 @@ struct APICCommonState { uint32_t vapic_control; DeviceState *vapic; - target_phys_addr_t vapic_paddr; /* note: persistence via kvmvapic */ + hwaddr vapic_paddr; /* note: persistence via kvmvapic */ }; typedef struct VAPICState { @@ -140,7 +141,7 @@ extern bool apic_report_tpr_access; void apic_report_irq_delivered(int delivered); bool apic_next_timer(APICCommonState *s, int64_t current_time); void apic_enable_tpr_access_reporting(DeviceState *d, bool enable); -void apic_enable_vapic(DeviceState *d, target_phys_addr_t paddr); +void apic_enable_vapic(DeviceState *d, hwaddr paddr); void vapic_report_tpr_access(DeviceState *dev, void *cpu, target_ulong ip, TPRAccess access); @@ -22,6 +22,7 @@ #include "apm.h" #include "hw.h" +#include "pci/pci.h" //#define DEBUG @@ -35,7 +36,8 @@ #define APM_CNT_IOPORT 0xb2 #define APM_STS_IOPORT 0xb3 -static void apm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) +static void apm_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, + unsigned size) { APMState *apm = opaque; addr &= 1; @@ -51,7 +53,7 @@ static void apm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t apm_ioport_readb(void *opaque, uint32_t addr) +static uint64_t apm_ioport_readb(void *opaque, hwaddr addr, unsigned size) { APMState *apm = opaque; uint32_t val; @@ -78,12 +80,23 @@ const VMStateDescription vmstate_apm = { } }; -void apm_init(APMState *apm, apm_ctrl_changed_t callback, void *arg) +static const MemoryRegionOps apm_ops = { + .read = apm_ioport_readb, + .write = apm_ioport_writeb, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +void apm_init(PCIDevice *dev, APMState *apm, apm_ctrl_changed_t callback, + void *arg) { apm->callback = callback; apm->arg = arg; /* ioport 0xb2, 0xb3 */ - register_ioport_write(APM_CNT_IOPORT, 2, 1, apm_ioport_writeb, apm); - register_ioport_read(APM_CNT_IOPORT, 2, 1, apm_ioport_readb, apm); + memory_region_init_io(&apm->io, &apm_ops, apm, "apm-io", 2); + memory_region_add_subregion(pci_address_space_io(dev), APM_CNT_IOPORT, + &apm->io); } @@ -4,6 +4,7 @@ #include <stdint.h> #include "qemu-common.h" #include "hw.h" +#include "exec/memory.h" typedef void (*apm_ctrl_changed_t)(uint32_t val, void *arg); @@ -13,9 +14,11 @@ typedef struct APMState { apm_ctrl_changed_t callback; void *arg; + MemoryRegion io; } APMState; -void apm_init(APMState *s, apm_ctrl_changed_t callback, void *arg); +void apm_init(PCIDevice *dev, APMState *s, apm_ctrl_changed_t callback, + void *arg); extern const VMStateDescription vmstate_apm; diff --git a/hw/applesmc.c b/hw/applesmc.c index 8bedaad310..c564b60c0a 100644 --- a/hw/applesmc.c +++ b/hw/applesmc.c @@ -32,8 +32,8 @@ #include "hw.h" #include "isa.h" -#include "console.h" -#include "qemu-timer.h" +#include "ui/console.h" +#include "qemu/timer.h" /* #define DEBUG_SMC */ diff --git a/hw/arm-misc.h b/hw/arm-misc.h index bdd8fecc99..cba7553039 100644 --- a/hw/arm-misc.h +++ b/hw/arm-misc.h @@ -11,7 +11,8 @@ #ifndef ARM_MISC_H #define ARM_MISC_H 1 -#include "memory.h" +#include "exec/memory.h" +#include "hw/irq.h" /* The CPU is also modeled as an interrupt controller. */ #define ARM_PIC_CPU_IRQ 0 @@ -30,15 +31,15 @@ struct arm_boot_info { const char *kernel_cmdline; const char *initrd_filename; const char *dtb_filename; - target_phys_addr_t loader_start; + hwaddr loader_start; /* multicore boards that use the default secondary core boot functions * need to put the address of the secondary boot code, the boot reg, * and the GIC address in the next 3 values, respectively. boards that * have their own boot functions can use these values as they want. */ - target_phys_addr_t smp_loader_start; - target_phys_addr_t smp_bootreg_addr; - target_phys_addr_t gic_cpu_if_addr; + hwaddr smp_loader_start; + hwaddr smp_bootreg_addr; + hwaddr gic_cpu_if_addr; int nb_cpus; int board_id; int (*atag_board)(const struct arm_boot_info *info, void *p); @@ -56,8 +57,9 @@ struct arm_boot_info { const struct arm_boot_info *info); /* Used internally by arm_boot.c */ int is_linux; - target_phys_addr_t initrd_size; - target_phys_addr_t entry; + hwaddr initrd_start; + hwaddr initrd_size; + hwaddr entry; }; void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info); diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 2b39fb3c85..6d049e7de6 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -1,6 +1,7 @@ obj-y = integratorcp.o versatilepb.o arm_pic.o obj-y += arm_boot.o obj-y += xilinx_zynq.o zynq_slcr.o +obj-y += xilinx_spips.o obj-y += arm_gic.o arm_gic_common.o obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c index 1bff3d3282..093331124a 100644 --- a/hw/arm11mpcore.c +++ b/hw/arm11mpcore.c @@ -8,7 +8,7 @@ */ #include "sysbus.h" -#include "qemu-timer.h" +#include "qemu/timer.h" /* MPCore private memory region. */ @@ -27,7 +27,7 @@ typedef struct mpcore_priv_state { /* Per-CPU private memory mapped IO. */ -static uint64_t mpcore_scu_read(void *opaque, target_phys_addr_t offset, +static uint64_t mpcore_scu_read(void *opaque, hwaddr offset, unsigned size) { mpcore_priv_state *s = (mpcore_priv_state *)opaque; @@ -44,11 +44,13 @@ static uint64_t mpcore_scu_read(void *opaque, target_phys_addr_t offset, case 0x0c: /* Invalidate all. */ return 0; default: - hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "mpcore_priv_read: Bad offset %x\n", (int)offset); + return 0; } } -static void mpcore_scu_write(void *opaque, target_phys_addr_t offset, +static void mpcore_scu_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { mpcore_priv_state *s = (mpcore_priv_state *)opaque; @@ -61,7 +63,8 @@ static void mpcore_scu_write(void *opaque, target_phys_addr_t offset, /* This is a no-op as cache is not emulated. */ break; default: - hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "mpcore_priv_read: Bad offset %x\n", (int)offset); } } @@ -89,7 +92,7 @@ static void mpcore_priv_map_setup(mpcore_priv_state *s) * at 0x200, 0x300... */ for (i = 0; i < (s->num_cpu + 1); i++) { - target_phys_addr_t offset = 0x100 + (i * 0x100); + hwaddr offset = 0x100 + (i * 0x100); memory_region_add_subregion(&s->container, offset, sysbus_mmio_get_region(gicbusdev, i + 1)); } @@ -98,7 +101,7 @@ static void mpcore_priv_map_setup(mpcore_priv_state *s) */ for (i = 0; i < (s->num_cpu + 1) * 2; i++) { /* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */ - target_phys_addr_t offset = 0x600 + (i >> 1) * 0x100 + (i & 1) * 0x20; + hwaddr offset = 0x600 + (i >> 1) * 0x100 + (i & 1) * 0x20; memory_region_add_subregion(&s->container, offset, sysbus_mmio_get_region(busdev, i)); } diff --git a/hw/arm_boot.c b/hw/arm_boot.c index a6e9143662..115f583876 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -10,15 +10,15 @@ #include "config.h" #include "hw.h" #include "arm-misc.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "boards.h" #include "loader.h" #include "elf.h" -#include "device_tree.h" +#include "sysemu/device_tree.h" +#include "qemu/config-file.h" #define KERNEL_ARGS_ADDR 0x100 #define KERNEL_LOAD_ADDR 0x00010000 -#define INITRD_LOAD_ADDR 0x00d00000 /* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ static uint32_t bootloader[] = { @@ -45,11 +45,17 @@ static uint32_t bootloader[] = { * for an interprocessor interrupt and polling a configurable * location for the kernel secondary CPU entry point. */ +#define DSB_INSN 0xf57ff04f +#define CP15_DSB_INSN 0xee070f9a /* mcr cp15, 0, r0, c7, c10, 4 */ + static uint32_t smpboot[] = { - 0xe59f201c, /* ldr r2, gic_cpu_if */ - 0xe59f001c, /* ldr r0, startaddr */ + 0xe59f2028, /* ldr r2, gic_cpu_if */ + 0xe59f0028, /* ldr r0, startaddr */ 0xe3a01001, /* mov r1, #1 */ - 0xe5821000, /* str r1, [r2] */ + 0xe5821000, /* str r1, [r2] - set GICC_CTLR.Enable */ + 0xe3a010ff, /* mov r1, #0xff */ + 0xe5821004, /* str r1, [r2, 4] - set GIC_PMR.Priority to 0xff */ + DSB_INSN, /* dsb */ 0xe320f003, /* wfi */ 0xe5901000, /* ldr r1, [r0] */ 0xe1110001, /* tst r1, r1 */ @@ -66,6 +72,11 @@ static void default_write_secondary(ARMCPU *cpu, smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr; smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr; for (n = 0; n < ARRAY_SIZE(smpboot); n++) { + /* Replace DSB with the pre-v7 DSB if necessary. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_V7) && + smpboot[n] == DSB_INSN) { + smpboot[n] = CP15_DSB_INSN; + } smpboot[n] = tswap32(smpboot[n]); } rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), @@ -89,8 +100,8 @@ static void default_reset_secondary(ARMCPU *cpu, static void set_kernel_args(const struct arm_boot_info *info) { int initrd_size = info->initrd_size; - target_phys_addr_t base = info->loader_start; - target_phys_addr_t p; + hwaddr base = info->loader_start; + hwaddr p; p = base + KERNEL_ARGS_ADDR; /* ATAG_CORE */ @@ -109,7 +120,7 @@ static void set_kernel_args(const struct arm_boot_info *info) /* ATAG_INITRD2 */ WRITE_WORD(p, 4); WRITE_WORD(p, 0x54420005); - WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR); + WRITE_WORD(p, info->initrd_start); WRITE_WORD(p, initrd_size); } if (info->kernel_cmdline && *info->kernel_cmdline) { @@ -142,10 +153,10 @@ static void set_kernel_args(const struct arm_boot_info *info) static void set_kernel_args_old(const struct arm_boot_info *info) { - target_phys_addr_t p; + hwaddr p; const char *s; int initrd_size = info->initrd_size; - target_phys_addr_t base = info->loader_start; + hwaddr base = info->loader_start; /* see linux/include/asm-arm/setup.h */ p = base + KERNEL_ARGS_ADDR; @@ -185,10 +196,11 @@ static void set_kernel_args_old(const struct arm_boot_info *info) /* pages_in_vram */ WRITE_WORD(p, 0); /* initrd_start */ - if (initrd_size) - WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR); - else + if (initrd_size) { + WRITE_WORD(p, info->initrd_start); + } else { WRITE_WORD(p, 0); + } /* initrd_size */ WRITE_WORD(p, initrd_size); /* rd_start */ @@ -213,7 +225,7 @@ static void set_kernel_args_old(const struct arm_boot_info *info) } } -static int load_dtb(target_phys_addr_t addr, const struct arm_boot_info *binfo) +static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo) { #ifdef CONFIG_FDT uint32_t *mem_reg_property; @@ -281,14 +293,13 @@ static int load_dtb(target_phys_addr_t addr, const struct arm_boot_info *binfo) if (binfo->initrd_size) { rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", - binfo->loader_start + INITRD_LOAD_ADDR); + binfo->initrd_start); if (rc < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); } rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", - binfo->loader_start + INITRD_LOAD_ADDR + - binfo->initrd_size); + binfo->initrd_start + binfo->initrd_size); if (rc < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); } @@ -342,7 +353,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) int n; int is_linux = 0; uint64_t elf_entry; - target_phys_addr_t entry; + hwaddr entry; int big_endian; QemuOpts *machine_opts; @@ -375,6 +386,19 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) big_endian = 0; #endif + /* We want to put the initrd far enough into RAM that when the + * kernel is uncompressed it will not clobber the initrd. However + * on boards without much RAM we must ensure that we still leave + * enough room for a decent sized initrd, and on boards with large + * amounts of RAM we must avoid the initrd being so far up in RAM + * that it is outside lowmem and inaccessible to the kernel. + * So for boards with less than 256MB of RAM we put the initrd + * halfway into RAM, and for boards with 256MB of RAM or more we put + * the initrd at 128MB. + */ + info->initrd_start = info->loader_start + + MIN(info->ram_size / 2, 128 * 1024 * 1024); + /* Assume that raw images are linux kernels, and ELF images are not. */ kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry, NULL, NULL, big_endian, ELF_MACHINE, 1); @@ -398,10 +422,9 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) if (is_linux) { if (info->initrd_filename) { initrd_size = load_image_targphys(info->initrd_filename, - info->loader_start - + INITRD_LOAD_ADDR, - info->ram_size - - INITRD_LOAD_ADDR); + info->initrd_start, + info->ram_size - + info->initrd_start); if (initrd_size < 0) { fprintf(stderr, "qemu: could not load initrd '%s'\n", info->initrd_filename); @@ -419,9 +442,8 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) */ if (info->dtb_filename) { /* Place the DTB after the initrd in memory */ - target_phys_addr_t dtb_start = TARGET_PAGE_ALIGN(info->loader_start - + INITRD_LOAD_ADDR - + initrd_size); + hwaddr dtb_start = TARGET_PAGE_ALIGN(info->initrd_start + + initrd_size); if (load_dtb(dtb_start, info)) { exit(1); } diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 186ac66f00..b6062c4241 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -36,7 +36,7 @@ static const uint8_t gic_id[] = { #define NUM_CPU(s) ((s)->num_cpu) -static inline int gic_get_current_cpu(gic_state *s) +static inline int gic_get_current_cpu(GICState *s) { if (s->num_cpu > 1) { return cpu_single_env->cpu_index; @@ -46,7 +46,7 @@ static inline int gic_get_current_cpu(gic_state *s) /* TODO: Many places that call this routine could be optimized. */ /* Update interrupt status after enabled or pending bits have been changed. */ -void gic_update(gic_state *s) +void gic_update(GICState *s) { int best_irq; int best_prio; @@ -73,10 +73,10 @@ void gic_update(gic_state *s) } } level = 0; - if (best_prio <= s->priority_mask[cpu]) { + if (best_prio < s->priority_mask[cpu]) { s->current_pending[cpu] = best_irq; if (best_prio < s->running_priority[cpu]) { - DPRINTF("Raised pending IRQ %d\n", best_irq); + DPRINTF("Raised pending IRQ %d (cpu %d)\n", best_irq, cpu); level = 1; } } @@ -84,7 +84,7 @@ void gic_update(gic_state *s) } } -void gic_set_pending_private(gic_state *s, int cpu, int irq) +void gic_set_pending_private(GICState *s, int cpu, int irq) { int cm = 1 << cpu; @@ -105,7 +105,7 @@ static void gic_set_irq(void *opaque, int irq, int level) * [N+32..N+63] : PPI (internal interrupts for CPU 1 * ... */ - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; int cm, target; if (irq < (s->num_irq - GIC_INTERNAL)) { /* The first external input line is internal interrupt 32. */ @@ -137,7 +137,7 @@ static void gic_set_irq(void *opaque, int irq, int level) gic_update(s); } -static void gic_set_running_irq(gic_state *s, int cpu, int irq) +static void gic_set_running_irq(GICState *s, int cpu, int irq) { s->running_irq[cpu] = irq; if (irq == 1023) { @@ -148,7 +148,7 @@ static void gic_set_running_irq(gic_state *s, int cpu, int irq) gic_update(s); } -uint32_t gic_acknowledge_irq(gic_state *s, int cpu) +uint32_t gic_acknowledge_irq(GICState *s, int cpu) { int new_irq; int cm = 1 << cpu; @@ -167,7 +167,7 @@ uint32_t gic_acknowledge_irq(gic_state *s, int cpu) return new_irq; } -void gic_complete_irq(gic_state *s, int cpu, int irq) +void gic_complete_irq(GICState *s, int cpu, int irq) { int update = 0; int cm = 1 << cpu; @@ -212,9 +212,9 @@ void gic_complete_irq(gic_state *s, int cpu, int irq) } } -static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) +static uint32_t gic_dist_readb(void *opaque, hwaddr offset) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; uint32_t res; int irq; int i; @@ -324,11 +324,12 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) } return res; bad_reg: - hw_error("gic_dist_readb: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "gic_dist_readb: Bad offset %x\n", (int)offset); return 0; } -static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset) +static uint32_t gic_dist_readw(void *opaque, hwaddr offset) { uint32_t val; val = gic_dist_readb(opaque, offset); @@ -336,7 +337,7 @@ static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset) return val; } -static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset) +static uint32_t gic_dist_readl(void *opaque, hwaddr offset) { uint32_t val; val = gic_dist_readw(opaque, offset); @@ -344,10 +345,10 @@ static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset) return val; } -static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, +static void gic_dist_writeb(void *opaque, hwaddr offset, uint32_t value) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; int irq; int i; int cpu; @@ -373,7 +374,8 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, value = 0xff; for (i = 0; i < 8; i++) { if (value & (1 << i)) { - int mask = (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq); + int mask = + (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i); int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; if (!GIC_TEST_ENABLED(irq + i, cm)) { @@ -416,7 +418,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, for (i = 0; i < 8; i++) { if (value & (1 << i)) { - GIC_SET_PENDING(irq + i, GIC_TARGET(irq)); + GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i)); } } } else if (offset < 0x300) { @@ -487,20 +489,21 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, gic_update(s); return; bad_reg: - hw_error("gic_dist_writeb: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "gic_dist_writeb: Bad offset %x\n", (int)offset); } -static void gic_dist_writew(void *opaque, target_phys_addr_t offset, +static void gic_dist_writew(void *opaque, hwaddr offset, uint32_t value) { gic_dist_writeb(opaque, offset, value & 0xff); gic_dist_writeb(opaque, offset + 1, value >> 8); } -static void gic_dist_writel(void *opaque, target_phys_addr_t offset, +static void gic_dist_writel(void *opaque, hwaddr offset, uint32_t value) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; if (offset == 0xf00) { int cpu; int irq; @@ -539,7 +542,7 @@ static const MemoryRegionOps gic_dist_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint32_t gic_cpu_read(gic_state *s, int cpu, int offset) +static uint32_t gic_cpu_read(GICState *s, int cpu, int offset) { switch (offset) { case 0x00: /* Control */ @@ -556,17 +559,18 @@ static uint32_t gic_cpu_read(gic_state *s, int cpu, int offset) case 0x18: /* Highest Pending Interrupt */ return s->current_pending[cpu]; default: - hw_error("gic_cpu_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "gic_cpu_read: Bad offset %x\n", (int)offset); return 0; } } -static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value) +static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value) { switch (offset) { case 0x00: /* Control */ s->cpu_enabled[cpu] = (value & 1); - DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled ? "En" : "Dis"); + DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled[cpu] ? "En" : "Dis"); break; case 0x04: /* Priority mask */ s->priority_mask[cpu] = (value & 0xff); @@ -577,44 +581,45 @@ static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value) case 0x10: /* End Of Interrupt */ return gic_complete_irq(s, cpu, value & 0x3ff); default: - hw_error("gic_cpu_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "gic_cpu_write: Bad offset %x\n", (int)offset); return; } gic_update(s); } /* Wrappers to read/write the GIC CPU interface for the current CPU */ -static uint64_t gic_thiscpu_read(void *opaque, target_phys_addr_t addr, +static uint64_t gic_thiscpu_read(void *opaque, hwaddr addr, unsigned size) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; return gic_cpu_read(s, gic_get_current_cpu(s), addr); } -static void gic_thiscpu_write(void *opaque, target_phys_addr_t addr, +static void gic_thiscpu_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; gic_cpu_write(s, gic_get_current_cpu(s), addr, value); } /* Wrappers to read/write the GIC CPU interface for a specific CPU. - * These just decode the opaque pointer into gic_state* + cpu id. + * These just decode the opaque pointer into GICState* + cpu id. */ -static uint64_t gic_do_cpu_read(void *opaque, target_phys_addr_t addr, +static uint64_t gic_do_cpu_read(void *opaque, hwaddr addr, unsigned size) { - gic_state **backref = (gic_state **)opaque; - gic_state *s = *backref; + GICState **backref = (GICState **)opaque; + GICState *s = *backref; int id = (backref - s->backref); return gic_cpu_read(s, id, addr); } -static void gic_do_cpu_write(void *opaque, target_phys_addr_t addr, +static void gic_do_cpu_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - gic_state **backref = (gic_state **)opaque; - gic_state *s = *backref; + GICState **backref = (GICState **)opaque; + GICState *s = *backref; int id = (backref - s->backref); gic_cpu_write(s, id, addr, value); } @@ -631,7 +636,7 @@ static const MemoryRegionOps gic_cpu_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -void gic_init_irqs_and_distributor(gic_state *s, int num_irq) +void gic_init_irqs_and_distributor(GICState *s, int num_irq) { int i; @@ -657,7 +662,7 @@ static int arm_gic_init(SysBusDevice *dev) { /* Device instance init function for the GIC sysbus device */ int i; - gic_state *s = FROM_SYSBUS(gic_state, dev); + GICState *s = FROM_SYSBUS(GICState, dev); ARMGICClass *agc = ARM_GIC_GET_CLASS(s); agc->parent_init(dev); @@ -701,8 +706,9 @@ static void arm_gic_class_init(ObjectClass *klass, void *data) static TypeInfo arm_gic_info = { .name = TYPE_ARM_GIC, .parent = TYPE_ARM_GIC_COMMON, - .instance_size = sizeof(gic_state), + .instance_size = sizeof(GICState), .class_init = arm_gic_class_init, + .class_size = sizeof(ARMGICClass), }; static void arm_gic_register_types(void) diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c index 360e7823f7..73ae331807 100644 --- a/hw/arm_gic_common.c +++ b/hw/arm_gic_common.c @@ -22,7 +22,7 @@ static void gic_save(QEMUFile *f, void *opaque) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; int i; int j; @@ -56,7 +56,7 @@ static void gic_save(QEMUFile *f, void *opaque) static int gic_load(QEMUFile *f, void *opaque, int version_id) { - gic_state *s = (gic_state *)opaque; + GICState *s = (GICState *)opaque; int i; int j; @@ -96,7 +96,7 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) static int arm_gic_common_init(SysBusDevice *dev) { - gic_state *s = FROM_SYSBUS(gic_state, dev); + GICState *s = FROM_SYSBUS(GICState, dev); int num_irq = s->num_irq; if (s->num_cpu > NCPU) { @@ -123,11 +123,15 @@ static int arm_gic_common_init(SysBusDevice *dev) static void arm_gic_common_reset(DeviceState *dev) { - gic_state *s = FROM_SYSBUS(gic_state, sysbus_from_qdev(dev)); + GICState *s = FROM_SYSBUS(GICState, sysbus_from_qdev(dev)); int i; memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state)); for (i = 0 ; i < s->num_cpu; i++) { - s->priority_mask[i] = 0xf0; + if (s->revision == REV_11MPCORE) { + s->priority_mask[i] = 0xf0; + } else { + s->priority_mask[i] = 0; + } s->current_pending[i] = 1023; s->running_irq[i] = 1023; s->running_priority[i] = 0x100; @@ -147,13 +151,13 @@ static void arm_gic_common_reset(DeviceState *dev) } static Property arm_gic_common_properties[] = { - DEFINE_PROP_UINT32("num-cpu", gic_state, num_cpu, 1), - DEFINE_PROP_UINT32("num-irq", gic_state, num_irq, 32), + DEFINE_PROP_UINT32("num-cpu", GICState, num_cpu, 1), + DEFINE_PROP_UINT32("num-irq", GICState, num_irq, 32), /* Revision can be 1 or 2 for GIC architecture specification * versions 1 or 2, or 0 to indicate the legacy 11MPCore GIC. * (Internally, 0xffffffff also indicates "not a GIC but an NVIC".) */ - DEFINE_PROP_UINT32("revision", gic_state, revision, 1), + DEFINE_PROP_UINT32("revision", GICState, revision, 1), DEFINE_PROP_END_OF_LIST(), }; @@ -170,7 +174,7 @@ static void arm_gic_common_class_init(ObjectClass *klass, void *data) static TypeInfo arm_gic_common_type = { .name = TYPE_ARM_GIC_COMMON, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(gic_state), + .instance_size = sizeof(GICState), .class_size = sizeof(ARMGICCommonClass), .class_init = arm_gic_common_class_init, .abstract = true, diff --git a/hw/arm_gic_internal.h b/hw/arm_gic_internal.h index db4fad564f..699352ca8b 100644 --- a/hw/arm_gic_internal.h +++ b/hw/arm_gic_internal.h @@ -69,7 +69,7 @@ typedef struct gic_irq_state { unsigned trigger:1; /* nonzero = edge triggered. */ } gic_irq_state; -typedef struct gic_state { +typedef struct GICState { SysBusDevice busdev; qemu_irq parent_irq[NCPU]; int enabled; @@ -92,25 +92,25 @@ typedef struct gic_state { /* This is just so we can have an opaque pointer which identifies * both this GIC and which CPU interface we should be accessing. */ - struct gic_state *backref[NCPU]; + struct GICState *backref[NCPU]; MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */ uint32_t num_irq; uint32_t revision; -} gic_state; +} GICState; /* The special cases for the revision property: */ #define REV_11MPCORE 0 #define REV_NVIC 0xffffffff -void gic_set_pending_private(gic_state *s, int cpu, int irq); -uint32_t gic_acknowledge_irq(gic_state *s, int cpu); -void gic_complete_irq(gic_state *s, int cpu, int irq); -void gic_update(gic_state *s); -void gic_init_irqs_and_distributor(gic_state *s, int num_irq); +void gic_set_pending_private(GICState *s, int cpu, int irq); +uint32_t gic_acknowledge_irq(GICState *s, int cpu); +void gic_complete_irq(GICState *s, int cpu, int irq); +void gic_update(GICState *s); +void gic_init_irqs_and_distributor(GICState *s, int num_irq); #define TYPE_ARM_GIC_COMMON "arm_gic_common" #define ARM_GIC_COMMON(obj) \ - OBJECT_CHECK(gic_state, (obj), TYPE_ARM_GIC_COMMON) + OBJECT_CHECK(GICState, (obj), TYPE_ARM_GIC_COMMON) #define ARM_GIC_COMMON_CLASS(klass) \ OBJECT_CLASS_CHECK(ARMGICCommonClass, (klass), TYPE_ARM_GIC_COMMON) #define ARM_GIC_COMMON_GET_CLASS(obj) \ @@ -122,7 +122,7 @@ typedef struct ARMGICCommonClass { #define TYPE_ARM_GIC "arm_gic" #define ARM_GIC(obj) \ - OBJECT_CHECK(gic_state, (obj), TYPE_ARM_GIC) + OBJECT_CHECK(GICState, (obj), TYPE_ARM_GIC) #define ARM_GIC_CLASS(klass) \ OBJECT_CLASS_CHECK(ARMGICClass, (klass), TYPE_ARM_GIC) #define ARM_GIC_GET_CLASS(obj) \ diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c index de6a0863d8..6abf0ee160 100644 --- a/hw/arm_l2x0.c +++ b/hw/arm_l2x0.c @@ -51,7 +51,7 @@ static const VMStateDescription vmstate_l2x0 = { }; -static uint64_t l2x0_priv_read(void *opaque, target_phys_addr_t offset, +static uint64_t l2x0_priv_read(void *opaque, hwaddr offset, unsigned size) { uint32_t cache_data; @@ -87,13 +87,14 @@ static uint64_t l2x0_priv_read(void *opaque, target_phys_addr_t offset, case 0xF80: return 0; default: - fprintf(stderr, "l2x0_priv_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "l2x0_priv_read: Bad offset %x\n", (int)offset); break; } return 0; } -static void l2x0_priv_write(void *opaque, target_phys_addr_t offset, +static void l2x0_priv_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { l2x0_state *s = (l2x0_state *)opaque; @@ -128,7 +129,8 @@ static void l2x0_priv_write(void *opaque, target_phys_addr_t offset, case 0xF80: return; default: - fprintf(stderr, "l2x0_priv_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "l2x0_priv_write: Bad offset %x\n", (int)offset); break; } } diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c index fe43cbb5f1..1febaeb7b1 100644 --- a/hw/arm_mptimer.c +++ b/hw/arm_mptimer.c @@ -20,7 +20,7 @@ */ #include "sysbus.h" -#include "qemu-timer.h" +#include "qemu/timer.h" /* This device implements the per-cpu private timer and watchdog block * which is used in both the ARM11MPCore and Cortex-A9MP. @@ -92,7 +92,7 @@ static void timerblock_tick(void *opaque) timerblock_update_irq(tb); } -static uint64_t timerblock_read(void *opaque, target_phys_addr_t addr, +static uint64_t timerblock_read(void *opaque, hwaddr addr, unsigned size) { timerblock *tb = (timerblock *)opaque; @@ -120,7 +120,7 @@ static uint64_t timerblock_read(void *opaque, target_phys_addr_t addr, } } -static void timerblock_write(void *opaque, target_phys_addr_t addr, +static void timerblock_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { timerblock *tb = (timerblock *)opaque; @@ -159,7 +159,7 @@ static void timerblock_write(void *opaque, target_phys_addr_t addr, /* Wrapper functions to implement the "read timer/watchdog for * the current CPU" memory regions. */ -static uint64_t arm_thistimer_read(void *opaque, target_phys_addr_t addr, +static uint64_t arm_thistimer_read(void *opaque, hwaddr addr, unsigned size) { arm_mptimer_state *s = (arm_mptimer_state *)opaque; @@ -167,7 +167,7 @@ static uint64_t arm_thistimer_read(void *opaque, target_phys_addr_t addr, return timerblock_read(&s->timerblock[id * 2], addr, size); } -static void arm_thistimer_write(void *opaque, target_phys_addr_t addr, +static void arm_thistimer_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { arm_mptimer_state *s = (arm_mptimer_state *)opaque; @@ -175,7 +175,7 @@ static void arm_thistimer_write(void *opaque, target_phys_addr_t addr, timerblock_write(&s->timerblock[id * 2], addr, value, size); } -static uint64_t arm_thiswdog_read(void *opaque, target_phys_addr_t addr, +static uint64_t arm_thiswdog_read(void *opaque, hwaddr addr, unsigned size) { arm_mptimer_state *s = (arm_mptimer_state *)opaque; @@ -183,7 +183,7 @@ static uint64_t arm_thiswdog_read(void *opaque, target_phys_addr_t addr, return timerblock_read(&s->timerblock[id * 2 + 1], addr, size); } -static void arm_thiswdog_write(void *opaque, target_phys_addr_t addr, +static void arm_thiswdog_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { arm_mptimer_state *s = (arm_mptimer_state *)opaque; diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index 5f1237b8c2..b733617aa0 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -8,10 +8,10 @@ */ #include "hw.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "sysbus.h" #include "primecell.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #define LOCK_VALUE 0xa05f @@ -92,7 +92,7 @@ static void arm_sysctl_reset(DeviceState *d) } } -static uint64_t arm_sysctl_read(void *opaque, target_phys_addr_t offset, +static uint64_t arm_sysctl_read(void *opaque, hwaddr offset, unsigned size) { arm_sysctl_state *s = (arm_sysctl_state *)opaque; @@ -184,12 +184,14 @@ static uint64_t arm_sysctl_read(void *opaque, target_phys_addr_t offset, return s->sys_cfgstat; default: bad_reg: - printf ("arm_sysctl_read: Bad register offset 0x%x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "arm_sysctl_read: Bad register offset 0x%x\n", + (int)offset); return 0; } } -static void arm_sysctl_write(void *opaque, target_phys_addr_t offset, +static void arm_sysctl_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { arm_sysctl_state *s = (arm_sysctl_state *)opaque; @@ -339,7 +341,9 @@ static void arm_sysctl_write(void *opaque, target_phys_addr_t offset, return; default: bad_reg: - printf ("arm_sysctl_write: Bad register offset 0x%x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "arm_sysctl_write: Bad register offset 0x%x\n", + (int)offset); return; } } diff --git a/hw/arm_timer.c b/hw/arm_timer.c index e3ecce29f0..37e28e993c 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -8,7 +8,7 @@ */ #include "sysbus.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "qemu-common.h" #include "qdev.h" #include "ptimer.h" @@ -45,7 +45,7 @@ static void arm_timer_update(arm_timer_state *s) } } -static uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset) +static uint32_t arm_timer_read(void *opaque, hwaddr offset) { arm_timer_state *s = (arm_timer_state *)opaque; @@ -64,7 +64,8 @@ static uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset) return 0; return s->int_level; default: - hw_error("%s: Bad offset %x\n", __func__, (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset %x\n", __func__, (int)offset); return 0; } } @@ -87,7 +88,7 @@ static void arm_timer_recalibrate(arm_timer_state *s, int reload) ptimer_set_limit(s->timer, limit, reload); } -static void arm_timer_write(void *opaque, target_phys_addr_t offset, +static void arm_timer_write(void *opaque, hwaddr offset, uint32_t value) { arm_timer_state *s = (arm_timer_state *)opaque; @@ -131,7 +132,8 @@ static void arm_timer_write(void *opaque, target_phys_addr_t offset, arm_timer_recalibrate(s, 0); break; default: - hw_error("%s: Bad offset %x\n", __func__, (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset %x\n", __func__, (int)offset); } arm_timer_update(s); } @@ -202,7 +204,7 @@ static void sp804_set_irq(void *opaque, int irq, int level) qemu_set_irq(s->irq, s->level[0] || s->level[1]); } -static uint64_t sp804_read(void *opaque, target_phys_addr_t offset, +static uint64_t sp804_read(void *opaque, hwaddr offset, unsigned size) { sp804_state *s = (sp804_state *)opaque; @@ -223,14 +225,18 @@ static uint64_t sp804_read(void *opaque, target_phys_addr_t offset, /* Integration Test control registers, which we won't support */ case 0xf00: /* TimerITCR */ case 0xf04: /* TimerITOP (strictly write only but..) */ + qemu_log_mask(LOG_UNIMP, + "%s: integration test registers unimplemented\n", + __func__); return 0; } - hw_error("%s: Bad offset %x\n", __func__, (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset %x\n", __func__, (int)offset); return 0; } -static void sp804_write(void *opaque, target_phys_addr_t offset, +static void sp804_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { sp804_state *s = (sp804_state *)opaque; @@ -246,7 +252,8 @@ static void sp804_write(void *opaque, target_phys_addr_t offset, } /* Technically we could be writing to the Test Registers, but not likely */ - hw_error("%s: Bad offset %x\n", __func__, (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n", + __func__, (int)offset); } static const MemoryRegionOps sp804_ops = { @@ -291,7 +298,7 @@ typedef struct { arm_timer_state *timer[3]; } icp_pit_state; -static uint64_t icp_pit_read(void *opaque, target_phys_addr_t offset, +static uint64_t icp_pit_read(void *opaque, hwaddr offset, unsigned size) { icp_pit_state *s = (icp_pit_state *)opaque; @@ -300,13 +307,13 @@ static uint64_t icp_pit_read(void *opaque, target_phys_addr_t offset, /* ??? Don't know the PrimeCell ID for this device. */ n = offset >> 8; if (n > 2) { - hw_error("%s: Bad timer %d\n", __func__, n); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n); } return arm_timer_read(s->timer[n], offset & 0xff); } -static void icp_pit_write(void *opaque, target_phys_addr_t offset, +static void icp_pit_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { icp_pit_state *s = (icp_pit_state *)opaque; @@ -314,7 +321,7 @@ static void icp_pit_write(void *opaque, target_phys_addr_t offset, n = offset >> 8; if (n > 2) { - hw_error("%s: Bad timer %d\n", __func__, n); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n); } arm_timer_write(s->timer[n], offset & 0xff, value); diff --git a/hw/armv7m.c b/hw/armv7m.c index 9f66667c6d..ce2ec9b4dc 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -25,14 +25,14 @@ static inline uint32_t bitband_addr(void * opaque, uint32_t addr) } -static uint32_t bitband_readb(void *opaque, target_phys_addr_t offset) +static uint32_t bitband_readb(void *opaque, hwaddr offset) { uint8_t v; cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1); return (v & (1 << ((offset >> 2) & 7))) != 0; } -static void bitband_writeb(void *opaque, target_phys_addr_t offset, +static void bitband_writeb(void *opaque, hwaddr offset, uint32_t value) { uint32_t addr; @@ -48,7 +48,7 @@ static void bitband_writeb(void *opaque, target_phys_addr_t offset, cpu_physical_memory_write(addr, &v, 1); } -static uint32_t bitband_readw(void *opaque, target_phys_addr_t offset) +static uint32_t bitband_readw(void *opaque, hwaddr offset) { uint32_t addr; uint16_t mask; @@ -60,7 +60,7 @@ static uint32_t bitband_readw(void *opaque, target_phys_addr_t offset) return (v & mask) != 0; } -static void bitband_writew(void *opaque, target_phys_addr_t offset, +static void bitband_writew(void *opaque, hwaddr offset, uint32_t value) { uint32_t addr; @@ -77,7 +77,7 @@ static void bitband_writew(void *opaque, target_phys_addr_t offset, cpu_physical_memory_write(addr, (uint8_t *)&v, 2); } -static uint32_t bitband_readl(void *opaque, target_phys_addr_t offset) +static uint32_t bitband_readl(void *opaque, hwaddr offset) { uint32_t addr; uint32_t mask; @@ -89,7 +89,7 @@ static uint32_t bitband_readl(void *opaque, target_phys_addr_t offset) return (v & mask) != 0; } -static void bitband_writel(void *opaque, target_phys_addr_t offset, +static void bitband_writel(void *opaque, hwaddr offset, uint32_t value) { uint32_t addr; diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index 6a0832eb3f..0907e42c0c 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -11,13 +11,13 @@ */ #include "sysbus.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "arm-misc.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #include "arm_gic_internal.h" typedef struct { - gic_state gic; + GICState gic; struct { uint32_t control; uint32_t reload; @@ -138,9 +138,8 @@ void armv7m_nvic_complete_irq(void *opaque, int irq) gic_complete_irq(&s->gic, 0, irq); } -static uint32_t nvic_readl(void *opaque, uint32_t offset) +static uint32_t nvic_readl(nvic_state *s, uint32_t offset) { - nvic_state *s = (nvic_state *)opaque; uint32_t val; int irq; @@ -216,14 +215,6 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset) case 0xd14: /* Configuration Control. */ /* TODO: Implement Configuration Control bits. */ return 0; - case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */ - irq = offset - 0xd14; - val = 0; - val |= s->gic.priority1[irq++][0]; - val |= s->gic.priority1[irq++][0] << 8; - val |= s->gic.priority1[irq++][0] << 16; - val |= s->gic.priority1[irq][0] << 24; - return val; case 0xd24: /* System Handler Status. */ val = 0; if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0); @@ -243,7 +234,7 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset) return val; case 0xd28: /* Configurable Fault Status. */ /* TODO: Implement Fault Status. */ - hw_error("Not implemented: Configurable Fault Status."); + qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n"); return 0; case 0xd2c: /* Hard Fault Status. */ case 0xd30: /* Debug Fault Status. */ @@ -251,7 +242,8 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset) case 0xd38: /* Bus Fault Address. */ case 0xd3c: /* Aux Fault Status. */ /* TODO: Implement fault status registers. */ - goto bad_reg; + qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n"); + return 0; case 0xd40: /* PFR0. */ return 0x00000030; case 0xd44: /* PRF1. */ @@ -280,14 +272,13 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset) return 0x01310102; /* TODO: Implement debug registers. */ default: - bad_reg: - hw_error("NVIC: Bad read offset 0x%x\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset); + return 0; } } -static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) +static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value) { - nvic_state *s = (nvic_state *)opaque; uint32_t oldval; switch (offset) { case 0x10: /* SysTick Control and Status. */ @@ -345,27 +336,17 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) case 0xd0c: /* Application Interrupt/Reset Control. */ if ((value >> 16) == 0x05fa) { if (value & 2) { - hw_error("VECTCLRACTIVE not implemented"); + qemu_log_mask(LOG_UNIMP, "VECTCLRACTIVE unimplemented\n"); } if (value & 5) { - hw_error("System reset"); + qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n"); } } break; case 0xd10: /* System Control. */ case 0xd14: /* Configuration Control. */ /* TODO: Implement control registers. */ - goto bad_reg; - case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */ - { - int irq; - irq = offset - 0xd14; - s->gic.priority1[irq++][0] = value & 0xff; - s->gic.priority1[irq++][0] = (value >> 8) & 0xff; - s->gic.priority1[irq++][0] = (value >> 16) & 0xff; - s->gic.priority1[irq][0] = (value >> 24) & 0xff; - gic_update(&s->gic); - } + qemu_log_mask(LOG_UNIMP, "NVIC: SCR and CCR unimplemented\n"); break; case 0xd24: /* System Handler Control. */ /* TODO: Real hardware allows you to set/clear the active bits @@ -380,47 +361,71 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) case 0xd34: /* Mem Manage Address. */ case 0xd38: /* Bus Fault Address. */ case 0xd3c: /* Aux Fault Status. */ - goto bad_reg; + qemu_log_mask(LOG_UNIMP, + "NVIC: fault status registers unimplemented\n"); + break; case 0xf00: /* Software Triggered Interrupt Register */ if ((value & 0x1ff) < s->num_irq) { gic_set_pending_private(&s->gic, 0, value & 0x1ff); } break; default: - bad_reg: - hw_error("NVIC: Bad write offset 0x%x\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "NVIC: Bad write offset 0x%x\n", offset); } } -static uint64_t nvic_sysreg_read(void *opaque, target_phys_addr_t addr, +static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr, unsigned size) { - /* At the moment we only support the ID registers for byte/word access. - * This is not strictly correct as a few of the other registers also - * allow byte access. - */ + nvic_state *s = (nvic_state *)opaque; uint32_t offset = addr; - if (offset >= 0xfe0) { + int i; + uint32_t val; + + switch (offset) { + case 0xd18 ... 0xd23: /* System Handler Priority. */ + val = 0; + for (i = 0; i < size; i++) { + val |= s->gic.priority1[(offset - 0xd14) + i][0] << (i * 8); + } + return val; + case 0xfe0 ... 0xfff: /* ID. */ if (offset & 3) { return 0; } return nvic_id[(offset - 0xfe0) >> 2]; } if (size == 4) { - return nvic_readl(opaque, offset); + return nvic_readl(s, offset); } - hw_error("NVIC: Bad read of size %d at offset 0x%x\n", size, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "NVIC: Bad read of size %d at offset 0x%x\n", size, offset); + return 0; } -static void nvic_sysreg_write(void *opaque, target_phys_addr_t addr, +static void nvic_sysreg_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { + nvic_state *s = (nvic_state *)opaque; uint32_t offset = addr; + int i; + + switch (offset) { + case 0xd18 ... 0xd23: /* System Handler Priority. */ + for (i = 0; i < size; i++) { + s->gic.priority1[(offset - 0xd14) + i][0] = + (value >> (i * 8)) & 0xff; + } + gic_update(&s->gic); + return; + } if (size == 4) { - nvic_writel(opaque, offset, value); + nvic_writel(s, offset, value); return; } - hw_error("NVIC: Bad write of size %d at offset 0x%x\n", size, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "NVIC: Bad write of size %d at offset 0x%x\n", size, offset); } static const MemoryRegionOps nvic_sysreg_ops = { @@ -450,9 +455,11 @@ static void armv7m_nvic_reset(DeviceState *dev) nc->parent_reset(dev); /* Common GIC reset resets to disabled; the NVIC doesn't have * per-CPU interfaces so mark our non-existent CPU interface - * as enabled by default. + * as enabled by default, and with a priority mask which allows + * all interrupts through. */ s->gic.cpu_enabled[0] = 1; + s->gic.priority_mask[0] = 0x100; /* The NVIC as a whole is always enabled. */ s->gic.enabled = 1; systick_reset(s); @@ -489,7 +496,8 @@ static int armv7m_nvic_init(SysBusDevice *dev) */ memory_region_init_alias(&s->gic_iomem_alias, "nvic-gic", &s->gic.iomem, 0x100, 0xc00); - memory_region_add_subregion_overlap(&s->container, 0x100, &s->gic.iomem, 1); + memory_region_add_subregion_overlap(&s->container, 0x100, + &s->gic_iomem_alias, 1); /* Map the whole thing into system memory at the location required * by the v7M architecture. */ @@ -504,9 +512,9 @@ static void armv7m_nvic_instance_init(Object *obj) * than our superclass. This function runs after qdev init * has set the defaults from the Property array and before * any user-specified property setting, so just modify the - * value in the gic_state struct. + * value in the GICState struct. */ - gic_state *s = ARM_GIC_COMMON(obj); + GICState *s = ARM_GIC_COMMON(obj); /* The ARM v7m may have anything from 0 to 496 external interrupt * IRQ lines. We default to 64. Other boards may differ and should * set the num-irq property appropriately. diff --git a/hw/audiodev.h b/hw/audiodev.h index ed2790f5f6..428274f929 100644 --- a/hw/audiodev.h +++ b/hw/audiodev.h @@ -1,3 +1,6 @@ +#ifndef HW_AUDIODEV_H +#define HW_AUDIODEV_H 1 + /* es1370.c */ int es1370_init(PCIBus *bus); @@ -18,3 +21,5 @@ int cs4231a_init(ISABus *bus); /* intel-hda.c + hda-audio.c */ int intel_hda_and_codec_init(PCIBus *bus); + +#endif diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c index eab6327bed..2ca606b835 100644 --- a/hw/axis_dev88.c +++ b/hw/axis_dev88.c @@ -23,15 +23,15 @@ */ #include "sysbus.h" -#include "net.h" +#include "net/net.h" #include "flash.h" #include "boards.h" #include "etraxfs.h" #include "loader.h" #include "elf.h" #include "cris-boot.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" #define D(x) #define DNAND(x) @@ -47,7 +47,7 @@ struct nand_state_t }; static struct nand_state_t nand_state; -static uint64_t nand_read(void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t nand_read(void *opaque, hwaddr addr, unsigned size) { struct nand_state_t *s = opaque; uint32_t r; @@ -62,7 +62,7 @@ static uint64_t nand_read(void *opaque, target_phys_addr_t addr, unsigned size) } static void -nand_write(void *opaque, target_phys_addr_t addr, uint64_t value, +nand_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct nand_state_t *s = opaque; @@ -166,7 +166,7 @@ static struct gpio_state_t uint32_t regs[0x5c / 4]; } gpio_state; -static uint64_t gpio_read(void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t gpio_read(void *opaque, hwaddr addr, unsigned size) { struct gpio_state_t *s = opaque; uint32_t r = 0; @@ -195,7 +195,7 @@ static uint64_t gpio_read(void *opaque, target_phys_addr_t addr, unsigned size) D(printf("%s %x=%x\n", __func__, addr, r)); } -static void gpio_write(void *opaque, target_phys_addr_t addr, uint64_t value, +static void gpio_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct gpio_state_t *s = opaque; @@ -242,11 +242,12 @@ static const MemoryRegionOps gpio_ops = { static struct cris_load_info li; static -void axisdev88_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +void axisdev88_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; CRISCPU *cpu; CPUCRISState *env; DeviceState *dev; @@ -22,8 +22,8 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "qemu-char.h" -#include "qemu-timer.h" +#include "char/char.h" +#include "qemu/timer.h" #include "usb.h" #include "baum.h" #include <brlapi.h> @@ -21,6 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#ifndef HW_BAUM_H +#define HW_BAUM_H 1 /* char device */ CharDriverState *chr_baum_init(QemuOpts *opts); + +#endif diff --git a/hw/blizzard.c b/hw/blizzard.c index 29074c4fa7..24bde32e5a 100644 --- a/hw/blizzard.c +++ b/hw/blizzard.c @@ -19,10 +19,10 @@ */ #include "qemu-common.h" -#include "console.h" +#include "ui/console.h" #include "devices.h" #include "vga_int.h" -#include "pixel_ops.h" +#include "ui/pixel_ops.h" typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int); @@ -878,8 +878,6 @@ void s1d13745_write_block(void *opaque, int dc, len -= 2; buf += 2; } - - return; } static void blizzard_update_display(void *opaque) @@ -923,8 +921,8 @@ static void blizzard_update_display(void *opaque) for (; y < s->my[1]; y ++, src += bypl, dst += bypl) memcpy(dst, src, bwidth); - dpy_update(s->state, s->mx[0], s->my[0], - s->mx[1] - s->mx[0], y - s->my[0]); + dpy_gfx_update(s->state, s->mx[0], s->my[0], + s->mx[1] - s->mx[0], y - s->my[0]); s->mx[0] = s->x; s->mx[1] = 0; @@ -933,13 +931,13 @@ static void blizzard_update_display(void *opaque) } static void blizzard_screen_dump(void *opaque, const char *filename, - bool cswitch) + bool cswitch, Error **errp) { BlizzardState *s = (BlizzardState *) opaque; blizzard_update_display(opaque); if (s && ds_get_data(s->state)) - ppm_save(filename, s->state->surface); + ppm_save(filename, s->state->surface, errp); } #define DEPTH 8 diff --git a/hw/block-common.c b/hw/block-common.c index f0196d78dc..0f1b64ec95 100644 --- a/hw/block-common.c +++ b/hw/block-common.c @@ -7,9 +7,9 @@ * later. See the COPYING file in the top-level directory. */ -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "hw/block-common.h" -#include "qemu-error.h" +#include "qemu/error-report.h" void blkconf_serial(BlockConf *conf, char **serial) { diff --git a/hw/boards.h b/hw/boards.h index 59c01d0367..4540e952f7 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -3,21 +3,29 @@ #ifndef HW_BOARDS_H #define HW_BOARDS_H +#include "sysemu/blockdev.h" #include "qdev.h" -typedef void QEMUMachineInitFunc(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model); +typedef struct QEMUMachineInitArgs { + ram_addr_t ram_size; + const char *boot_device; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; + const char *cpu_model; +} QEMUMachineInitArgs; + +typedef void QEMUMachineInitFunc(QEMUMachineInitArgs *args); + +typedef void QEMUMachineResetFunc(void); typedef struct QEMUMachine { const char *name; const char *alias; const char *desc; QEMUMachineInitFunc *init; - int use_scsi; + QEMUMachineResetFunc *reset; + BlockInterfaceType block_default_type; int max_cpus; unsigned int no_serial:1, no_parallel:1, diff --git a/hw/bonito.c b/hw/bonito.c index 77786f8883..0498c9be79 100644 --- a/hw/bonito.c +++ b/hw/bonito.c @@ -40,12 +40,12 @@ #include <assert.h> #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "pc.h" #include "mips.h" -#include "pci_host.h" -#include "sysemu.h" -#include "exec-memory.h" +#include "pci/pci_host.h" +#include "sysemu/sysemu.h" +#include "exec/address-spaces.h" //#define DEBUG_BONITO @@ -180,11 +180,14 @@ #define PCI_ADDR(busno,devno,funno,regno) \ ((((busno)<<16)&0xff0000) + (((devno)<<11)&0xf800) + (((funno)<<8)&0x700) + (regno)) -typedef PCIHostState BonitoState; +#define TYPE_BONITO_PCI_HOST_BRIDGE "Bonito-pcihost" + +typedef struct BonitoState BonitoState; typedef struct PCIBonitoState { PCIDevice dev; + BonitoState *pcihost; uint32_t regs[BONITO_REGS]; @@ -208,19 +211,28 @@ typedef struct PCIBonitoState MemoryRegion iomem_ldma; MemoryRegion iomem_cop; - target_phys_addr_t bonito_pciio_start; - target_phys_addr_t bonito_pciio_length; + hwaddr bonito_pciio_start; + hwaddr bonito_pciio_length; int bonito_pciio_handle; - target_phys_addr_t bonito_localio_start; - target_phys_addr_t bonito_localio_length; + hwaddr bonito_localio_start; + hwaddr bonito_localio_length; int bonito_localio_handle; } PCIBonitoState; -PCIBonitoState * bonito_state; +#define BONITO_PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(BonitoState, (obj), TYPE_BONITO_PCI_HOST_BRIDGE) + +struct BonitoState { + PCIHostState parent_obj; + + qemu_irq *pic; -static void bonito_writel(void *opaque, target_phys_addr_t addr, + PCIBonitoState *pci_dev; +}; + +static void bonito_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { PCIBonitoState *s = opaque; @@ -283,7 +295,7 @@ static void bonito_writel(void *opaque, target_phys_addr_t addr, } } -static uint64_t bonito_readl(void *opaque, target_phys_addr_t addr, +static uint64_t bonito_readl(void *opaque, hwaddr addr, unsigned size) { PCIBonitoState *s = opaque; @@ -310,23 +322,25 @@ static const MemoryRegionOps bonito_ops = { }, }; -static void bonito_pciconf_writel(void *opaque, target_phys_addr_t addr, +static void bonito_pciconf_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { PCIBonitoState *s = opaque; + PCIDevice *d = PCI_DEVICE(s); DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %x\n", addr, val); - s->dev.config_write(&s->dev, addr, val, 4); + d->config_write(d, addr, val, 4); } -static uint64_t bonito_pciconf_readl(void *opaque, target_phys_addr_t addr, +static uint64_t bonito_pciconf_readl(void *opaque, hwaddr addr, unsigned size) { PCIBonitoState *s = opaque; + PCIDevice *d = PCI_DEVICE(s); DPRINTF("bonito_pciconf_readl "TARGET_FMT_plx"\n", addr); - return s->dev.config_read(&s->dev, addr, 4); + return d->config_read(d, addr, 4); } /* north bridge PCI configure space. 0x1fe0 0000 - 0x1fe0 00ff */ @@ -341,7 +355,7 @@ static const MemoryRegionOps bonito_pciconf_ops = { }, }; -static uint64_t bonito_ldma_readl(void *opaque, target_phys_addr_t addr, +static uint64_t bonito_ldma_readl(void *opaque, hwaddr addr, unsigned size) { uint32_t val; @@ -352,7 +366,7 @@ static uint64_t bonito_ldma_readl(void *opaque, target_phys_addr_t addr, return val; } -static void bonito_ldma_writel(void *opaque, target_phys_addr_t addr, +static void bonito_ldma_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { PCIBonitoState *s = opaque; @@ -370,7 +384,7 @@ static const MemoryRegionOps bonito_ldma_ops = { }, }; -static uint64_t bonito_cop_readl(void *opaque, target_phys_addr_t addr, +static uint64_t bonito_cop_readl(void *opaque, hwaddr addr, unsigned size) { uint32_t val; @@ -381,7 +395,7 @@ static uint64_t bonito_cop_readl(void *opaque, target_phys_addr_t addr, return val; } -static void bonito_cop_writel(void *opaque, target_phys_addr_t addr, +static void bonito_cop_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { PCIBonitoState *s = opaque; @@ -399,9 +413,10 @@ static const MemoryRegionOps bonito_cop_ops = { }, }; -static uint32_t bonito_sbridge_pciaddr(void *opaque, target_phys_addr_t addr) +static uint32_t bonito_sbridge_pciaddr(void *opaque, hwaddr addr) { PCIBonitoState *s = opaque; + PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost); uint32_t cfgaddr; uint32_t idsel; uint32_t devno; @@ -423,21 +438,23 @@ static uint32_t bonito_sbridge_pciaddr(void *opaque, target_phys_addr_t addr) regno = (cfgaddr & BONITO_PCICONF_REG_MASK) >> BONITO_PCICONF_REG_OFFSET; if (idsel == 0) { - fprintf(stderr, "error in bonito pci config address" TARGET_FMT_plx + fprintf(stderr, "error in bonito pci config address " TARGET_FMT_plx ",pcimap_cfg=%x\n", addr, s->regs[BONITO_PCIMAP_CFG]); exit(1); } - pciaddr = PCI_ADDR(pci_bus_num(s->pcihost->bus), devno, funno, regno); + pciaddr = PCI_ADDR(pci_bus_num(phb->bus), devno, funno, regno); DPRINTF("cfgaddr %x pciaddr %x busno %x devno %d funno %d regno %d\n", - cfgaddr, pciaddr, pci_bus_num(s->pcihost->bus), devno, funno, regno); + cfgaddr, pciaddr, pci_bus_num(phb->bus), devno, funno, regno); return pciaddr; } -static void bonito_spciconf_writeb(void *opaque, target_phys_addr_t addr, +static void bonito_spciconf_writeb(void *opaque, hwaddr addr, uint32_t val) { PCIBonitoState *s = opaque; + PCIDevice *d = PCI_DEVICE(s); + PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost); uint32_t pciaddr; uint16_t status; @@ -449,24 +466,26 @@ static void bonito_spciconf_writeb(void *opaque, target_phys_addr_t addr, } /* set the pci address in s->config_reg */ - s->pcihost->config_reg = (pciaddr) | (1u << 31); - pci_data_write(s->pcihost->bus, s->pcihost->config_reg, val & 0xff, 1); + phb->config_reg = (pciaddr) | (1u << 31); + pci_data_write(phb->bus, phb->config_reg, val & 0xff, 1); /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */ - status = pci_get_word(s->dev.config + PCI_STATUS); + status = pci_get_word(d->config + PCI_STATUS); status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT); - pci_set_word(s->dev.config + PCI_STATUS, status); + pci_set_word(d->config + PCI_STATUS, status); } -static void bonito_spciconf_writew(void *opaque, target_phys_addr_t addr, +static void bonito_spciconf_writew(void *opaque, hwaddr addr, uint32_t val) { PCIBonitoState *s = opaque; + PCIDevice *d = PCI_DEVICE(s); + PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost); uint32_t pciaddr; uint16_t status; DPRINTF("bonito_spciconf_writew "TARGET_FMT_plx" val %x\n", addr, val); - assert((addr&0x1)==0); + assert((addr & 0x1) == 0); pciaddr = bonito_sbridge_pciaddr(s, addr); @@ -475,24 +494,26 @@ static void bonito_spciconf_writew(void *opaque, target_phys_addr_t addr, } /* set the pci address in s->config_reg */ - s->pcihost->config_reg = (pciaddr) | (1u << 31); - pci_data_write(s->pcihost->bus, s->pcihost->config_reg, val, 2); + phb->config_reg = (pciaddr) | (1u << 31); + pci_data_write(phb->bus, phb->config_reg, val, 2); /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */ - status = pci_get_word(s->dev.config + PCI_STATUS); + status = pci_get_word(d->config + PCI_STATUS); status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT); - pci_set_word(s->dev.config + PCI_STATUS, status); + pci_set_word(d->config + PCI_STATUS, status); } -static void bonito_spciconf_writel(void *opaque, target_phys_addr_t addr, +static void bonito_spciconf_writel(void *opaque, hwaddr addr, uint32_t val) { PCIBonitoState *s = opaque; + PCIDevice *d = PCI_DEVICE(s); + PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost); uint32_t pciaddr; uint16_t status; DPRINTF("bonito_spciconf_writel "TARGET_FMT_plx" val %x\n", addr, val); - assert((addr&0x3)==0); + assert((addr & 0x3) == 0); pciaddr = bonito_sbridge_pciaddr(s, addr); @@ -501,18 +522,20 @@ static void bonito_spciconf_writel(void *opaque, target_phys_addr_t addr, } /* set the pci address in s->config_reg */ - s->pcihost->config_reg = (pciaddr) | (1u << 31); - pci_data_write(s->pcihost->bus, s->pcihost->config_reg, val, 4); + phb->config_reg = (pciaddr) | (1u << 31); + pci_data_write(phb->bus, phb->config_reg, val, 4); /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */ - status = pci_get_word(s->dev.config + PCI_STATUS); + status = pci_get_word(d->config + PCI_STATUS); status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT); - pci_set_word(s->dev.config + PCI_STATUS, status); + pci_set_word(d->config + PCI_STATUS, status); } -static uint32_t bonito_spciconf_readb(void *opaque, target_phys_addr_t addr) +static uint32_t bonito_spciconf_readb(void *opaque, hwaddr addr) { PCIBonitoState *s = opaque; + PCIDevice *d = PCI_DEVICE(s); + PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost); uint32_t pciaddr; uint16_t status; @@ -524,24 +547,26 @@ static uint32_t bonito_spciconf_readb(void *opaque, target_phys_addr_t addr) } /* set the pci address in s->config_reg */ - s->pcihost->config_reg = (pciaddr) | (1u << 31); + phb->config_reg = (pciaddr) | (1u << 31); /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */ - status = pci_get_word(s->dev.config + PCI_STATUS); + status = pci_get_word(d->config + PCI_STATUS); status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT); - pci_set_word(s->dev.config + PCI_STATUS, status); + pci_set_word(d->config + PCI_STATUS, status); - return pci_data_read(s->pcihost->bus, s->pcihost->config_reg, 1); + return pci_data_read(phb->bus, phb->config_reg, 1); } -static uint32_t bonito_spciconf_readw(void *opaque, target_phys_addr_t addr) +static uint32_t bonito_spciconf_readw(void *opaque, hwaddr addr) { PCIBonitoState *s = opaque; + PCIDevice *d = PCI_DEVICE(s); + PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost); uint32_t pciaddr; uint16_t status; DPRINTF("bonito_spciconf_readw "TARGET_FMT_plx"\n", addr); - assert((addr&0x1)==0); + assert((addr & 0x1) == 0); pciaddr = bonito_sbridge_pciaddr(s, addr); @@ -550,24 +575,26 @@ static uint32_t bonito_spciconf_readw(void *opaque, target_phys_addr_t addr) } /* set the pci address in s->config_reg */ - s->pcihost->config_reg = (pciaddr) | (1u << 31); + phb->config_reg = (pciaddr) | (1u << 31); /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */ - status = pci_get_word(s->dev.config + PCI_STATUS); + status = pci_get_word(d->config + PCI_STATUS); status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT); - pci_set_word(s->dev.config + PCI_STATUS, status); + pci_set_word(d->config + PCI_STATUS, status); - return pci_data_read(s->pcihost->bus, s->pcihost->config_reg, 2); + return pci_data_read(phb->bus, phb->config_reg, 2); } -static uint32_t bonito_spciconf_readl(void *opaque, target_phys_addr_t addr) +static uint32_t bonito_spciconf_readl(void *opaque, hwaddr addr) { PCIBonitoState *s = opaque; + PCIDevice *d = PCI_DEVICE(s); + PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost); uint32_t pciaddr; uint16_t status; DPRINTF("bonito_spciconf_readl "TARGET_FMT_plx"\n", addr); - assert((addr&0x3) == 0); + assert((addr & 0x3) == 0); pciaddr = bonito_sbridge_pciaddr(s, addr); @@ -576,14 +603,14 @@ static uint32_t bonito_spciconf_readl(void *opaque, target_phys_addr_t addr) } /* set the pci address in s->config_reg */ - s->pcihost->config_reg = (pciaddr) | (1u << 31); + phb->config_reg = (pciaddr) | (1u << 31); /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */ - status = pci_get_word(s->dev.config + PCI_STATUS); + status = pci_get_word(d->config + PCI_STATUS); status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT); - pci_set_word(s->dev.config + PCI_STATUS, status); + pci_set_word(d->config + PCI_STATUS, status); - return pci_data_read(s->pcihost->bus, s->pcihost->config_reg, 4); + return pci_data_read(phb->bus, phb->config_reg, 4); } /* south bridge PCI configure space. 0x1fe8 0000 - 0x1fef ffff */ @@ -607,13 +634,15 @@ static const MemoryRegionOps bonito_spciconf_ops = { static void pci_bonito_set_irq(void *opaque, int irq_num, int level) { - qemu_irq *pic = opaque; + BonitoState *s = opaque; + qemu_irq *pic = s->pic; + PCIBonitoState *bonito_state = s->pci_dev; int internal_irq = irq_num - BONITO_IRQ_BASE; - if (bonito_state->regs[BONITO_INTEDGE] & (1<<internal_irq)) { + if (bonito_state->regs[BONITO_INTEDGE] & (1 << internal_irq)) { qemu_irq_pulse(*pic); } else { /* level triggered */ - if (bonito_state->regs[BONITO_INTPOL] & (1<<internal_irq)) { + if (bonito_state->regs[BONITO_INTPOL] & (1 << internal_irq)) { qemu_irq_raise(*pic); } else { qemu_irq_lower(*pic); @@ -673,13 +702,21 @@ static const VMStateDescription vmstate_bonito = { static int bonito_pcihost_initfn(SysBusDevice *dev) { + PCIHostState *phb = PCI_HOST_BRIDGE(dev); + + phb->bus = pci_register_bus(DEVICE(dev), "pci", + pci_bonito_set_irq, pci_bonito_map_irq, dev, + get_system_memory(), get_system_io(), + 0x28, 32); + return 0; } static int bonito_initfn(PCIDevice *dev) { PCIBonitoState *s = DO_UPCAST(PCIBonitoState, dev, dev); - SysBusDevice *sysbus = &s->pcihost->busdev; + SysBusDevice *sysbus = SYS_BUS_DEVICE(s->pcihost); + PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost); /* Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined" */ pci_config_set_prog_interface(dev->config, 0x00); @@ -691,15 +728,15 @@ static int bonito_initfn(PCIDevice *dev) sysbus_mmio_map(sysbus, 0, BONITO_INTERNAL_REG_BASE); /* set the north bridge pci configure mapping */ - memory_region_init_io(&s->pcihost->conf_mem, &bonito_pciconf_ops, s, + memory_region_init_io(&phb->conf_mem, &bonito_pciconf_ops, s, "north-bridge-pci-config", BONITO_PCICONFIG_SIZE); - sysbus_init_mmio(sysbus, &s->pcihost->conf_mem); + sysbus_init_mmio(sysbus, &phb->conf_mem); sysbus_mmio_map(sysbus, 1, BONITO_PCICONFIG_BASE); /* set the south bridge pci configure mapping */ - memory_region_init_io(&s->pcihost->data_mem, &bonito_spciconf_ops, s, + memory_region_init_io(&phb->data_mem, &bonito_spciconf_ops, s, "south-bridge-pci-config", BONITO_SPCICONFIG_SIZE); - sysbus_init_mmio(sysbus, &s->pcihost->data_mem); + sysbus_init_mmio(sysbus, &phb->data_mem); sysbus_mmio_map(sysbus, 2, BONITO_SPCICONFIG_BASE); memory_region_init_io(&s->iomem_ldma, &bonito_ldma_ops, s, @@ -742,28 +779,25 @@ static int bonito_initfn(PCIDevice *dev) PCIBus *bonito_init(qemu_irq *pic) { DeviceState *dev; - PCIBus *b; BonitoState *pcihost; + PCIHostState *phb; PCIBonitoState *s; PCIDevice *d; - dev = qdev_create(NULL, "Bonito-pcihost"); - pcihost = FROM_SYSBUS(BonitoState, sysbus_from_qdev(dev)); - b = pci_register_bus(&pcihost->busdev.qdev, "pci", pci_bonito_set_irq, - pci_bonito_map_irq, pic, get_system_memory(), - get_system_io(), - 0x28, 32); - pcihost->bus = b; + dev = qdev_create(NULL, TYPE_BONITO_PCI_HOST_BRIDGE); + phb = PCI_HOST_BRIDGE(dev); + pcihost = BONITO_PCI_HOST_BRIDGE(dev); + pcihost->pic = pic; qdev_init_nofail(dev); /* set the pcihost pointer before bonito_initfn is called */ - d = pci_create(b, PCI_DEVFN(0, 0), "Bonito"); + d = pci_create(phb->bus, PCI_DEVFN(0, 0), "Bonito"); s = DO_UPCAST(PCIBonitoState, dev, d); s->pcihost = pcihost; - bonito_state = s; - qdev_init_nofail(&d->qdev); + pcihost->pci_dev = s; + qdev_init_nofail(DEVICE(d)); - return b; + return phb->bus; } static void bonito_class_init(ObjectClass *klass, void *data) @@ -781,7 +815,7 @@ static void bonito_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_bonito; } -static TypeInfo bonito_info = { +static const TypeInfo bonito_info = { .name = "Bonito", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIBonitoState), @@ -797,9 +831,9 @@ static void bonito_pcihost_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo bonito_pcihost_info = { - .name = "Bonito-pcihost", - .parent = TYPE_SYS_BUS_DEVICE, +static const TypeInfo bonito_pcihost_info = { + .name = TYPE_BONITO_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(BonitoState), .class_init = bonito_pcihost_class_init, }; diff --git a/hw/bt-hci-csr.c b/hw/bt-hci-csr.c index 772b677ba1..2070bb940c 100644 --- a/hw/bt-hci-csr.c +++ b/hw/bt-hci-csr.c @@ -19,10 +19,10 @@ */ #include "qemu-common.h" -#include "qemu-char.h" -#include "qemu-timer.h" +#include "char/char.h" +#include "qemu/timer.h" #include "irq.h" -#include "net.h" +#include "bt/bt.h" #include "bt.h" struct csrhci_s { diff --git a/hw/bt-hci.c b/hw/bt-hci.c index a3a7fb49e2..69d2c73862 100644 --- a/hw/bt-hci.c +++ b/hw/bt-hci.c @@ -19,9 +19,9 @@ */ #include "qemu-common.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "usb.h" -#include "net.h" +#include "bt/bt.h" #include "bt.h" struct bt_hci_s { @@ -786,7 +786,6 @@ static void bt_hci_lmp_connection_request(struct bt_link_s *link) memcpy(¶ms.dev_class, &link->host->class, sizeof(params.dev_class)); params.link_type = ACL_LINK; bt_hci_event(hci, EVT_CONN_REQUEST, ¶ms, EVT_CONN_REQUEST_SIZE); - return; } static void bt_hci_conn_accept_timeout(void *opaque) @@ -943,7 +942,6 @@ static int bt_hci_name_req(struct bt_hci_s *hci, bdaddr_t *bdaddr) { struct bt_device_s *slave; evt_remote_name_req_complete params; - int len; for (slave = hci->device.net->slave; slave; slave = slave->next) if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr)) @@ -955,9 +953,7 @@ static int bt_hci_name_req(struct bt_hci_s *hci, bdaddr_t *bdaddr) params.status = HCI_SUCCESS; bacpy(¶ms.bdaddr, &slave->bd_addr); - len = snprintf(params.name, sizeof(params.name), - "%s", slave->lmp_name ?: ""); - memset(params.name + len, 0, sizeof(params.name) - len); + pstrcpy(params.name, sizeof(params.name), slave->lmp_name ?: ""); bt_hci_event(hci, EVT_REMOTE_NAME_REQ_COMPLETE, ¶ms, EVT_REMOTE_NAME_REQ_COMPLETE_SIZE); @@ -1388,7 +1384,7 @@ static inline void bt_hci_event_complete_read_local_name(struct bt_hci_s *hci) params.status = HCI_SUCCESS; memset(params.name, 0, sizeof(params.name)); if (hci->device.lmp_name) - strncpy(params.name, hci->device.lmp_name, sizeof(params.name)); + pstrcpy(params.name, sizeof(params.name), hci->device.lmp_name); bt_hci_event_complete(hci, ¶ms, READ_LOCAL_NAME_RP_SIZE); } diff --git a/hw/bt-hid.c b/hw/bt-hid.c index 8d7a3dae21..cfa7c145b8 100644 --- a/hw/bt-hid.c +++ b/hw/bt-hid.c @@ -19,8 +19,8 @@ */ #include "qemu-common.h" -#include "qemu-timer.h" -#include "console.h" +#include "qemu/timer.h" +#include "ui/console.h" #include "hid.h" #include "bt.h" diff --git a/hw/bt-l2cap.c b/hw/bt-l2cap.c index cb43ee7733..ba061c0da3 100644 --- a/hw/bt-l2cap.c +++ b/hw/bt-l2cap.c @@ -18,7 +18,7 @@ */ #include "qemu-common.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "bt.h" #define L2CAP_CID_MAX 0x100 /* Between 0x40 and 0x10000 */ @@ -18,7 +18,7 @@ */ #include "qemu-common.h" -#include "net.h" +#include "bt/bt.h" #include "bt.h" /* Slave implementations can ignore this */ @@ -23,6 +23,11 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#ifndef HW_BT_H +#define HW_BT_H 1 + +#include "hw/irq.h" + /* BD Address */ typedef struct { uint8_t b[6]; @@ -2181,3 +2186,5 @@ enum bt_sdp_attribute_id { SDP_ATTR_NORMALLY_CONNECTABLE = 0x020d, SDP_ATTR_BOOT_DEVICE = 0x020e, }; + +#endif diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c index 967f62513e..40a239973c 100644 --- a/hw/cadence_gem.c +++ b/hw/cadence_gem.c @@ -25,7 +25,7 @@ #include <zlib.h> /* For crc32 */ #include "sysbus.h" -#include "net.h" +#include "net/net.h" #include "net/checksum.h" #ifdef CADENCE_GEM_ERR_DEBUG @@ -605,7 +605,7 @@ static int gem_mac_address_filter(GemState *s, const uint8_t *packet) static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) { unsigned desc[2]; - target_phys_addr_t packet_desc_addr, last_desc_addr; + hwaddr packet_desc_addr, last_desc_addr; GemState *s; unsigned rxbufsize, bytes_to_copy; unsigned rxbuf_offset; @@ -824,7 +824,7 @@ static void gem_transmit_updatestats(GemState *s, const uint8_t *packet, static void gem_transmit(GemState *s) { unsigned desc[2]; - target_phys_addr_t packet_desc_addr; + hwaddr packet_desc_addr; uint8_t tx_packet[2048]; uint8_t *p; unsigned total_bytes; @@ -1021,7 +1021,7 @@ static void gem_phy_write(GemState *s, unsigned reg_num, uint16_t val) * gem_read32: * Read a GEM register. */ -static uint64_t gem_read(void *opaque, target_phys_addr_t offset, unsigned size) +static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size) { GemState *s; uint32_t retval; @@ -1067,7 +1067,7 @@ static uint64_t gem_read(void *opaque, target_phys_addr_t offset, unsigned size) * gem_write32: * Write a GEM register. */ -static void gem_write(void *opaque, target_phys_addr_t offset, uint64_t val, +static void gem_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { GemState *s = (GemState *)opaque; diff --git a/hw/cadence_ttc.c b/hw/cadence_ttc.c index dd02f86eb9..9e1cb1f152 100644 --- a/hw/cadence_ttc.c +++ b/hw/cadence_ttc.c @@ -17,7 +17,7 @@ */ #include "sysbus.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #ifdef CADENCE_TTC_ERR_DEBUG #define DB_PRINT(...) do { \ @@ -76,7 +76,7 @@ static void cadence_timer_update(CadenceTimerState *s) } static CadenceTimerState *cadence_timer_from_addr(void *opaque, - target_phys_addr_t offset) + hwaddr offset) { unsigned int index; CadenceTTCState *s = (CadenceTTCState *)opaque; @@ -224,7 +224,7 @@ static void cadence_timer_tick(void *opaque) cadence_timer_run(s); } -static uint32_t cadence_ttc_read_imp(void *opaque, target_phys_addr_t offset) +static uint32_t cadence_ttc_read_imp(void *opaque, hwaddr offset) { CadenceTimerState *s = cadence_timer_from_addr(opaque, offset); uint32_t value; @@ -274,6 +274,7 @@ static uint32_t cadence_ttc_read_imp(void *opaque, target_phys_addr_t offset) /* cleared after read */ value = s->reg_intr; s->reg_intr = 0; + cadence_timer_update(s); return value; case 0x60: /* interrupt enable */ @@ -296,7 +297,7 @@ static uint32_t cadence_ttc_read_imp(void *opaque, target_phys_addr_t offset) } } -static uint64_t cadence_ttc_read(void *opaque, target_phys_addr_t offset, +static uint64_t cadence_ttc_read(void *opaque, hwaddr offset, unsigned size) { uint32_t ret = cadence_ttc_read_imp(opaque, offset); @@ -305,7 +306,7 @@ static uint64_t cadence_ttc_read(void *opaque, target_phys_addr_t offset, return ret; } -static void cadence_ttc_write(void *opaque, target_phys_addr_t offset, +static void cadence_ttc_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { CadenceTimerState *s = cadence_timer_from_addr(opaque, offset); @@ -355,7 +356,6 @@ static void cadence_ttc_write(void *opaque, target_phys_addr_t offset, case 0x54: /* interrupt register */ case 0x58: case 0x5c: - s->reg_intr &= (~value & 0xfff); break; case 0x60: /* interrupt enable */ diff --git a/hw/cadence_uart.c b/hw/cadence_uart.c index d98e531372..7dd2fe54ed 100644 --- a/hw/cadence_uart.c +++ b/hw/cadence_uart.c @@ -17,8 +17,8 @@ */ #include "sysbus.h" -#include "qemu-char.h" -#include "qemu-timer.h" +#include "char/char.h" +#include "qemu/timer.h" #ifdef CADENCE_UART_ERR_DEBUG #define DB_PRINT(...) do { \ @@ -354,12 +354,12 @@ static void uart_read_rx_fifo(UartState *s, uint32_t *c) uart_update_status(s); } -static void uart_write(void *opaque, target_phys_addr_t offset, +static void uart_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { UartState *s = (UartState *)opaque; - DB_PRINT(" offset:%x data:%08x\n", offset, (unsigned)value); + DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value); offset >>= 2; switch (offset) { case R_IER: /* ier (wts imr) */ @@ -397,20 +397,23 @@ static void uart_write(void *opaque, target_phys_addr_t offset, } } -static uint64_t uart_read(void *opaque, target_phys_addr_t offset, +static uint64_t uart_read(void *opaque, hwaddr offset, unsigned size) { UartState *s = (UartState *)opaque; uint32_t c = 0; offset >>= 2; - if (offset > R_MAX) { - return 0; + if (offset >= R_MAX) { + c = 0; } else if (offset == R_TX_RX) { uart_read_rx_fifo(s, &c); - return c; + } else { + c = s->r[offset]; } - return s->r[offset]; + + DB_PRINT(" offset:%x data:%08x\n", (unsigned)(offset << 2), (unsigned)c); + return c; } static const MemoryRegionOps uart_ops = { @@ -23,7 +23,7 @@ #include "qemu-common.h" #include "irq.h" #include "devices.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" //#define DEBUG diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c index f4a6da4283..6fd44695ae 100644 --- a/hw/ccid-card-emulated.c +++ b/hw/ccid-card-emulated.c @@ -31,9 +31,9 @@ #include <vreader.h> #include <vcard_emul.h> -#include "qemu-thread.h" -#include "qemu-char.h" -#include "monitor.h" +#include "qemu/thread.h" +#include "char/char.h" +#include "monitor/monitor.h" #include "hw/ccid.h" #define DPRINTF(card, lvl, fmt, ...) \ diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c index bd6c77777d..4be05471a9 100644 --- a/hw/ccid-card-passthru.c +++ b/hw/ccid-card-passthru.c @@ -8,9 +8,9 @@ * See the COPYING file in the top-level directory. */ -#include "qemu-char.h" -#include "qemu_socket.h" -#include "monitor.h" +#include "char/char.h" +#include "qemu/sockets.h" +#include "monitor/monitor.h" #include "hw/ccid.h" #include "libcacard/vscard_common.h" diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 623dd688d9..80510bc9af 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -27,9 +27,8 @@ * available at http://home.worldonline.dk/~finth/ */ #include "hw.h" -#include "pc.h" -#include "pci.h" -#include "console.h" +#include "pci/pci.h" +#include "ui/console.h" #include "vga_int.h" #include "loader.h" @@ -43,8 +42,6 @@ //#define DEBUG_CIRRUS //#define DEBUG_BITBLT -#define VGA_RAM_SIZE (8192 * 1024) - /*************************************** * * definitions @@ -200,6 +197,7 @@ typedef void (*cirrus_fill_t)(struct CirrusVGAState *s, typedef struct CirrusVGAState { VGACommonState vga; + MemoryRegion cirrus_vga_io; MemoryRegion cirrus_linear_io; MemoryRegion cirrus_linear_bitblt_io; MemoryRegion cirrus_mmio_io; @@ -1953,7 +1951,7 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, ***************************************/ static uint64_t cirrus_vga_mem_read(void *opaque, - target_phys_addr_t addr, + hwaddr addr, uint32_t size) { CirrusVGAState *s = opaque; @@ -1997,7 +1995,7 @@ static uint64_t cirrus_vga_mem_read(void *opaque, } static void cirrus_vga_mem_write(void *opaque, - target_phys_addr_t addr, + hwaddr addr, uint64_t mem_value, uint32_t size) { @@ -2256,7 +2254,7 @@ static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y) * ***************************************/ -static uint64_t cirrus_linear_read(void *opaque, target_phys_addr_t addr, +static uint64_t cirrus_linear_read(void *opaque, hwaddr addr, unsigned size) { CirrusVGAState *s = opaque; @@ -2285,7 +2283,7 @@ static uint64_t cirrus_linear_read(void *opaque, target_phys_addr_t addr, return ret; } -static void cirrus_linear_write(void *opaque, target_phys_addr_t addr, +static void cirrus_linear_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { CirrusVGAState *s = opaque; @@ -2334,7 +2332,7 @@ static void cirrus_linear_write(void *opaque, target_phys_addr_t addr, static uint64_t cirrus_linear_bitblt_read(void *opaque, - target_phys_addr_t addr, + hwaddr addr, unsigned size) { CirrusVGAState *s = opaque; @@ -2347,7 +2345,7 @@ static uint64_t cirrus_linear_bitblt_read(void *opaque, } static void cirrus_linear_bitblt_write(void *opaque, - target_phys_addr_t addr, + hwaddr addr, uint64_t val, unsigned size) { @@ -2435,12 +2433,16 @@ static void cirrus_update_memory_access(CirrusVGAState *s) /* I/O ports */ -static uint32_t cirrus_vga_ioport_read(void *opaque, uint32_t addr) +static uint64_t cirrus_vga_ioport_read(void *opaque, hwaddr addr, + unsigned size) { CirrusVGAState *c = opaque; VGACommonState *s = &c->vga; int val, index; + qemu_flush_coalesced_mmio_buffer(); + addr += 0x3b0; + if (vga_ioport_invalid(s, addr)) { val = 0xff; } else { @@ -2528,12 +2530,16 @@ static uint32_t cirrus_vga_ioport_read(void *opaque, uint32_t addr) return val; } -static void cirrus_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void cirrus_vga_ioport_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) { CirrusVGAState *c = opaque; VGACommonState *s = &c->vga; int index; + qemu_flush_coalesced_mmio_buffer(); + addr += 0x3b0; + /* check port range access depending on color/monochrome mode */ if (vga_ioport_invalid(s, addr)) { return; @@ -2637,7 +2643,7 @@ static void cirrus_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) * ***************************************/ -static uint64_t cirrus_mmio_read(void *opaque, target_phys_addr_t addr, +static uint64_t cirrus_mmio_read(void *opaque, hwaddr addr, unsigned size) { CirrusVGAState *s = opaque; @@ -2645,11 +2651,11 @@ static uint64_t cirrus_mmio_read(void *opaque, target_phys_addr_t addr, if (addr >= 0x100) { return cirrus_mmio_blt_read(s, addr - 0x100); } else { - return cirrus_vga_ioport_read(s, addr + 0x3c0); + return cirrus_vga_ioport_read(s, addr + 0x10, size); } } -static void cirrus_mmio_write(void *opaque, target_phys_addr_t addr, +static void cirrus_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { CirrusVGAState *s = opaque; @@ -2657,7 +2663,7 @@ static void cirrus_mmio_write(void *opaque, target_phys_addr_t addr, if (addr >= 0x100) { cirrus_mmio_blt_write(s, addr - 0x100, val); } else { - cirrus_vga_ioport_write(s, addr + 0x3c0, val); + cirrus_vga_ioport_write(s, addr + 0x10, val, size); } } @@ -2783,8 +2789,19 @@ static const MemoryRegionOps cirrus_linear_io_ops = { }, }; +static const MemoryRegionOps cirrus_vga_io_ops = { + .read = cirrus_vga_ioport_read, + .write = cirrus_vga_ioport_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci, - MemoryRegion *system_memory) + MemoryRegion *system_memory, + MemoryRegion *system_io) { int i; static int inited; @@ -2816,19 +2833,10 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci, s->bustype = CIRRUS_BUSTYPE_ISA; } - register_ioport_write(0x3c0, 16, 1, cirrus_vga_ioport_write, s); - - register_ioport_write(0x3b4, 2, 1, cirrus_vga_ioport_write, s); - register_ioport_write(0x3d4, 2, 1, cirrus_vga_ioport_write, s); - register_ioport_write(0x3ba, 1, 1, cirrus_vga_ioport_write, s); - register_ioport_write(0x3da, 1, 1, cirrus_vga_ioport_write, s); - - register_ioport_read(0x3c0, 16, 1, cirrus_vga_ioport_read, s); - - register_ioport_read(0x3b4, 2, 1, cirrus_vga_ioport_read, s); - register_ioport_read(0x3d4, 2, 1, cirrus_vga_ioport_read, s); - register_ioport_read(0x3ba, 1, 1, cirrus_vga_ioport_read, s); - register_ioport_read(0x3da, 1, 1, cirrus_vga_ioport_read, s); + /* Register ioport 0x3b0 - 0x3df */ + memory_region_init_io(&s->cirrus_vga_io, &cirrus_vga_io_ops, s, + "cirrus-io", 0x30); + memory_region_add_subregion(system_io, 0x3b0, &s->cirrus_vga_io); memory_region_init(&s->low_mem_container, "cirrus-lowmem-container", @@ -2853,7 +2861,9 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci, /* I/O handler for LFB */ memory_region_init_io(&s->cirrus_linear_io, &cirrus_linear_io_ops, s, - "cirrus-linear-io", VGA_RAM_SIZE); + "cirrus-linear-io", s->vga.vram_size_mb + * 1024 * 1024); + memory_region_set_flush_coalesced(&s->cirrus_linear_io); /* I/O handler for LFB */ memory_region_init_io(&s->cirrus_linear_bitblt_io, @@ -2861,10 +2871,12 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci, s, "cirrus-bitblt-mmio", 0x400000); + memory_region_set_flush_coalesced(&s->cirrus_linear_bitblt_io); /* I/O handler for memory-mapped I/O */ memory_region_init_io(&s->cirrus_mmio_io, &cirrus_mmio_io_ops, s, "cirrus-mmio", CIRRUS_PNPMMIO_SIZE); + memory_region_set_flush_coalesced(&s->cirrus_mmio_io); s->real_vram_size = (s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024; @@ -2893,10 +2905,9 @@ static int vga_initfn(ISADevice *dev) ISACirrusVGAState *d = DO_UPCAST(ISACirrusVGAState, dev, dev); VGACommonState *s = &d->cirrus_vga.vga; - s->vram_size_mb = VGA_RAM_SIZE >> 20; vga_common_init(s); cirrus_init_common(&d->cirrus_vga, CIRRUS_ID_CLGD5430, 0, - isa_address_space(dev)); + isa_address_space(dev), isa_address_space_io(dev)); s->ds = graphic_console_init(s->update, s->invalidate, s->screen_dump, s->text_update, s); @@ -2906,6 +2917,12 @@ static int vga_initfn(ISADevice *dev) return 0; } +static Property isa_vga_cirrus_properties[] = { + DEFINE_PROP_UINT32("vgamem_mb", struct ISACirrusVGAState, + cirrus_vga.vga.vram_size_mb, 8), + DEFINE_PROP_END_OF_LIST(), +}; + static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data) { ISADeviceClass *k = ISA_DEVICE_CLASS(klass); @@ -2913,6 +2930,7 @@ static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_cirrus_vga; k->init = vga_initfn; + dc->props = isa_vga_cirrus_properties; } static TypeInfo isa_cirrus_vga_info = { @@ -2936,9 +2954,9 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev) int16_t device_id = pc->device_id; /* setup VGA */ - s->vga.vram_size_mb = VGA_RAM_SIZE >> 20; vga_common_init(&s->vga); - cirrus_init_common(s, device_id, 1, pci_address_space(dev)); + cirrus_init_common(s, device_id, 1, pci_address_space(dev), + pci_address_space_io(dev)); s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate, s->vga.screen_dump, s->vga.text_update, &s->vga); @@ -2963,10 +2981,11 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev) return 0; } -DeviceState *pci_cirrus_vga_init(PCIBus *bus) -{ - return &pci_create_simple(bus, -1, "cirrus-vga")->qdev; -} +static Property pci_vga_cirrus_properties[] = { + DEFINE_PROP_UINT32("vgamem_mb", struct PCICirrusVGAState, + cirrus_vga.vga.vram_size_mb, 8), + DEFINE_PROP_END_OF_LIST(), +}; static void cirrus_vga_class_init(ObjectClass *klass, void *data) { @@ -2981,6 +3000,7 @@ static void cirrus_vga_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_DISPLAY_VGA; dc->desc = "Cirrus CLGD 54xx VGA"; dc->vmsd = &vmstate_pci_cirrus_vga; + dc->props = pci_vga_cirrus_properties; } static TypeInfo cirrus_vga_info = { diff --git a/hw/collie.c b/hw/collie.c index 56f89a9f2e..804d61a421 100644 --- a/hw/collie.c +++ b/hw/collie.c @@ -15,19 +15,20 @@ #include "strongarm.h" #include "arm-misc.h" #include "flash.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" static struct arm_boot_info collie_binfo = { .loader_start = SA_SDCS0, .ram_size = 0x20000000, }; -static void collie_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void collie_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; StrongARMState *s; DriveInfo *dinfo; MemoryRegion *sysmem = get_system_memory(); diff --git a/hw/cris-boot.h b/hw/cris-boot.h index 0a2c242411..c4d3fa6f6f 100644 --- a/hw/cris-boot.h +++ b/hw/cris-boot.h @@ -1,3 +1,5 @@ +#ifndef _CRIS_BOOT_H +#define HW_CRIS_BOOT_H 1 struct cris_load_info { @@ -5,7 +7,9 @@ struct cris_load_info const char *cmdline; int image_size; - target_phys_addr_t entry; + hwaddr entry; }; void cris_load_image(CRISCPU *cpu, struct cris_load_info *li); + +#endif diff --git a/hw/cs4231.c b/hw/cs4231.c index cfec1d9cd1..23570d5b41 100644 --- a/hw/cs4231.c +++ b/hw/cs4231.c @@ -55,7 +55,7 @@ static void cs_reset(DeviceState *d) s->dregs[25] = CS_VER; } -static uint64_t cs_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t cs_mem_read(void *opaque, hwaddr addr, unsigned size) { CSState *s = opaque; @@ -82,7 +82,7 @@ static uint64_t cs_mem_read(void *opaque, target_phys_addr_t addr, return ret; } -static void cs_mem_write(void *opaque, target_phys_addr_t addr, +static void cs_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { CSState *s = opaque; diff --git a/hw/cs4231a.c b/hw/cs4231a.c index e07b9d6237..9d528c43b0 100644 --- a/hw/cs4231a.c +++ b/hw/cs4231a.c @@ -26,7 +26,7 @@ #include "audio/audio.h" #include "isa.h" #include "qdev.h" -#include "qemu-timer.h" +#include "qemu/timer.h" /* Missing features: @@ -346,7 +346,7 @@ static void cs_reset_voices (CSState *s, uint32_t val) } } -static uint64_t cs_read (void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t cs_read (void *opaque, hwaddr addr, unsigned size) { CSState *s = opaque; uint32_t saddr, iaddr, ret; @@ -383,7 +383,7 @@ static uint64_t cs_read (void *opaque, target_phys_addr_t addr, unsigned size) return ret; } -static void cs_write (void *opaque, target_phys_addr_t addr, +static void cs_write (void *opaque, hwaddr addr, uint64_t val64, unsigned size) { CSState *s = opaque; @@ -25,8 +25,8 @@ #include "hw.h" #include "ppc_mac.h" #include "adb.h" -#include "qemu-timer.h" -#include "sysemu.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" /* XXX: implement all timer modes */ @@ -252,7 +252,7 @@ static void cuda_timer1(void *opaque) cuda_update_irq(s); } -static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) +static uint32_t cuda_readb(void *opaque, hwaddr addr) { CUDAState *s = opaque; uint32_t val; @@ -325,7 +325,7 @@ static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) return val; } -static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val) { CUDAState *s = opaque; @@ -616,20 +616,20 @@ static void cuda_receive_packet_from_host(CUDAState *s, } } -static void cuda_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +static void cuda_writew (void *opaque, hwaddr addr, uint32_t value) { } -static void cuda_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +static void cuda_writel (void *opaque, hwaddr addr, uint32_t value) { } -static uint32_t cuda_readw (void *opaque, target_phys_addr_t addr) +static uint32_t cuda_readw (void *opaque, hwaddr addr) { return 0; } -static uint32_t cuda_readl (void *opaque, target_phys_addr_t addr) +static uint32_t cuda_readl (void *opaque, hwaddr addr) { return 0; } diff --git a/hw/dataplane/Makefile.objs b/hw/dataplane/Makefile.objs new file mode 100644 index 0000000000..3e47d0537e --- /dev/null +++ b/hw/dataplane/Makefile.objs @@ -0,0 +1 @@ +obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o vring.o event-poll.o ioq.o virtio-blk.o diff --git a/hw/dataplane/event-poll.c b/hw/dataplane/event-poll.c new file mode 100644 index 0000000000..2b55c6e255 --- /dev/null +++ b/hw/dataplane/event-poll.c @@ -0,0 +1,100 @@ +/* + * Event loop with file descriptor polling + * + * Copyright 2012 IBM, Corp. + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi <stefanha@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include <sys/epoll.h> +#include "hw/dataplane/event-poll.h" + +/* Add an event notifier and its callback for polling */ +void event_poll_add(EventPoll *poll, EventHandler *handler, + EventNotifier *notifier, EventCallback *callback) +{ + struct epoll_event event = { + .events = EPOLLIN, + .data.ptr = handler, + }; + handler->notifier = notifier; + handler->callback = callback; + if (epoll_ctl(poll->epoll_fd, EPOLL_CTL_ADD, + event_notifier_get_fd(notifier), &event) != 0) { + fprintf(stderr, "failed to add event handler to epoll: %m\n"); + exit(1); + } +} + +/* Event callback for stopping event_poll() */ +static void handle_stop(EventHandler *handler) +{ + /* Do nothing */ +} + +void event_poll_init(EventPoll *poll) +{ + /* Create epoll file descriptor */ + poll->epoll_fd = epoll_create1(EPOLL_CLOEXEC); + if (poll->epoll_fd < 0) { + fprintf(stderr, "epoll_create1 failed: %m\n"); + exit(1); + } + + /* Set up stop notifier */ + if (event_notifier_init(&poll->stop_notifier, 0) < 0) { + fprintf(stderr, "failed to init stop notifier\n"); + exit(1); + } + event_poll_add(poll, &poll->stop_handler, + &poll->stop_notifier, handle_stop); +} + +void event_poll_cleanup(EventPoll *poll) +{ + event_notifier_cleanup(&poll->stop_notifier); + close(poll->epoll_fd); + poll->epoll_fd = -1; +} + +/* Block until the next event and invoke its callback */ +void event_poll(EventPoll *poll) +{ + EventHandler *handler; + struct epoll_event event; + int nevents; + + /* Wait for the next event. Only do one event per call to keep the + * function simple, this could be changed later. */ + do { + nevents = epoll_wait(poll->epoll_fd, &event, 1, -1); + } while (nevents < 0 && errno == EINTR); + if (unlikely(nevents != 1)) { + fprintf(stderr, "epoll_wait failed: %m\n"); + exit(1); /* should never happen */ + } + + /* Find out which event handler has become active */ + handler = event.data.ptr; + + /* Clear the eventfd */ + event_notifier_test_and_clear(handler->notifier); + + /* Handle the event */ + handler->callback(handler); +} + +/* Stop event_poll() + * + * This function can be used from another thread. + */ +void event_poll_notify(EventPoll *poll) +{ + event_notifier_set(&poll->stop_notifier); +} diff --git a/hw/dataplane/event-poll.h b/hw/dataplane/event-poll.h new file mode 100644 index 0000000000..3e8d3ec7d5 --- /dev/null +++ b/hw/dataplane/event-poll.h @@ -0,0 +1,40 @@ +/* + * Event loop with file descriptor polling + * + * Copyright 2012 IBM, Corp. + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi <stefanha@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef EVENT_POLL_H +#define EVENT_POLL_H + +#include "qemu/event_notifier.h" + +typedef struct EventHandler EventHandler; +typedef void EventCallback(EventHandler *handler); +struct EventHandler { + EventNotifier *notifier; /* eventfd */ + EventCallback *callback; /* callback function */ +}; + +typedef struct { + int epoll_fd; /* epoll(2) file descriptor */ + EventNotifier stop_notifier; /* stop poll notifier */ + EventHandler stop_handler; /* stop poll handler */ +} EventPoll; + +void event_poll_add(EventPoll *poll, EventHandler *handler, + EventNotifier *notifier, EventCallback *callback); +void event_poll_init(EventPoll *poll); +void event_poll_cleanup(EventPoll *poll); +void event_poll(EventPoll *poll); +void event_poll_notify(EventPoll *poll); + +#endif /* EVENT_POLL_H */ diff --git a/hw/dataplane/hostmem.c b/hw/dataplane/hostmem.c new file mode 100644 index 0000000000..380537e06d --- /dev/null +++ b/hw/dataplane/hostmem.c @@ -0,0 +1,176 @@ +/* + * Thread-safe guest to host memory mapping + * + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi <stefanha@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "exec/address-spaces.h" +#include "hostmem.h" + +static int hostmem_lookup_cmp(const void *phys_, const void *region_) +{ + hwaddr phys = *(const hwaddr *)phys_; + const HostMemRegion *region = region_; + + if (phys < region->guest_addr) { + return -1; + } else if (phys >= region->guest_addr + region->size) { + return 1; + } else { + return 0; + } +} + +/** + * Map guest physical address to host pointer + */ +void *hostmem_lookup(HostMem *hostmem, hwaddr phys, hwaddr len, bool is_write) +{ + HostMemRegion *region; + void *host_addr = NULL; + hwaddr offset_within_region; + + qemu_mutex_lock(&hostmem->current_regions_lock); + region = bsearch(&phys, hostmem->current_regions, + hostmem->num_current_regions, + sizeof(hostmem->current_regions[0]), + hostmem_lookup_cmp); + if (!region) { + goto out; + } + if (is_write && region->readonly) { + goto out; + } + offset_within_region = phys - region->guest_addr; + if (len <= region->size - offset_within_region) { + host_addr = region->host_addr + offset_within_region; + } +out: + qemu_mutex_unlock(&hostmem->current_regions_lock); + + return host_addr; +} + +/** + * Install new regions list + */ +static void hostmem_listener_commit(MemoryListener *listener) +{ + HostMem *hostmem = container_of(listener, HostMem, listener); + + qemu_mutex_lock(&hostmem->current_regions_lock); + g_free(hostmem->current_regions); + hostmem->current_regions = hostmem->new_regions; + hostmem->num_current_regions = hostmem->num_new_regions; + qemu_mutex_unlock(&hostmem->current_regions_lock); + + /* Reset new regions list */ + hostmem->new_regions = NULL; + hostmem->num_new_regions = 0; +} + +/** + * Add a MemoryRegionSection to the new regions list + */ +static void hostmem_append_new_region(HostMem *hostmem, + MemoryRegionSection *section) +{ + void *ram_ptr = memory_region_get_ram_ptr(section->mr); + size_t num = hostmem->num_new_regions; + size_t new_size = (num + 1) * sizeof(hostmem->new_regions[0]); + + hostmem->new_regions = g_realloc(hostmem->new_regions, new_size); + hostmem->new_regions[num] = (HostMemRegion){ + .host_addr = ram_ptr + section->offset_within_region, + .guest_addr = section->offset_within_address_space, + .size = section->size, + .readonly = section->readonly, + }; + hostmem->num_new_regions++; +} + +static void hostmem_listener_append_region(MemoryListener *listener, + MemoryRegionSection *section) +{ + HostMem *hostmem = container_of(listener, HostMem, listener); + + /* Ignore non-RAM regions, we may not be able to map them */ + if (!memory_region_is_ram(section->mr)) { + return; + } + + /* Ignore regions with dirty logging, we cannot mark them dirty */ + if (memory_region_is_logging(section->mr)) { + return; + } + + hostmem_append_new_region(hostmem, section); +} + +/* We don't implement most MemoryListener callbacks, use these nop stubs */ +static void hostmem_listener_dummy(MemoryListener *listener) +{ +} + +static void hostmem_listener_section_dummy(MemoryListener *listener, + MemoryRegionSection *section) +{ +} + +static void hostmem_listener_eventfd_dummy(MemoryListener *listener, + MemoryRegionSection *section, + bool match_data, uint64_t data, + EventNotifier *e) +{ +} + +static void hostmem_listener_coalesced_mmio_dummy(MemoryListener *listener, + MemoryRegionSection *section, + hwaddr addr, hwaddr len) +{ +} + +void hostmem_init(HostMem *hostmem) +{ + memset(hostmem, 0, sizeof(*hostmem)); + + qemu_mutex_init(&hostmem->current_regions_lock); + + hostmem->listener = (MemoryListener){ + .begin = hostmem_listener_dummy, + .commit = hostmem_listener_commit, + .region_add = hostmem_listener_append_region, + .region_del = hostmem_listener_section_dummy, + .region_nop = hostmem_listener_append_region, + .log_start = hostmem_listener_section_dummy, + .log_stop = hostmem_listener_section_dummy, + .log_sync = hostmem_listener_section_dummy, + .log_global_start = hostmem_listener_dummy, + .log_global_stop = hostmem_listener_dummy, + .eventfd_add = hostmem_listener_eventfd_dummy, + .eventfd_del = hostmem_listener_eventfd_dummy, + .coalesced_mmio_add = hostmem_listener_coalesced_mmio_dummy, + .coalesced_mmio_del = hostmem_listener_coalesced_mmio_dummy, + .priority = 10, + }; + + memory_listener_register(&hostmem->listener, &address_space_memory); + if (hostmem->num_new_regions > 0) { + hostmem_listener_commit(&hostmem->listener); + } +} + +void hostmem_finalize(HostMem *hostmem) +{ + memory_listener_unregister(&hostmem->listener); + g_free(hostmem->new_regions); + g_free(hostmem->current_regions); + qemu_mutex_destroy(&hostmem->current_regions_lock); +} diff --git a/hw/dataplane/hostmem.h b/hw/dataplane/hostmem.h new file mode 100644 index 0000000000..b2cf09333f --- /dev/null +++ b/hw/dataplane/hostmem.h @@ -0,0 +1,57 @@ +/* + * Thread-safe guest to host memory mapping + * + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi <stefanha@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef HOSTMEM_H +#define HOSTMEM_H + +#include "exec/memory.h" +#include "qemu/thread.h" + +typedef struct { + void *host_addr; + hwaddr guest_addr; + uint64_t size; + bool readonly; +} HostMemRegion; + +typedef struct { + /* The listener is invoked when regions change and a new list of regions is + * built up completely before they are installed. + */ + MemoryListener listener; + HostMemRegion *new_regions; + size_t num_new_regions; + + /* Current regions are accessed from multiple threads either to lookup + * addresses or to install a new list of regions. The lock protects the + * pointer and the regions. + */ + QemuMutex current_regions_lock; + HostMemRegion *current_regions; + size_t num_current_regions; +} HostMem; + +void hostmem_init(HostMem *hostmem); +void hostmem_finalize(HostMem *hostmem); + +/** + * Map a guest physical address to a pointer + * + * Note that there is map/unmap mechanism here. The caller must ensure that + * mapped memory is no longer used across events like hot memory unplug. This + * can be done with other mechanisms like bdrv_drain_all() that quiesce + * in-flight I/O. + */ +void *hostmem_lookup(HostMem *hostmem, hwaddr phys, hwaddr len, bool is_write); + +#endif /* HOSTMEM_H */ diff --git a/hw/dataplane/ioq.c b/hw/dataplane/ioq.c new file mode 100644 index 0000000000..0c9f5c4d60 --- /dev/null +++ b/hw/dataplane/ioq.c @@ -0,0 +1,117 @@ +/* + * Linux AIO request queue + * + * Copyright 2012 IBM, Corp. + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi <stefanha@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "hw/dataplane/ioq.h" + +void ioq_init(IOQueue *ioq, int fd, unsigned int max_reqs) +{ + int rc; + + ioq->fd = fd; + ioq->max_reqs = max_reqs; + + memset(&ioq->io_ctx, 0, sizeof ioq->io_ctx); + rc = io_setup(max_reqs, &ioq->io_ctx); + if (rc != 0) { + fprintf(stderr, "ioq io_setup failed %d\n", rc); + exit(1); + } + + rc = event_notifier_init(&ioq->io_notifier, 0); + if (rc != 0) { + fprintf(stderr, "ioq io event notifier creation failed %d\n", rc); + exit(1); + } + + ioq->freelist = g_malloc0(sizeof ioq->freelist[0] * max_reqs); + ioq->freelist_idx = 0; + + ioq->queue = g_malloc0(sizeof ioq->queue[0] * max_reqs); + ioq->queue_idx = 0; +} + +void ioq_cleanup(IOQueue *ioq) +{ + g_free(ioq->freelist); + g_free(ioq->queue); + + event_notifier_cleanup(&ioq->io_notifier); + io_destroy(ioq->io_ctx); +} + +EventNotifier *ioq_get_notifier(IOQueue *ioq) +{ + return &ioq->io_notifier; +} + +struct iocb *ioq_get_iocb(IOQueue *ioq) +{ + /* Underflow cannot happen since ioq is sized for max_reqs */ + assert(ioq->freelist_idx != 0); + + struct iocb *iocb = ioq->freelist[--ioq->freelist_idx]; + ioq->queue[ioq->queue_idx++] = iocb; + return iocb; +} + +void ioq_put_iocb(IOQueue *ioq, struct iocb *iocb) +{ + /* Overflow cannot happen since ioq is sized for max_reqs */ + assert(ioq->freelist_idx != ioq->max_reqs); + + ioq->freelist[ioq->freelist_idx++] = iocb; +} + +struct iocb *ioq_rdwr(IOQueue *ioq, bool read, struct iovec *iov, + unsigned int count, long long offset) +{ + struct iocb *iocb = ioq_get_iocb(ioq); + + if (read) { + io_prep_preadv(iocb, ioq->fd, iov, count, offset); + } else { + io_prep_pwritev(iocb, ioq->fd, iov, count, offset); + } + io_set_eventfd(iocb, event_notifier_get_fd(&ioq->io_notifier)); + return iocb; +} + +int ioq_submit(IOQueue *ioq) +{ + int rc = io_submit(ioq->io_ctx, ioq->queue_idx, ioq->queue); + ioq->queue_idx = 0; /* reset */ + return rc; +} + +int ioq_run_completion(IOQueue *ioq, IOQueueCompletion *completion, + void *opaque) +{ + struct io_event events[ioq->max_reqs]; + int nevents, i; + + do { + nevents = io_getevents(ioq->io_ctx, 0, ioq->max_reqs, events, NULL); + } while (nevents < 0 && errno == EINTR); + if (nevents < 0) { + return nevents; + } + + for (i = 0; i < nevents; i++) { + ssize_t ret = ((uint64_t)events[i].res2 << 32) | events[i].res; + + completion(events[i].obj, ret, opaque); + ioq_put_iocb(ioq, events[i].obj); + } + return nevents; +} diff --git a/hw/dataplane/ioq.h b/hw/dataplane/ioq.h new file mode 100644 index 0000000000..b49b5de7f4 --- /dev/null +++ b/hw/dataplane/ioq.h @@ -0,0 +1,57 @@ +/* + * Linux AIO request queue + * + * Copyright 2012 IBM, Corp. + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi <stefanha@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef IOQ_H +#define IOQ_H + +#include <libaio.h> +#include "qemu/event_notifier.h" + +typedef struct { + int fd; /* file descriptor */ + unsigned int max_reqs; /* max length of freelist and queue */ + + io_context_t io_ctx; /* Linux AIO context */ + EventNotifier io_notifier; /* Linux AIO eventfd */ + + /* Requests can complete in any order so a free list is necessary to manage + * available iocbs. + */ + struct iocb **freelist; /* free iocbs */ + unsigned int freelist_idx; + + /* Multiple requests are queued up before submitting them all in one go */ + struct iocb **queue; /* queued iocbs */ + unsigned int queue_idx; +} IOQueue; + +void ioq_init(IOQueue *ioq, int fd, unsigned int max_reqs); +void ioq_cleanup(IOQueue *ioq); +EventNotifier *ioq_get_notifier(IOQueue *ioq); +struct iocb *ioq_get_iocb(IOQueue *ioq); +void ioq_put_iocb(IOQueue *ioq, struct iocb *iocb); +struct iocb *ioq_rdwr(IOQueue *ioq, bool read, struct iovec *iov, + unsigned int count, long long offset); +int ioq_submit(IOQueue *ioq); + +static inline unsigned int ioq_num_queued(IOQueue *ioq) +{ + return ioq->queue_idx; +} + +typedef void IOQueueCompletion(struct iocb *iocb, ssize_t ret, void *opaque); +int ioq_run_completion(IOQueue *ioq, IOQueueCompletion *completion, + void *opaque); + +#endif /* IOQ_H */ diff --git a/hw/dataplane/virtio-blk.c b/hw/dataplane/virtio-blk.c new file mode 100644 index 0000000000..4c4ad8422a --- /dev/null +++ b/hw/dataplane/virtio-blk.c @@ -0,0 +1,465 @@ +/* + * Dedicated thread for virtio-blk I/O processing + * + * Copyright 2012 IBM, Corp. + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi <stefanha@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "trace.h" +#include "qemu/iov.h" +#include "event-poll.h" +#include "qemu/thread.h" +#include "vring.h" +#include "ioq.h" +#include "migration/migration.h" +#include "hw/virtio-blk.h" +#include "hw/dataplane/virtio-blk.h" + +enum { + SEG_MAX = 126, /* maximum number of I/O segments */ + VRING_MAX = SEG_MAX + 2, /* maximum number of vring descriptors */ + REQ_MAX = VRING_MAX, /* maximum number of requests in the vring, + * is VRING_MAX / 2 with traditional and + * VRING_MAX with indirect descriptors */ +}; + +typedef struct { + struct iocb iocb; /* Linux AIO control block */ + QEMUIOVector *inhdr; /* iovecs for virtio_blk_inhdr */ + unsigned int head; /* vring descriptor index */ +} VirtIOBlockRequest; + +struct VirtIOBlockDataPlane { + bool started; + QEMUBH *start_bh; + QemuThread thread; + + VirtIOBlkConf *blk; + int fd; /* image file descriptor */ + + VirtIODevice *vdev; + Vring vring; /* virtqueue vring */ + EventNotifier *guest_notifier; /* irq */ + + EventPoll event_poll; /* event poller */ + EventHandler io_handler; /* Linux AIO completion handler */ + EventHandler notify_handler; /* virtqueue notify handler */ + + IOQueue ioqueue; /* Linux AIO queue (should really be per + dataplane thread) */ + VirtIOBlockRequest requests[REQ_MAX]; /* pool of requests, managed by the + queue */ + + unsigned int num_reqs; + + Error *migration_blocker; +}; + +/* Raise an interrupt to signal guest, if necessary */ +static void notify_guest(VirtIOBlockDataPlane *s) +{ + if (!vring_should_notify(s->vdev, &s->vring)) { + return; + } + + event_notifier_set(s->guest_notifier); +} + +static void complete_request(struct iocb *iocb, ssize_t ret, void *opaque) +{ + VirtIOBlockDataPlane *s = opaque; + VirtIOBlockRequest *req = container_of(iocb, VirtIOBlockRequest, iocb); + struct virtio_blk_inhdr hdr; + int len; + + if (likely(ret >= 0)) { + hdr.status = VIRTIO_BLK_S_OK; + len = ret; + } else { + hdr.status = VIRTIO_BLK_S_IOERR; + len = 0; + } + + trace_virtio_blk_data_plane_complete_request(s, req->head, ret); + + qemu_iovec_from_buf(req->inhdr, 0, &hdr, sizeof(hdr)); + qemu_iovec_destroy(req->inhdr); + g_slice_free(QEMUIOVector, req->inhdr); + + /* According to the virtio specification len should be the number of bytes + * written to, but for virtio-blk it seems to be the number of bytes + * transferred plus the status bytes. + */ + vring_push(&s->vring, req->head, len + sizeof(hdr)); + + s->num_reqs--; +} + +static void complete_request_early(VirtIOBlockDataPlane *s, unsigned int head, + QEMUIOVector *inhdr, unsigned char status) +{ + struct virtio_blk_inhdr hdr = { + .status = status, + }; + + qemu_iovec_from_buf(inhdr, 0, &hdr, sizeof(hdr)); + qemu_iovec_destroy(inhdr); + g_slice_free(QEMUIOVector, inhdr); + + vring_push(&s->vring, head, sizeof(hdr)); + notify_guest(s); +} + +/* Get disk serial number */ +static void do_get_id_cmd(VirtIOBlockDataPlane *s, + struct iovec *iov, unsigned int iov_cnt, + unsigned int head, QEMUIOVector *inhdr) +{ + char id[VIRTIO_BLK_ID_BYTES]; + + /* Serial number not NUL-terminated when shorter than buffer */ + strncpy(id, s->blk->serial ? s->blk->serial : "", sizeof(id)); + iov_from_buf(iov, iov_cnt, 0, id, sizeof(id)); + complete_request_early(s, head, inhdr, VIRTIO_BLK_S_OK); +} + +static int process_request(IOQueue *ioq, struct iovec iov[], + unsigned int out_num, unsigned int in_num, + unsigned int head) +{ + VirtIOBlockDataPlane *s = container_of(ioq, VirtIOBlockDataPlane, ioqueue); + struct iovec *in_iov = &iov[out_num]; + struct virtio_blk_outhdr outhdr; + QEMUIOVector *inhdr; + size_t in_size; + struct iocb *iocb; + + /* Copy in outhdr */ + if (unlikely(iov_to_buf(iov, out_num, 0, &outhdr, + sizeof(outhdr)) != sizeof(outhdr))) { + error_report("virtio-blk request outhdr too short"); + return -EFAULT; + } + iov_discard_front(&iov, &out_num, sizeof(outhdr)); + + /* Grab inhdr for later */ + in_size = iov_size(in_iov, in_num); + if (in_size < sizeof(struct virtio_blk_inhdr)) { + error_report("virtio_blk request inhdr too short"); + return -EFAULT; + } + inhdr = g_slice_new(QEMUIOVector); + qemu_iovec_init(inhdr, 1); + qemu_iovec_concat_iov(inhdr, in_iov, in_num, + in_size - sizeof(struct virtio_blk_inhdr), + sizeof(struct virtio_blk_inhdr)); + iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr)); + + /* TODO Linux sets the barrier bit even when not advertised! */ + outhdr.type &= ~VIRTIO_BLK_T_BARRIER; + + switch (outhdr.type) { + case VIRTIO_BLK_T_IN: + iocb = ioq_rdwr(ioq, true, in_iov, in_num, outhdr.sector * 512); + break; + + case VIRTIO_BLK_T_OUT: + iocb = ioq_rdwr(ioq, false, iov, out_num, outhdr.sector * 512); + break; + + case VIRTIO_BLK_T_SCSI_CMD: + /* TODO support SCSI commands */ + complete_request_early(s, head, inhdr, VIRTIO_BLK_S_UNSUPP); + return 0; + + case VIRTIO_BLK_T_FLUSH: + /* TODO fdsync not supported by Linux AIO, do it synchronously here! */ + if (qemu_fdatasync(s->fd) < 0) { + complete_request_early(s, head, inhdr, VIRTIO_BLK_S_IOERR); + } else { + complete_request_early(s, head, inhdr, VIRTIO_BLK_S_OK); + } + return 0; + + case VIRTIO_BLK_T_GET_ID: + do_get_id_cmd(s, in_iov, in_num, head, inhdr); + return 0; + + default: + error_report("virtio-blk unsupported request type %#x", outhdr.type); + qemu_iovec_destroy(inhdr); + g_slice_free(QEMUIOVector, inhdr); + return -EFAULT; + } + + /* Fill in virtio block metadata needed for completion */ + VirtIOBlockRequest *req = container_of(iocb, VirtIOBlockRequest, iocb); + req->head = head; + req->inhdr = inhdr; + return 0; +} + +static void handle_notify(EventHandler *handler) +{ + VirtIOBlockDataPlane *s = container_of(handler, VirtIOBlockDataPlane, + notify_handler); + + /* There is one array of iovecs into which all new requests are extracted + * from the vring. Requests are read from the vring and the translated + * descriptors are written to the iovecs array. The iovecs do not have to + * persist across handle_notify() calls because the kernel copies the + * iovecs on io_submit(). + * + * Handling io_submit() EAGAIN may require storing the requests across + * handle_notify() calls until the kernel has sufficient resources to + * accept more I/O. This is not implemented yet. + */ + struct iovec iovec[VRING_MAX]; + struct iovec *end = &iovec[VRING_MAX]; + struct iovec *iov = iovec; + + /* When a request is read from the vring, the index of the first descriptor + * (aka head) is returned so that the completed request can be pushed onto + * the vring later. + * + * The number of hypervisor read-only iovecs is out_num. The number of + * hypervisor write-only iovecs is in_num. + */ + int head; + unsigned int out_num = 0, in_num = 0; + unsigned int num_queued; + + for (;;) { + /* Disable guest->host notifies to avoid unnecessary vmexits */ + vring_disable_notification(s->vdev, &s->vring); + + for (;;) { + head = vring_pop(s->vdev, &s->vring, iov, end, &out_num, &in_num); + if (head < 0) { + break; /* no more requests */ + } + + trace_virtio_blk_data_plane_process_request(s, out_num, in_num, + head); + + if (process_request(&s->ioqueue, iov, out_num, in_num, head) < 0) { + vring_set_broken(&s->vring); + break; + } + iov += out_num + in_num; + } + + if (likely(head == -EAGAIN)) { /* vring emptied */ + /* Re-enable guest->host notifies and stop processing the vring. + * But if the guest has snuck in more descriptors, keep processing. + */ + if (vring_enable_notification(s->vdev, &s->vring)) { + break; + } + } else { /* head == -ENOBUFS or fatal error, iovecs[] is depleted */ + /* Since there are no iovecs[] left, stop processing for now. Do + * not re-enable guest->host notifies since the I/O completion + * handler knows to check for more vring descriptors anyway. + */ + break; + } + } + + num_queued = ioq_num_queued(&s->ioqueue); + if (num_queued > 0) { + s->num_reqs += num_queued; + + int rc = ioq_submit(&s->ioqueue); + if (unlikely(rc < 0)) { + fprintf(stderr, "ioq_submit failed %d\n", rc); + exit(1); + } + } +} + +static void handle_io(EventHandler *handler) +{ + VirtIOBlockDataPlane *s = container_of(handler, VirtIOBlockDataPlane, + io_handler); + + if (ioq_run_completion(&s->ioqueue, complete_request, s) > 0) { + notify_guest(s); + } + + /* If there were more requests than iovecs, the vring will not be empty yet + * so check again. There should now be enough resources to process more + * requests. + */ + if (unlikely(vring_more_avail(&s->vring))) { + handle_notify(&s->notify_handler); + } +} + +static void *data_plane_thread(void *opaque) +{ + VirtIOBlockDataPlane *s = opaque; + + do { + event_poll(&s->event_poll); + } while (s->started || s->num_reqs > 0); + return NULL; +} + +static void start_data_plane_bh(void *opaque) +{ + VirtIOBlockDataPlane *s = opaque; + + qemu_bh_delete(s->start_bh); + s->start_bh = NULL; + qemu_thread_create(&s->thread, data_plane_thread, + s, QEMU_THREAD_JOINABLE); +} + +bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, + VirtIOBlockDataPlane **dataplane) +{ + VirtIOBlockDataPlane *s; + int fd; + + *dataplane = NULL; + + if (!blk->data_plane) { + return true; + } + + if (blk->scsi) { + error_report("device is incompatible with x-data-plane, use scsi=off"); + return false; + } + + if (blk->config_wce) { + error_report("device is incompatible with x-data-plane, " + "use config-wce=off"); + return false; + } + + fd = raw_get_aio_fd(blk->conf.bs); + if (fd < 0) { + error_report("drive is incompatible with x-data-plane, " + "use format=raw,cache=none,aio=native"); + return false; + } + + s = g_new0(VirtIOBlockDataPlane, 1); + s->vdev = vdev; + s->fd = fd; + s->blk = blk; + + /* Prevent block operations that conflict with data plane thread */ + bdrv_set_in_use(blk->conf.bs, 1); + + error_setg(&s->migration_blocker, + "x-data-plane does not support migration"); + migrate_add_blocker(s->migration_blocker); + + *dataplane = s; + return true; +} + +void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s) +{ + if (!s) { + return; + } + + virtio_blk_data_plane_stop(s); + migrate_del_blocker(s->migration_blocker); + error_free(s->migration_blocker); + bdrv_set_in_use(s->blk->conf.bs, 0); + g_free(s); +} + +void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) +{ + VirtQueue *vq; + int i; + + if (s->started) { + return; + } + + vq = virtio_get_queue(s->vdev, 0); + if (!vring_setup(&s->vring, s->vdev, 0)) { + return; + } + + event_poll_init(&s->event_poll); + + /* Set up guest notifier (irq) */ + if (s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, + true) != 0) { + fprintf(stderr, "virtio-blk failed to set guest notifier, " + "ensure -enable-kvm is set\n"); + exit(1); + } + s->guest_notifier = virtio_queue_get_guest_notifier(vq); + + /* Set up virtqueue notify */ + if (s->vdev->binding->set_host_notifier(s->vdev->binding_opaque, + 0, true) != 0) { + fprintf(stderr, "virtio-blk failed to set host notifier\n"); + exit(1); + } + event_poll_add(&s->event_poll, &s->notify_handler, + virtio_queue_get_host_notifier(vq), + handle_notify); + + /* Set up ioqueue */ + ioq_init(&s->ioqueue, s->fd, REQ_MAX); + for (i = 0; i < ARRAY_SIZE(s->requests); i++) { + ioq_put_iocb(&s->ioqueue, &s->requests[i].iocb); + } + event_poll_add(&s->event_poll, &s->io_handler, + ioq_get_notifier(&s->ioqueue), handle_io); + + s->started = true; + trace_virtio_blk_data_plane_start(s); + + /* Kick right away to begin processing requests already in vring */ + event_notifier_set(virtio_queue_get_host_notifier(vq)); + + /* Spawn thread in BH so it inherits iothread cpusets */ + s->start_bh = qemu_bh_new(start_data_plane_bh, s); + qemu_bh_schedule(s->start_bh); +} + +void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) +{ + if (!s->started) { + return; + } + s->started = false; + trace_virtio_blk_data_plane_stop(s); + + /* Stop thread or cancel pending thread creation BH */ + if (s->start_bh) { + qemu_bh_delete(s->start_bh); + s->start_bh = NULL; + } else { + event_poll_notify(&s->event_poll); + qemu_thread_join(&s->thread); + } + + ioq_cleanup(&s->ioqueue); + + s->vdev->binding->set_host_notifier(s->vdev->binding_opaque, 0, false); + + event_poll_cleanup(&s->event_poll); + + /* Clean up guest notifier (irq) */ + s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, false); + + vring_teardown(&s->vring); +} diff --git a/hw/dataplane/virtio-blk.h b/hw/dataplane/virtio-blk.h new file mode 100644 index 0000000000..1e8fdfe418 --- /dev/null +++ b/hw/dataplane/virtio-blk.h @@ -0,0 +1,29 @@ +/* + * Dedicated thread for virtio-blk I/O processing + * + * Copyright 2012 IBM, Corp. + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi <stefanha@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef HW_DATAPLANE_VIRTIO_BLK_H +#define HW_DATAPLANE_VIRTIO_BLK_H + +#include "hw/virtio.h" + +typedef struct VirtIOBlockDataPlane VirtIOBlockDataPlane; + +bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, + VirtIOBlockDataPlane **dataplane); +void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s); +void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s); +void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s); +void virtio_blk_data_plane_drain(VirtIOBlockDataPlane *s); + +#endif /* HW_DATAPLANE_VIRTIO_BLK_H */ diff --git a/hw/dataplane/vring.c b/hw/dataplane/vring.c new file mode 100644 index 0000000000..d5d4ef45d1 --- /dev/null +++ b/hw/dataplane/vring.c @@ -0,0 +1,362 @@ +/* Copyright 2012 Red Hat, Inc. + * Copyright IBM, Corp. 2012 + * + * Based on Linux 2.6.39 vhost code: + * Copyright (C) 2009 Red Hat, Inc. + * Copyright (C) 2006 Rusty Russell IBM Corporation + * + * Author: Michael S. Tsirkin <mst@redhat.com> + * Stefan Hajnoczi <stefanha@redhat.com> + * + * Inspiration, some code, and most witty comments come from + * Documentation/virtual/lguest/lguest.c, by Rusty Russell + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ + +#include "trace.h" +#include "hw/dataplane/vring.h" + +/* Map the guest's vring to host memory */ +bool vring_setup(Vring *vring, VirtIODevice *vdev, int n) +{ + hwaddr vring_addr = virtio_queue_get_ring_addr(vdev, n); + hwaddr vring_size = virtio_queue_get_ring_size(vdev, n); + void *vring_ptr; + + vring->broken = false; + + hostmem_init(&vring->hostmem); + vring_ptr = hostmem_lookup(&vring->hostmem, vring_addr, vring_size, true); + if (!vring_ptr) { + error_report("Failed to map vring " + "addr %#" HWADDR_PRIx " size %" HWADDR_PRIu, + vring_addr, vring_size); + vring->broken = true; + return false; + } + + vring_init(&vring->vr, virtio_queue_get_num(vdev, n), vring_ptr, 4096); + + vring->last_avail_idx = 0; + vring->last_used_idx = 0; + vring->signalled_used = 0; + vring->signalled_used_valid = false; + + trace_vring_setup(virtio_queue_get_ring_addr(vdev, n), + vring->vr.desc, vring->vr.avail, vring->vr.used); + return true; +} + +void vring_teardown(Vring *vring) +{ + hostmem_finalize(&vring->hostmem); +} + +/* Disable guest->host notifies */ +void vring_disable_notification(VirtIODevice *vdev, Vring *vring) +{ + if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX))) { + vring->vr.used->flags |= VRING_USED_F_NO_NOTIFY; + } +} + +/* Enable guest->host notifies + * + * Return true if the vring is empty, false if there are more requests. + */ +bool vring_enable_notification(VirtIODevice *vdev, Vring *vring) +{ + if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) { + vring_avail_event(&vring->vr) = vring->vr.avail->idx; + } else { + vring->vr.used->flags &= ~VRING_USED_F_NO_NOTIFY; + } + smp_mb(); /* ensure update is seen before reading avail_idx */ + return !vring_more_avail(vring); +} + +/* This is stolen from linux/drivers/vhost/vhost.c:vhost_notify() */ +bool vring_should_notify(VirtIODevice *vdev, Vring *vring) +{ + uint16_t old, new; + bool v; + /* Flush out used index updates. This is paired + * with the barrier that the Guest executes when enabling + * interrupts. */ + smp_mb(); + + if ((vdev->guest_features & VIRTIO_F_NOTIFY_ON_EMPTY) && + unlikely(vring->vr.avail->idx == vring->last_avail_idx)) { + return true; + } + + if (!(vdev->guest_features & VIRTIO_RING_F_EVENT_IDX)) { + return !(vring->vr.avail->flags & VRING_AVAIL_F_NO_INTERRUPT); + } + old = vring->signalled_used; + v = vring->signalled_used_valid; + new = vring->signalled_used = vring->last_used_idx; + vring->signalled_used_valid = true; + + if (unlikely(!v)) { + return true; + } + + return vring_need_event(vring_used_event(&vring->vr), new, old); +} + +/* This is stolen from linux/drivers/vhost/vhost.c. */ +static int get_indirect(Vring *vring, + struct iovec iov[], struct iovec *iov_end, + unsigned int *out_num, unsigned int *in_num, + struct vring_desc *indirect) +{ + struct vring_desc desc; + unsigned int i = 0, count, found = 0; + + /* Sanity check */ + if (unlikely(indirect->len % sizeof(desc))) { + error_report("Invalid length in indirect descriptor: " + "len %#x not multiple of %#zx", + indirect->len, sizeof(desc)); + vring->broken = true; + return -EFAULT; + } + + count = indirect->len / sizeof(desc); + /* Buffers are chained via a 16 bit next field, so + * we can have at most 2^16 of these. */ + if (unlikely(count > USHRT_MAX + 1)) { + error_report("Indirect buffer length too big: %d", indirect->len); + vring->broken = true; + return -EFAULT; + } + + do { + struct vring_desc *desc_ptr; + + /* Translate indirect descriptor */ + desc_ptr = hostmem_lookup(&vring->hostmem, + indirect->addr + found * sizeof(desc), + sizeof(desc), false); + if (!desc_ptr) { + error_report("Failed to map indirect descriptor " + "addr %#" PRIx64 " len %zu", + (uint64_t)indirect->addr + found * sizeof(desc), + sizeof(desc)); + vring->broken = true; + return -EFAULT; + } + desc = *desc_ptr; + + /* Ensure descriptor has been loaded before accessing fields */ + barrier(); /* read_barrier_depends(); */ + + if (unlikely(++found > count)) { + error_report("Loop detected: last one at %u " + "indirect size %u", i, count); + vring->broken = true; + return -EFAULT; + } + + if (unlikely(desc.flags & VRING_DESC_F_INDIRECT)) { + error_report("Nested indirect descriptor"); + vring->broken = true; + return -EFAULT; + } + + /* Stop for now if there are not enough iovecs available. */ + if (iov >= iov_end) { + return -ENOBUFS; + } + + iov->iov_base = hostmem_lookup(&vring->hostmem, desc.addr, desc.len, + desc.flags & VRING_DESC_F_WRITE); + if (!iov->iov_base) { + error_report("Failed to map indirect descriptor" + "addr %#" PRIx64 " len %u", + (uint64_t)desc.addr, desc.len); + vring->broken = true; + return -EFAULT; + } + iov->iov_len = desc.len; + iov++; + + /* If this is an input descriptor, increment that count. */ + if (desc.flags & VRING_DESC_F_WRITE) { + *in_num += 1; + } else { + /* If it's an output descriptor, they're all supposed + * to come before any input descriptors. */ + if (unlikely(*in_num)) { + error_report("Indirect descriptor " + "has out after in: idx %u", i); + vring->broken = true; + return -EFAULT; + } + *out_num += 1; + } + i = desc.next; + } while (desc.flags & VRING_DESC_F_NEXT); + return 0; +} + +/* This looks in the virtqueue and for the first available buffer, and converts + * it to an iovec for convenient access. Since descriptors consist of some + * number of output then some number of input descriptors, it's actually two + * iovecs, but we pack them into one and note how many of each there were. + * + * This function returns the descriptor number found, or vq->num (which is + * never a valid descriptor number) if none was found. A negative code is + * returned on error. + * + * Stolen from linux/drivers/vhost/vhost.c. + */ +int vring_pop(VirtIODevice *vdev, Vring *vring, + struct iovec iov[], struct iovec *iov_end, + unsigned int *out_num, unsigned int *in_num) +{ + struct vring_desc desc; + unsigned int i, head, found = 0, num = vring->vr.num; + uint16_t avail_idx, last_avail_idx; + + /* If there was a fatal error then refuse operation */ + if (vring->broken) { + return -EFAULT; + } + + /* Check it isn't doing very strange things with descriptor numbers. */ + last_avail_idx = vring->last_avail_idx; + avail_idx = vring->vr.avail->idx; + barrier(); /* load indices now and not again later */ + + if (unlikely((uint16_t)(avail_idx - last_avail_idx) > num)) { + error_report("Guest moved used index from %u to %u", + last_avail_idx, avail_idx); + vring->broken = true; + return -EFAULT; + } + + /* If there's nothing new since last we looked. */ + if (avail_idx == last_avail_idx) { + return -EAGAIN; + } + + /* Only get avail ring entries after they have been exposed by guest. */ + smp_rmb(); + + /* Grab the next descriptor number they're advertising, and increment + * the index we've seen. */ + head = vring->vr.avail->ring[last_avail_idx % num]; + + /* If their number is silly, that's an error. */ + if (unlikely(head >= num)) { + error_report("Guest says index %u > %u is available", head, num); + vring->broken = true; + return -EFAULT; + } + + if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) { + vring_avail_event(&vring->vr) = vring->vr.avail->idx; + } + + /* When we start there are none of either input nor output. */ + *out_num = *in_num = 0; + + i = head; + do { + if (unlikely(i >= num)) { + error_report("Desc index is %u > %u, head = %u", i, num, head); + vring->broken = true; + return -EFAULT; + } + if (unlikely(++found > num)) { + error_report("Loop detected: last one at %u vq size %u head %u", + i, num, head); + vring->broken = true; + return -EFAULT; + } + desc = vring->vr.desc[i]; + + /* Ensure descriptor is loaded before accessing fields */ + barrier(); + + if (desc.flags & VRING_DESC_F_INDIRECT) { + int ret = get_indirect(vring, iov, iov_end, out_num, in_num, &desc); + if (ret < 0) { + return ret; + } + continue; + } + + /* If there are not enough iovecs left, stop for now. The caller + * should check if there are more descs available once they have dealt + * with the current set. + */ + if (iov >= iov_end) { + return -ENOBUFS; + } + + /* TODO handle non-contiguous memory across region boundaries */ + iov->iov_base = hostmem_lookup(&vring->hostmem, desc.addr, desc.len, + desc.flags & VRING_DESC_F_WRITE); + if (!iov->iov_base) { + error_report("Failed to map vring desc addr %#" PRIx64 " len %u", + (uint64_t)desc.addr, desc.len); + vring->broken = true; + return -EFAULT; + } + iov->iov_len = desc.len; + iov++; + + if (desc.flags & VRING_DESC_F_WRITE) { + /* If this is an input descriptor, + * increment that count. */ + *in_num += 1; + } else { + /* If it's an output descriptor, they're all supposed + * to come before any input descriptors. */ + if (unlikely(*in_num)) { + error_report("Descriptor has out after in: idx %d", i); + vring->broken = true; + return -EFAULT; + } + *out_num += 1; + } + i = desc.next; + } while (desc.flags & VRING_DESC_F_NEXT); + + /* On success, increment avail index. */ + vring->last_avail_idx++; + return head; +} + +/* After we've used one of their buffers, we tell them about it. + * + * Stolen from linux/drivers/vhost/vhost.c. + */ +void vring_push(Vring *vring, unsigned int head, int len) +{ + struct vring_used_elem *used; + uint16_t new; + + /* Don't touch vring if a fatal error occurred */ + if (vring->broken) { + return; + } + + /* The virtqueue contains a ring of used buffers. Get a pointer to the + * next entry in that used ring. */ + used = &vring->vr.used->ring[vring->last_used_idx % vring->vr.num]; + used->id = head; + used->len = len; + + /* Make sure buffer is written before we update index. */ + smp_wmb(); + + new = vring->vr.used->idx = ++vring->last_used_idx; + if (unlikely((int16_t)(new - vring->signalled_used) < (uint16_t)1)) { + vring->signalled_used_valid = false; + } +} diff --git a/hw/dataplane/vring.h b/hw/dataplane/vring.h new file mode 100644 index 0000000000..3274f623f5 --- /dev/null +++ b/hw/dataplane/vring.h @@ -0,0 +1,62 @@ +/* Copyright 2012 Red Hat, Inc. and/or its affiliates + * Copyright IBM, Corp. 2012 + * + * Based on Linux 2.6.39 vhost code: + * Copyright (C) 2009 Red Hat, Inc. + * Copyright (C) 2006 Rusty Russell IBM Corporation + * + * Author: Michael S. Tsirkin <mst@redhat.com> + * Stefan Hajnoczi <stefanha@redhat.com> + * + * Inspiration, some code, and most witty comments come from + * Documentation/virtual/lguest/lguest.c, by Rusty Russell + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ + +#ifndef VRING_H +#define VRING_H + +#include <linux/virtio_ring.h> +#include "qemu-common.h" +#include "hw/dataplane/hostmem.h" +#include "hw/virtio.h" + +typedef struct { + HostMem hostmem; /* guest memory mapper */ + struct vring vr; /* virtqueue vring mapped to host memory */ + uint16_t last_avail_idx; /* last processed avail ring index */ + uint16_t last_used_idx; /* last processed used ring index */ + uint16_t signalled_used; /* EVENT_IDX state */ + bool signalled_used_valid; + bool broken; /* was there a fatal error? */ +} Vring; + +static inline unsigned int vring_get_num(Vring *vring) +{ + return vring->vr.num; +} + +/* Are there more descriptors available? */ +static inline bool vring_more_avail(Vring *vring) +{ + return vring->vr.avail->idx != vring->last_avail_idx; +} + +/* Fail future vring_pop() and vring_push() calls until reset */ +static inline void vring_set_broken(Vring *vring) +{ + vring->broken = true; +} + +bool vring_setup(Vring *vring, VirtIODevice *vdev, int n); +void vring_teardown(Vring *vring); +void vring_disable_notification(VirtIODevice *vdev, Vring *vring); +bool vring_enable_notification(VirtIODevice *vdev, Vring *vring); +bool vring_should_notify(VirtIODevice *vdev, Vring *vring); +int vring_pop(VirtIODevice *vdev, Vring *vring, + struct iovec iov[], struct iovec *iov_end, + unsigned int *out_num, unsigned int *in_num); +void vring_push(Vring *vring, unsigned int head, int len); + +#endif /* VRING_H */ diff --git a/hw/debugcon.c b/hw/debugcon.c index 14ab326be3..e8a855e33a 100644 --- a/hw/debugcon.c +++ b/hw/debugcon.c @@ -25,24 +25,31 @@ */ #include "hw.h" -#include "qemu-char.h" +#include "char/char.h" #include "isa.h" #include "pc.h" +#define TYPE_ISA_DEBUGCON_DEVICE "isa-debugcon" +#define ISA_DEBUGCON_DEVICE(obj) \ + OBJECT_CHECK(ISADebugconState, (obj), TYPE_ISA_DEBUGCON_DEVICE) + //#define DEBUG_DEBUGCON typedef struct DebugconState { + MemoryRegion io; CharDriverState *chr; uint32_t readback; } DebugconState; typedef struct ISADebugconState { - ISADevice dev; + ISADevice parent_obj; + uint32_t iobase; DebugconState state; } ISADebugconState; -static void debugcon_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val, + unsigned width) { DebugconState *s = opaque; unsigned char ch = val; @@ -55,7 +62,7 @@ static void debugcon_ioport_write(void *opaque, uint32_t addr, uint32_t val) } -static uint32_t debugcon_ioport_read(void *opaque, uint32_t addr) +static uint64_t debugcon_ioport_read(void *opaque, hwaddr addr, unsigned width) { DebugconState *s = opaque; @@ -66,6 +73,14 @@ static uint32_t debugcon_ioport_read(void *opaque, uint32_t addr) return s->readback; } +static const MemoryRegionOps debugcon_ops = { + .read = debugcon_ioport_read, + .write = debugcon_ioport_write, + .valid.min_access_size = 1, + .valid.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + static void debugcon_init_core(DebugconState *s) { if (!s->chr) { @@ -78,12 +93,14 @@ static void debugcon_init_core(DebugconState *s) static int debugcon_isa_initfn(ISADevice *dev) { - ISADebugconState *isa = DO_UPCAST(ISADebugconState, dev, dev); + ISADebugconState *isa = ISA_DEBUGCON_DEVICE(dev); DebugconState *s = &isa->state; debugcon_init_core(s); - register_ioport_write(isa->iobase, 1, 1, debugcon_ioport_write, s); - register_ioport_read(isa->iobase, 1, 1, debugcon_ioport_read, s); + memory_region_init_io(&s->io, &debugcon_ops, s, + TYPE_ISA_DEBUGCON_DEVICE, 1); + memory_region_add_subregion(isa_address_space_io(dev), + isa->iobase, &s->io); return 0; } @@ -103,7 +120,7 @@ static void debugcon_isa_class_initfn(ObjectClass *klass, void *data) } static TypeInfo debugcon_isa_info = { - .name = "isa-debugcon", + .name = TYPE_ISA_DEBUGCON_DEVICE, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISADebugconState), .class_init = debugcon_isa_class_initfn, diff --git a/hw/debugexit.c b/hw/debugexit.c new file mode 100644 index 0000000000..90642eb37f --- /dev/null +++ b/hw/debugexit.c @@ -0,0 +1,75 @@ +/* + * debug exit port emulation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + */ + +#include "hw.h" +#include "isa.h" + +#define TYPE_ISA_DEBUG_EXIT_DEVICE "isa-debug-exit" +#define ISA_DEBUG_EXIT_DEVICE(obj) \ + OBJECT_CHECK(ISADebugExitState, (obj), TYPE_ISA_DEBUG_EXIT_DEVICE) + +typedef struct ISADebugExitState { + ISADevice parent_obj; + + uint32_t iobase; + uint32_t iosize; + MemoryRegion io; +} ISADebugExitState; + +static void debug_exit_write(void *opaque, hwaddr addr, uint64_t val, + unsigned width) +{ + exit((val << 1) | 1); +} + +static const MemoryRegionOps debug_exit_ops = { + .write = debug_exit_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static int debug_exit_initfn(ISADevice *dev) +{ + ISADebugExitState *isa = ISA_DEBUG_EXIT_DEVICE(dev); + + memory_region_init_io(&isa->io, &debug_exit_ops, isa, + TYPE_ISA_DEBUG_EXIT_DEVICE, isa->iosize); + memory_region_add_subregion(isa_address_space_io(dev), + isa->iobase, &isa->io); + return 0; +} + +static Property debug_exit_properties[] = { + DEFINE_PROP_HEX32("iobase", ISADebugExitState, iobase, 0x501), + DEFINE_PROP_HEX32("iosize", ISADebugExitState, iosize, 0x02), + DEFINE_PROP_END_OF_LIST(), +}; + +static void debug_exit_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = debug_exit_initfn; + dc->props = debug_exit_properties; +} + +static TypeInfo debug_exit_info = { + .name = TYPE_ISA_DEBUG_EXIT_DEVICE, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISADebugExitState), + .class_init = debug_exit_class_initfn, +}; + +static void debug_exit_register_types(void) +{ + type_register_static(&debug_exit_info); +} + +type_init(debug_exit_register_types) diff --git a/hw/dec_pci.c b/hw/dec_pci.c index 37337bf4b6..ee3f4ca834 100644 --- a/hw/dec_pci.c +++ b/hw/dec_pci.c @@ -25,10 +25,10 @@ #include "dec_pci.h" #include "sysbus.h" -#include "pci.h" -#include "pci_host.h" -#include "pci_bridge.h" -#include "pci_internals.h" +#include "pci/pci.h" +#include "pci/pci_host.h" +#include "pci/pci_bridge.h" +#include "pci/pci_bus.h" /* debug DEC */ //#define DEBUG_DEC @@ -40,9 +40,10 @@ #define DEC_DPRINTF(fmt, ...) #endif +#define DEC_21154(obj) OBJECT_CHECK(DECState, (obj), TYPE_DEC_21154) + typedef struct DECState { - SysBusDevice busdev; - PCIHostState host_state; + PCIHostState parent_obj; } DECState; static int dec_map_irq(PCIDevice *pci_dev, int irq_num) @@ -66,7 +67,7 @@ static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pci_device; } -static TypeInfo dec_21154_pci_bridge_info = { +static const TypeInfo dec_21154_pci_bridge_info = { .name = "dec-21154-p2p-bridge", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIBridge), @@ -88,16 +89,16 @@ PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn) static int pci_dec_21154_device_init(SysBusDevice *dev) { - DECState *s; + PCIHostState *phb; - s = FROM_SYSBUS(DECState, dev); + phb = PCI_HOST_BRIDGE(dev); - memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops, - &s->host_state, "pci-conf-idx", 0x1000); - memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops, - &s->host_state, "pci-data-idx", 0x1000); - sysbus_init_mmio(dev, &s->host_state.conf_mem); - sysbus_init_mmio(dev, &s->host_state.data_mem); + memory_region_init_io(&phb->conf_mem, &pci_host_conf_le_ops, + dev, "pci-conf-idx", 0x1000); + memory_region_init_io(&phb->data_mem, &pci_host_data_le_ops, + dev, "pci-data-idx", 0x1000); + sysbus_init_mmio(dev, &phb->conf_mem); + sysbus_init_mmio(dev, &phb->data_mem); return 0; } @@ -119,7 +120,7 @@ static void dec_21154_pci_host_class_init(ObjectClass *klass, void *data) k->is_bridge = 1; } -static TypeInfo dec_21154_pci_host_info = { +static const TypeInfo dec_21154_pci_host_info = { .name = "dec-21154", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), @@ -133,9 +134,9 @@ static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data) sdc->init = pci_dec_21154_device_init; } -static TypeInfo pci_dec_21154_device_info = { - .name = "dec-21154-sysbus", - .parent = TYPE_SYS_BUS_DEVICE, +static const TypeInfo pci_dec_21154_device_info = { + .name = TYPE_DEC_21154, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(DECState), .class_init = pci_dec_21154_device_class_init, }; diff --git a/hw/dec_pci.h b/hw/dec_pci.h index 79264bac84..17dc0c2b0a 100644 --- a/hw/dec_pci.h +++ b/hw/dec_pci.h @@ -3,6 +3,8 @@ #include "qemu-common.h" +#define TYPE_DEC_21154 "dec-21154-sysbus" + PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn); #endif diff --git a/hw/device-hotplug.c b/hw/device-hotplug.c index 2bdc615b49..88da145a89 100644 --- a/hw/device-hotplug.c +++ b/hw/device-hotplug.c @@ -24,11 +24,10 @@ #include "hw.h" #include "boards.h" -#include "net.h" -#include "blockdev.h" -#include "qemu-config.h" -#include "sysemu.h" -#include "monitor.h" +#include "sysemu/blockdev.h" +#include "qemu/config-file.h" +#include "sysemu/sysemu.h" +#include "monitor/monitor.h" DriveInfo *add_init_drive(const char *optstr) { @@ -39,7 +38,7 @@ DriveInfo *add_init_drive(const char *optstr) if (!opts) return NULL; - dinfo = drive_init(opts, current_machine->use_scsi); + dinfo = drive_init(opts, current_machine->block_default_type); if (!dinfo) { qemu_opts_del(opts); return NULL; @@ -49,18 +48,16 @@ DriveInfo *add_init_drive(const char *optstr) } #if !defined(TARGET_I386) -int pci_drive_hot_add(Monitor *mon, const QDict *qdict, - DriveInfo *dinfo, int type) +int pci_drive_hot_add(Monitor *mon, const QDict *qdict, DriveInfo *dinfo) { /* On non-x86 we don't do PCI hotplug */ - monitor_printf(mon, "Can't hot-add drive to type %d\n", type); + monitor_printf(mon, "Can't hot-add drive to type %d\n", dinfo->type); return -1; } #endif void drive_hot_add(Monitor *mon, const QDict *qdict) { - int type; DriveInfo *dinfo = NULL; const char *opts = qdict_get_str(qdict, "opts"); @@ -72,14 +69,13 @@ void drive_hot_add(Monitor *mon, const QDict *qdict) monitor_printf(mon, "Parameter addr not supported\n"); goto err; } - type = dinfo->type; - switch (type) { + switch (dinfo->type) { case IF_NONE: monitor_printf(mon, "OK\n"); break; default: - if (pci_drive_hot_add(mon, qdict, dinfo, type)) { + if (pci_drive_hot_add(mon, qdict, dinfo)) { goto err; } } @@ -89,5 +85,4 @@ err: if (dinfo) { drive_put_ref(dinfo); } - return; } diff --git a/hw/devices.h b/hw/devices.h index 1a55c1e905..c60bcabae3 100644 --- a/hw/devices.h +++ b/hw/devices.h @@ -1,6 +1,8 @@ #ifndef QEMU_DEVICES_H #define QEMU_DEVICES_H +#include "hw/irq.h" + /* ??? Not all users of this file can include cpu-common.h. */ struct MemoryRegion; @@ -23,6 +23,7 @@ */ #include "hw.h" #include "isa.h" +#include "qemu/main-loop.h" /* #define DEBUG_DMA */ @@ -58,6 +59,8 @@ static struct dma_cont { int dshift; struct dma_regs regs[4]; qemu_irq *cpu_request_exit; + MemoryRegion channel_io; + MemoryRegion cont_io; } dma_controllers[2]; enum { @@ -149,7 +152,7 @@ static inline int getff (struct dma_cont *d) return ff; } -static uint32_t read_chan (void *opaque, uint32_t nport) +static uint64_t read_chan(void *opaque, hwaddr nport, unsigned size) { struct dma_cont *d = opaque; int ichan, nreg, iport, ff, val, dir; @@ -171,7 +174,8 @@ static uint32_t read_chan (void *opaque, uint32_t nport) return (val >> (d->dshift + (ff << 3))) & 0xff; } -static void write_chan (void *opaque, uint32_t nport, uint32_t data) +static void write_chan(void *opaque, hwaddr nport, uint64_t data, + unsigned size) { struct dma_cont *d = opaque; int iport, ichan, nreg; @@ -189,22 +193,23 @@ static void write_chan (void *opaque, uint32_t nport, uint32_t data) } } -static void write_cont (void *opaque, uint32_t nport, uint32_t data) +static void write_cont(void *opaque, hwaddr nport, uint64_t data, + unsigned size) { struct dma_cont *d = opaque; int iport, ichan = 0; iport = (nport >> d->dshift) & 0x0f; switch (iport) { - case 0x08: /* command */ + case 0x01: /* command */ if ((data != 0) && (data & CMD_NOT_SUPPORTED)) { - dolog ("command %#x not supported\n", data); + dolog("command %"PRIx64" not supported\n", data); return; } d->command = data; break; - case 0x09: + case 0x02: ichan = data & 3; if (data & 4) { d->status |= 1 << (ichan + 4); @@ -216,7 +221,7 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) DMA_run(); break; - case 0x0a: /* single mask */ + case 0x03: /* single mask */ if (data & 4) d->mask |= 1 << (data & 3); else @@ -224,7 +229,7 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) DMA_run(); break; - case 0x0b: /* mode */ + case 0x04: /* mode */ { ichan = data & 3; #ifdef DEBUG_DMA @@ -243,23 +248,23 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) break; } - case 0x0c: /* clear flip flop */ + case 0x05: /* clear flip flop */ d->flip_flop = 0; break; - case 0x0d: /* reset */ + case 0x06: /* reset */ d->flip_flop = 0; d->mask = ~0; d->status = 0; d->command = 0; break; - case 0x0e: /* clear mask for all channels */ + case 0x07: /* clear mask for all channels */ d->mask = 0; DMA_run(); break; - case 0x0f: /* write mask for all channels */ + case 0x08: /* write mask for all channels */ d->mask = data; DMA_run(); break; @@ -277,7 +282,7 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) #endif } -static uint32_t read_cont (void *opaque, uint32_t nport) +static uint64_t read_cont(void *opaque, hwaddr nport, unsigned size) { struct dma_cont *d = opaque; int iport, val; @@ -411,7 +416,7 @@ void DMA_register_channel (int nchan, int DMA_read_memory (int nchan, void *buf, int pos, int len) { struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3]; - target_phys_addr_t addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR]; + hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR]; if (r->mode & 0x20) { int i; @@ -433,7 +438,7 @@ int DMA_read_memory (int nchan, void *buf, int pos, int len) int DMA_write_memory (int nchan, void *buf, int pos, int len) { struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3]; - target_phys_addr_t addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR]; + hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR]; if (r->mode & 0x20) { int i; @@ -463,7 +468,7 @@ void DMA_schedule(int nchan) static void dma_reset(void *opaque) { struct dma_cont *d = opaque; - write_cont (d, (0x0d << d->dshift), 0); + write_cont(d, (0x06 << d->dshift), 0, 1); } static int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len) @@ -473,38 +478,68 @@ static int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len) return dma_pos; } + +static const MemoryRegionOps channel_io_ops = { + .read = read_chan, + .write = write_chan, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +/* IOport from page_base */ +static const MemoryRegionPortio page_portio_list[] = { + { 0x01, 3, 1, .write = write_page, .read = read_page, }, + { 0x07, 1, 1, .write = write_page, .read = read_page, }, + PORTIO_END_OF_LIST(), +}; + +/* IOport from pageh_base */ +static const MemoryRegionPortio pageh_portio_list[] = { + { 0x01, 3, 1, .write = write_pageh, .read = read_pageh, }, + { 0x07, 3, 1, .write = write_pageh, .read = read_pageh, }, + PORTIO_END_OF_LIST(), +}; + +static const MemoryRegionOps cont_io_ops = { + .read = read_cont, + .write = write_cont, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + /* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */ static void dma_init2(struct dma_cont *d, int base, int dshift, int page_base, int pageh_base, qemu_irq *cpu_request_exit) { - static const int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 }; int i; d->dshift = dshift; d->cpu_request_exit = cpu_request_exit; - for (i = 0; i < 8; i++) { - register_ioport_write (base + (i << dshift), 1, 1, write_chan, d); - register_ioport_read (base + (i << dshift), 1, 1, read_chan, d); - } - for (i = 0; i < ARRAY_SIZE (page_port_list); i++) { - register_ioport_write (page_base + page_port_list[i], 1, 1, - write_page, d); - register_ioport_read (page_base + page_port_list[i], 1, 1, - read_page, d); - if (pageh_base >= 0) { - register_ioport_write (pageh_base + page_port_list[i], 1, 1, - write_pageh, d); - register_ioport_read (pageh_base + page_port_list[i], 1, 1, - read_pageh, d); - } - } - for (i = 0; i < 8; i++) { - register_ioport_write (base + ((i + 8) << dshift), 1, 1, - write_cont, d); - register_ioport_read (base + ((i + 8) << dshift), 1, 1, - read_cont, d); + + memory_region_init_io(&d->channel_io, &channel_io_ops, d, + "dma-chan", 8 << d->dshift); + memory_region_add_subregion(isa_address_space_io(NULL), + base, &d->channel_io); + + isa_register_portio_list(NULL, page_base, page_portio_list, d, + "dma-page"); + if (pageh_base >= 0) { + isa_register_portio_list(NULL, pageh_base, pageh_portio_list, d, + "dma-pageh"); } + + memory_region_init_io(&d->cont_io, &cont_io_ops, d, "dma-cont", + 8 << d->dshift); + memory_region_add_subregion(isa_address_space_io(NULL), + base + (8 << d->dshift), &d->cont_io); + qemu_register_reset(dma_reset, d); dma_reset(d); for (i = 0; i < ARRAY_SIZE (d->regs); ++i) { diff --git a/hw/dp8393x.c b/hw/dp8393x.c index 4fa6eccba4..b5014501df 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -18,8 +18,8 @@ */ #include "hw.h" -#include "qemu-timer.h" -#include "net.h" +#include "qemu/timer.h" +#include "net/net.h" #include "mips.h" //#define DEBUG_SONIC @@ -168,7 +168,7 @@ typedef struct dp8393xState { int loopback_packet; /* Memory access */ - void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write); + void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write); void* mem_opaque; } dp8393xState; @@ -603,7 +603,7 @@ static void dp8393x_watchdog(void *opaque) dp8393x_update_irq(s); } -static uint32_t dp8393x_readw(void *opaque, target_phys_addr_t addr) +static uint32_t dp8393x_readw(void *opaque, hwaddr addr) { dp8393xState *s = opaque; int reg; @@ -616,13 +616,13 @@ static uint32_t dp8393x_readw(void *opaque, target_phys_addr_t addr) return read_register(s, reg); } -static uint32_t dp8393x_readb(void *opaque, target_phys_addr_t addr) +static uint32_t dp8393x_readb(void *opaque, hwaddr addr) { uint16_t v = dp8393x_readw(opaque, addr & ~0x1); return (v >> (8 * (addr & 0x1))) & 0xff; } -static uint32_t dp8393x_readl(void *opaque, target_phys_addr_t addr) +static uint32_t dp8393x_readl(void *opaque, hwaddr addr) { uint32_t v; v = dp8393x_readw(opaque, addr); @@ -630,7 +630,7 @@ static uint32_t dp8393x_readl(void *opaque, target_phys_addr_t addr) return v; } -static void dp8393x_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +static void dp8393x_writew(void *opaque, hwaddr addr, uint32_t val) { dp8393xState *s = opaque; int reg; @@ -644,7 +644,7 @@ static void dp8393x_writew(void *opaque, target_phys_addr_t addr, uint32_t val) write_register(s, reg, (uint16_t)val); } -static void dp8393x_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void dp8393x_writeb(void *opaque, hwaddr addr, uint32_t val) { uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1); @@ -659,7 +659,7 @@ static void dp8393x_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) dp8393x_writew(opaque, addr & ~0x1, val); } -static void dp8393x_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void dp8393x_writel(void *opaque, hwaddr addr, uint32_t val) { dp8393x_writew(opaque, addr, val & 0xffff); dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff); @@ -879,10 +879,10 @@ static NetClientInfo net_dp83932_info = { .cleanup = nic_cleanup, }; -void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, +void dp83932_init(NICInfo *nd, hwaddr base, int it_shift, MemoryRegion *address_space, qemu_irq irq, void* mem_opaque, - void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write)) + void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write)) { dp8393xState *s; diff --git a/hw/ds1225y.c b/hw/ds1225y.c index 2cd355bd0a..4b3f69bc67 100644 --- a/hw/ds1225y.c +++ b/hw/ds1225y.c @@ -34,7 +34,7 @@ typedef struct { uint8_t *contents; } NvRamState; -static uint64_t nvram_read(void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t nvram_read(void *opaque, hwaddr addr, unsigned size) { NvRamState *s = opaque; uint32_t val; @@ -44,7 +44,7 @@ static uint64_t nvram_read(void *opaque, target_phys_addr_t addr, unsigned size) return val; } -static void nvram_write(void *opaque, target_phys_addr_t addr, uint64_t val, +static void nvram_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { NvRamState *s = opaque; diff --git a/hw/ds1338.c b/hw/ds1338.c index d590d9c007..1aefa3ba04 100644 --- a/hw/ds1338.c +++ b/hw/ds1338.c @@ -12,39 +12,97 @@ #include "i2c.h" +/* Size of NVRAM including both the user-accessible area and the + * secondary register area. + */ +#define NVRAM_SIZE 64 + +/* Flags definitions */ +#define SECONDS_CH 0x80 +#define HOURS_12 0x40 +#define HOURS_PM 0x20 +#define CTRL_OSF 0x20 + typedef struct { I2CSlave i2c; - time_t offset; - struct tm now; - uint8_t nvram[56]; - int ptr; - int addr_byte; + int64_t offset; + uint8_t wday_offset; + uint8_t nvram[NVRAM_SIZE]; + int32_t ptr; + bool addr_byte; } DS1338State; +static const VMStateDescription vmstate_ds1338 = { + .name = "ds1338", + .version_id = 2, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_I2C_SLAVE(i2c, DS1338State), + VMSTATE_INT64(offset, DS1338State), + VMSTATE_UINT8_V(wday_offset, DS1338State, 2), + VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE), + VMSTATE_INT32(ptr, DS1338State), + VMSTATE_BOOL(addr_byte, DS1338State), + VMSTATE_END_OF_LIST() + } +}; + +static void capture_current_time(DS1338State *s) +{ + /* Capture the current time into the secondary registers + * which will be actually read by the data transfer operation. + */ + struct tm now; + qemu_get_timedate(&now, s->offset); + s->nvram[0] = to_bcd(now.tm_sec); + s->nvram[1] = to_bcd(now.tm_min); + if (s->nvram[2] & HOURS_12) { + int tmp = now.tm_hour; + if (tmp == 0) { + tmp = 24; + } + if (tmp <= 12) { + s->nvram[2] = HOURS_12 | to_bcd(tmp); + } else { + s->nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12); + } + } else { + s->nvram[2] = to_bcd(now.tm_hour); + } + s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1; + s->nvram[4] = to_bcd(now.tm_mday); + s->nvram[5] = to_bcd(now.tm_mon + 1); + s->nvram[6] = to_bcd(now.tm_year - 100); +} + +static void inc_regptr(DS1338State *s) +{ + /* The register pointer wraps around after 0x3F; wraparound + * causes the current time/date to be retransferred into + * the secondary registers. + */ + s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1); + if (!s->ptr) { + capture_current_time(s); + } +} + static void ds1338_event(I2CSlave *i2c, enum i2c_event event) { DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c); switch (event) { case I2C_START_RECV: - qemu_get_timedate(&s->now, s->offset); - s->nvram[0] = to_bcd(s->now.tm_sec); - s->nvram[1] = to_bcd(s->now.tm_min); - if (s->nvram[2] & 0x40) { - s->nvram[2] = (to_bcd((s->now.tm_hour % 12)) + 1) | 0x40; - if (s->now.tm_hour >= 12) { - s->nvram[2] |= 0x20; - } - } else { - s->nvram[2] = to_bcd(s->now.tm_hour); - } - s->nvram[3] = to_bcd(s->now.tm_wday) + 1; - s->nvram[4] = to_bcd(s->now.tm_mday); - s->nvram[5] = to_bcd(s->now.tm_mon) + 1; - s->nvram[6] = to_bcd(s->now.tm_year - 100); + /* In h/w, capture happens on any START condition, not just a + * START_RECV, but there is no need to actually capture on + * START_SEND, because the guest can't get at that data + * without going through a START_RECV which would overwrite it. + */ + capture_current_time(s); break; case I2C_START_SEND: - s->addr_byte = 1; + s->addr_byte = true; break; default: break; @@ -57,7 +115,7 @@ static int ds1338_recv(I2CSlave *i2c) uint8_t res; res = s->nvram[s->ptr]; - s->ptr = (s->ptr + 1) & 0xff; + inc_regptr(s); return res; } @@ -65,52 +123,71 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data) { DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c); if (s->addr_byte) { - s->ptr = data; - s->addr_byte = 0; + s->ptr = data & (NVRAM_SIZE - 1); + s->addr_byte = false; return 0; } - s->nvram[s->ptr - 8] = data; - if (data < 8) { - qemu_get_timedate(&s->now, s->offset); - switch(data) { + if (s->ptr < 7) { + /* Time register. */ + struct tm now; + qemu_get_timedate(&now, s->offset); + switch(s->ptr) { case 0: /* TODO: Implement CH (stop) bit. */ - s->now.tm_sec = from_bcd(data & 0x7f); + now.tm_sec = from_bcd(data & 0x7f); break; case 1: - s->now.tm_min = from_bcd(data & 0x7f); + now.tm_min = from_bcd(data & 0x7f); break; case 2: - if (data & 0x40) { - if (data & 0x20) { - data = from_bcd(data & 0x4f) + 11; - } else { - data = from_bcd(data & 0x1f) - 1; + if (data & HOURS_12) { + int tmp = from_bcd(data & (HOURS_PM - 1)); + if (data & HOURS_PM) { + tmp += 12; } + if (tmp == 24) { + tmp = 0; + } + now.tm_hour = tmp; } else { - data = from_bcd(data); + now.tm_hour = from_bcd(data & (HOURS_12 - 1)); } - s->now.tm_hour = data; break; case 3: - s->now.tm_wday = from_bcd(data & 7) - 1; + { + /* The day field is supposed to contain a value in + the range 1-7. Otherwise behavior is undefined. + */ + int user_wday = (data & 7) - 1; + s->wday_offset = (user_wday - now.tm_wday + 7) % 7; + } break; case 4: - s->now.tm_mday = from_bcd(data & 0x3f); + now.tm_mday = from_bcd(data & 0x3f); break; case 5: - s->now.tm_mon = from_bcd(data & 0x1f) - 1; + now.tm_mon = from_bcd(data & 0x1f) - 1; break; case 6: - s->now.tm_year = from_bcd(data) + 100; - break; - case 7: - /* Control register. Currently ignored. */ + now.tm_year = from_bcd(data) + 100; break; } - s->offset = qemu_timedate_diff(&s->now); + s->offset = qemu_timedate_diff(&now); + } else if (s->ptr == 7) { + /* Control register. */ + + /* Ensure bits 2, 3 and 6 will read back as zero. */ + data &= 0xB3; + + /* Attempting to write the OSF flag to logic 1 leaves the + value unchanged. */ + data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF); + + s->nvram[s->ptr] = data; + } else { + s->nvram[s->ptr] = data; } - s->ptr = (s->ptr + 1) & 0xff; + inc_regptr(s); return 0; } @@ -119,14 +196,29 @@ static int ds1338_init(I2CSlave *i2c) return 0; } +static void ds1338_reset(DeviceState *dev) +{ + DS1338State *s = FROM_I2C_SLAVE(DS1338State, I2C_SLAVE_FROM_QDEV(dev)); + + /* The clock is running and synchronized with the host */ + s->offset = 0; + s->wday_offset = 0; + memset(s->nvram, 0, NVRAM_SIZE); + s->ptr = 0; + s->addr_byte = false; +} + static void ds1338_class_init(ObjectClass *klass, void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); k->init = ds1338_init; k->event = ds1338_event; k->recv = ds1338_recv; k->send = ds1338_send; + dc->reset = ds1338_reset; + dc->vmsd = &vmstate_ds1338; } static TypeInfo ds1338_info = { diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c index 7cc7a99bfb..7878cc3e15 100644 --- a/hw/dummy_m68k.c +++ b/hw/dummy_m68k.c @@ -10,23 +10,23 @@ #include "boards.h" #include "loader.h" #include "elf.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #define KERNEL_LOAD_ADDR 0x10000 /* Board init. */ -static void dummy_m68k_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void dummy_m68k_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; CPUM68KState *env; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); int kernel_size; uint64_t elf_entry; - target_phys_addr_t entry; + hwaddr entry; if (!cpu_model) cpu_model = "cfv4e"; diff --git a/hw/e1000.c b/hw/e1000.c index ae8a6c5523..0f177ff844 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -26,12 +26,12 @@ #include "hw.h" -#include "pci.h" -#include "net.h" +#include "pci/pci.h" +#include "net/net.h" #include "net/checksum.h" #include "loader.h" -#include "sysemu.h" -#include "dma.h" +#include "sysemu/sysemu.h" +#include "sysemu/dma.h" #include "e1000_hw.h" @@ -59,6 +59,11 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL); #define PNPMMIO_SIZE 0x20000 #define MIN_BUF_SIZE 60 /* Min. octets in an ethernet frame sans FCS */ +/* this is the size past which hardware will drop packets when setting LPE=0 */ +#define MAXIMUM_ETHERNET_VLAN_SIZE 1522 +/* this is the size past which hardware will drop packets when setting LPE=1 */ +#define MAXIMUM_ETHERNET_LPE_SIZE 16384 + /* * HW models: * E1000_DEV_ID_82540EM works with Windows and Linux @@ -92,7 +97,6 @@ typedef struct E1000State_st { uint32_t rxbuf_size; uint32_t rxbuf_min_shift; - int check_rxov; struct e1000_tx { unsigned char header[256]; unsigned char vlan_header[4]; @@ -162,6 +166,11 @@ static void set_phy_ctrl(E1000State *s, int index, uint16_t val) { if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) { + /* no need auto-negotiation if link was down */ + if (s->nic->nc.link_down) { + s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE; + return; + } s->nic->nc.link_down = true; e1000_link_down(s); s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE; @@ -266,6 +275,8 @@ rxbufsize(uint32_t v) static void e1000_reset(void *opaque) { E1000State *d = opaque; + uint8_t *macaddr = d->conf.macaddr.a; + int i; qemu_del_timer(d->autoneg_timer); memset(d->phy_reg, 0, sizeof d->phy_reg); @@ -278,6 +289,14 @@ static void e1000_reset(void *opaque) if (d->nic->nc.link_down) { e1000_link_down(d); } + + /* Some guests expect pre-initialized RAH/RAL (AddrValid flag + MACaddr) */ + d->mac_reg[RA] = 0; + d->mac_reg[RA + 1] = E1000_RAH_AV; + for (i = 0; i < 4; i++) { + d->mac_reg[RA] |= macaddr[i] << (8 * i); + d->mac_reg[RA + 1] |= (i < 2) ? macaddr[i + 4] << (8 * i) : 0; + } } static void @@ -295,6 +314,7 @@ set_rx_control(E1000State *s, int index, uint32_t val) s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1; DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT], s->mac_reg[RCTL]); + qemu_flush_queued_packets(&s->nic->nc); } static void @@ -740,11 +760,11 @@ static bool e1000_has_rxbufs(E1000State *s, size_t total_size) int bufs; /* Fast-path short packets */ if (total_size <= s->rxbuf_size) { - return s->mac_reg[RDH] != s->mac_reg[RDT] || !s->check_rxov; + return s->mac_reg[RDH] != s->mac_reg[RDT]; } if (s->mac_reg[RDH] < s->mac_reg[RDT]) { bufs = s->mac_reg[RDT] - s->mac_reg[RDH]; - } else if (s->mac_reg[RDH] > s->mac_reg[RDT] || !s->check_rxov) { + } else if (s->mac_reg[RDH] > s->mac_reg[RDT]) { bufs = s->mac_reg[RDLEN] / sizeof(struct e1000_rx_desc) + s->mac_reg[RDT] - s->mac_reg[RDH]; } else { @@ -795,6 +815,14 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) size = sizeof(min_buf); } + /* Discard oversized packets if !LPE and !SBP. */ + if ((size > MAXIMUM_ETHERNET_LPE_SIZE || + (size > MAXIMUM_ETHERNET_VLAN_SIZE + && !(s->mac_reg[RCTL] & E1000_RCTL_LPE))) + && !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) { + return size; + } + if (!receive_filter(s, buf, size)) return size; @@ -847,7 +875,6 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN]) s->mac_reg[RDH] = 0; - s->check_rxov = 1; /* see comment in start_xmit; same here */ if (s->mac_reg[RDH] == rdh_start) { DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n", @@ -924,8 +951,10 @@ mac_writereg(E1000State *s, int index, uint32_t val) static void set_rdt(E1000State *s, int index, uint32_t val) { - s->check_rxov = 0; s->mac_reg[index] = val & 0xffff; + if (e1000_has_rxbufs(s, 1)) { + qemu_flush_queued_packets(&s->nic->nc); + } } static void @@ -1007,7 +1036,7 @@ static void (*macreg_writeops[])(E1000State *, int, uint32_t) = { enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) }; static void -e1000_mmio_write(void *opaque, target_phys_addr_t addr, uint64_t val, +e1000_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { E1000State *s = opaque; @@ -1024,7 +1053,7 @@ e1000_mmio_write(void *opaque, target_phys_addr_t addr, uint64_t val, } static uint64_t -e1000_mmio_read(void *opaque, target_phys_addr_t addr, unsigned size) +e1000_mmio_read(void *opaque, hwaddr addr, unsigned size) { E1000State *s = opaque; unsigned int index = (addr & 0x1ffff) >> 2; @@ -1047,7 +1076,7 @@ static const MemoryRegionOps e1000_mmio_ops = { }, }; -static uint64_t e1000_io_read(void *opaque, target_phys_addr_t addr, +static uint64_t e1000_io_read(void *opaque, hwaddr addr, unsigned size) { E1000State *s = opaque; @@ -1056,7 +1085,7 @@ static uint64_t e1000_io_read(void *opaque, target_phys_addr_t addr, return 0; } -static void e1000_io_write(void *opaque, target_phys_addr_t addr, +static void e1000_io_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { E1000State *s = opaque; @@ -1075,11 +1104,23 @@ static bool is_version_1(void *opaque, int version_id) return version_id == 1; } +static int e1000_post_load(void *opaque, int version_id) +{ + E1000State *s = opaque; + + /* nc.link_down can't be migrated, so infer link_down according + * to link status bit in mac_reg[STATUS] */ + s->nic->nc.link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0; + + return 0; +} + static const VMStateDescription vmstate_e1000 = { .name = "e1000", .version_id = 2, .minimum_version_id = 1, .minimum_version_id_old = 1, + .post_load = e1000_post_load, .fields = (VMStateField []) { VMSTATE_PCI_DEVICE(dev, E1000State), VMSTATE_UNUSED_TEST(is_version_1, 4), /* was instance id */ diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c index fe1cd90007..000bd08dee 100644 --- a/hw/eccmemctl.c +++ b/hw/eccmemctl.c @@ -129,7 +129,7 @@ typedef struct ECCState { uint32_t version; } ECCState; -static void ecc_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val, +static void ecc_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { ECCState *s = opaque; @@ -172,7 +172,7 @@ static void ecc_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val, } } -static uint64_t ecc_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t ecc_mem_read(void *opaque, hwaddr addr, unsigned size) { ECCState *s = opaque; @@ -229,7 +229,7 @@ static const MemoryRegionOps ecc_mem_ops = { }, }; -static void ecc_diag_mem_write(void *opaque, target_phys_addr_t addr, +static void ecc_diag_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { ECCState *s = opaque; @@ -238,7 +238,7 @@ static void ecc_diag_mem_write(void *opaque, target_phys_addr_t addr, s->diag[addr & ECC_DIAG_MASK] = val; } -static uint64_t ecc_diag_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t ecc_diag_mem_read(void *opaque, hwaddr addr, unsigned size) { ECCState *s = opaque; diff --git a/hw/eepro100.c b/hw/eepro100.c index 50d117e35e..6bbefb505f 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -42,11 +42,11 @@ #include <stddef.h> /* offsetof */ #include "hw.h" -#include "pci.h" -#include "net.h" +#include "pci/pci.h" +#include "net/net.h" #include "eeprom93xx.h" -#include "sysemu.h" -#include "dma.h" +#include "sysemu/sysemu.h" +#include "sysemu/dma.h" /* QEMU sends frames smaller than 60 bytes to ethernet nics. * Such frames are rejected by real nics and their emulations. @@ -1036,6 +1036,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val) } set_ru_state(s, ru_ready); s->ru_offset = e100_read_reg4(s, SCBPointer); + qemu_flush_queued_packets(&s->nic->nc); TRACE(OTHER, logout("val=0x%02x (rx start)\n", val)); break; case RX_RESUME: @@ -1577,7 +1578,7 @@ static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val) } } -static uint64_t eepro100_read(void *opaque, target_phys_addr_t addr, +static uint64_t eepro100_read(void *opaque, hwaddr addr, unsigned size) { EEPRO100State *s = opaque; @@ -1590,7 +1591,7 @@ static uint64_t eepro100_read(void *opaque, target_phys_addr_t addr, } } -static void eepro100_write(void *opaque, target_phys_addr_t addr, +static void eepro100_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { EEPRO100State *s = opaque; @@ -1770,7 +1771,8 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) if (rfd_command & COMMAND_EL) { /* EL bit is set, so this was the last frame. */ logout("receive: Running out of frames\n"); - set_ru_state(s, ru_suspended); + set_ru_state(s, ru_no_resources); + eepro100_rnr_interrupt(s); } if (rfd_command & COMMAND_S) { /* S bit is set. */ diff --git a/hw/elf_ops.h b/hw/elf_ops.h index fa65ce2f93..531a42553b 100644 --- a/hw/elf_ops.h +++ b/hw/elf_ops.h @@ -62,7 +62,7 @@ static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table, static int glue(symfind, SZ)(const void *s0, const void *s1) { - target_phys_addr_t addr = *(target_phys_addr_t *)s0; + hwaddr addr = *(hwaddr *)s0; struct elf_sym *sym = (struct elf_sym *)s1; int result = 0; if (addr < sym->st_value) { @@ -74,7 +74,7 @@ static int glue(symfind, SZ)(const void *s0, const void *s1) } static const char *glue(lookup_symbol, SZ)(struct syminfo *s, - target_phys_addr_t orig_addr) + hwaddr orig_addr) { struct elf_sym *syms = glue(s->disas_symtab.elf, SZ); struct elf_sym *sym; @@ -269,6 +269,17 @@ static int glue(load_elf, SZ)(const char *name, int fd, addr = ph->p_paddr; } + /* the entry pointer in the ELF header is a virtual + * address, if the text segments paddr and vaddr differ + * we need to adjust the entry */ + if (pentry && !translate_fn && + ph->p_vaddr != ph->p_paddr && + ehdr.e_entry >= ph->p_vaddr && + ehdr.e_entry < ph->p_vaddr + ph->p_filesz && + ph->p_flags & PF_X) { + *pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr; + } + snprintf(label, sizeof(label), "phdr #%d: %s", i, name); rom_add_blob_fixed(label, data, mem_size, addr); diff --git a/hw/empty_slot.c b/hw/empty_slot.c index 099c85e583..23978eb149 100644 --- a/hw/empty_slot.c +++ b/hw/empty_slot.c @@ -28,14 +28,14 @@ typedef struct EmptySlot { uint64_t size; } EmptySlot; -static uint64_t empty_slot_read(void *opaque, target_phys_addr_t addr, +static uint64_t empty_slot_read(void *opaque, hwaddr addr, unsigned size) { DPRINTF("read from " TARGET_FMT_plx "\n", addr); return 0; } -static void empty_slot_write(void *opaque, target_phys_addr_t addr, +static void empty_slot_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { DPRINTF("write 0x%x to " TARGET_FMT_plx "\n", (unsigned)val, addr); @@ -47,7 +47,7 @@ static const MemoryRegionOps empty_slot_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -void empty_slot_init(target_phys_addr_t addr, uint64_t slot_size) +void empty_slot_init(hwaddr addr, uint64_t slot_size) { if (slot_size > 0) { /* Only empty slots larger than 0 byte need handling. */ diff --git a/hw/empty_slot.h b/hw/empty_slot.h index 78dc91de10..6079602cdf 100644 --- a/hw/empty_slot.h +++ b/hw/empty_slot.h @@ -1,2 +1,7 @@ +#ifndef HW_EMPTY_SLOT_H +#define HW_EMPTY_SLOT_H 1 + /* empty_slot.c */ -void empty_slot_init(target_phys_addr_t addr, uint64_t slot_size); +void empty_slot_init(hwaddr addr, uint64_t slot_size); + +#endif diff --git a/hw/es1370.c b/hw/es1370.c index e34234c350..59c3f2329e 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -29,8 +29,8 @@ #include "hw.h" #include "audiodev.h" #include "audio/audio.h" -#include "pci.h" -#include "dma.h" +#include "pci/pci.h" +#include "sysemu/dma.h" /* Missing stuff: SCTRL_P[12](END|ST)INC @@ -908,18 +908,44 @@ static void es1370_adc_callback (void *opaque, int avail) es1370_run_channel (s, ADC_CHANNEL, avail); } -static const MemoryRegionPortio es1370_portio[] = { - { 0, 0x40 * 4, 1, .write = es1370_writeb, }, - { 0, 0x40 * 2, 2, .write = es1370_writew, }, - { 0, 0x40, 4, .write = es1370_writel, }, - { 0, 0x40 * 4, 1, .read = es1370_readb, }, - { 0, 0x40 * 2, 2, .read = es1370_readw, }, - { 0, 0x40, 4, .read = es1370_readl, }, - PORTIO_END_OF_LIST () -}; +static uint64_t es1370_read(void *opaque, hwaddr addr, + unsigned size) +{ + switch (size) { + case 1: + return es1370_readb(opaque, addr); + case 2: + return es1370_readw(opaque, addr); + case 4: + return es1370_readl(opaque, addr); + default: + return -1; + } +} + +static void es1370_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + switch (size) { + case 1: + es1370_writeb(opaque, addr, val); + break; + case 2: + es1370_writew(opaque, addr, val); + break; + case 4: + es1370_writel(opaque, addr, val); + break; + } +} static const MemoryRegionOps es1370_io_ops = { - .old_portio = es1370_portio, + .read = es1370_read, + .write = es1370_write, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, .endianness = DEVICE_LITTLE_ENDIAN, }; @@ -25,8 +25,8 @@ #include "hw.h" #include "sysbus.h" #include "escc.h" -#include "qemu-char.h" -#include "console.h" +#include "char/char.h" +#include "ui/console.h" #include "trace.h" /* @@ -463,7 +463,7 @@ static void escc_update_parameters(ChannelState *s) qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); } -static void escc_mem_write(void *opaque, target_phys_addr_t addr, +static void escc_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { SerialState *serial = opaque; @@ -565,7 +565,7 @@ static void escc_mem_write(void *opaque, target_phys_addr_t addr, } } -static uint64_t escc_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t escc_mem_read(void *opaque, hwaddr addr, unsigned size) { SerialState *serial = opaque; @@ -683,7 +683,7 @@ static const VMStateDescription vmstate_escc = { } }; -MemoryRegion *escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB, +MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB, CharDriverState *chrA, CharDriverState *chrB, int clock, int it_shift) { @@ -846,7 +846,7 @@ static void sunmouse_event(void *opaque, put_queue(s, 0); } -void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq, +void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq, int disabled, int clock, int it_shift) { DeviceState *dev; @@ -1,8 +1,13 @@ +#ifndef HW_ESCC_H +#define HW_ESCC_H 1 + /* escc.c */ #define ESCC_SIZE 4 -MemoryRegion *escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB, +MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB, CharDriverState *chrA, CharDriverState *chrB, int clock, int it_shift); -void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq, +void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq, int disabled, int clock, int it_shift); + +#endif diff --git a/hw/esp-pci.c b/hw/esp-pci.c index 170e007be9..c949e6e0d9 100644 --- a/hw/esp-pci.c +++ b/hw/esp-pci.c @@ -23,11 +23,11 @@ * THE SOFTWARE. */ -#include "pci.h" +#include "pci/pci.h" #include "eeprom93xx.h" #include "esp.h" #include "trace.h" -#include "qemu-log.h" +#include "qemu/log.h" #define TYPE_AM53C974_DEVICE "am53c974" @@ -159,7 +159,7 @@ static uint32_t esp_pci_dma_read(PCIESPState *pci, uint32_t saddr) return val; } -static void esp_pci_io_write(void *opaque, target_phys_addr_t addr, +static void esp_pci_io_write(void *opaque, hwaddr addr, uint64_t val, unsigned int size) { PCIESPState *pci = opaque; @@ -202,7 +202,7 @@ static void esp_pci_io_write(void *opaque, target_phys_addr_t addr, } } -static uint64_t esp_pci_io_read(void *opaque, target_phys_addr_t addr, +static uint64_t esp_pci_io_read(void *opaque, hwaddr addr, unsigned int size) { PCIESPState *pci = opaque; @@ -26,7 +26,7 @@ #include "sysbus.h" #include "esp.h" #include "trace.h" -#include "qemu-log.h" +#include "qemu/log.h" /* * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O), @@ -87,7 +87,9 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf) target = s->wregs[ESP_WBUSID] & BUSID_DID; if (s->dma) { - dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8); + dmalen = s->rregs[ESP_TCLO]; + dmalen |= s->rregs[ESP_TCMID] << 8; + dmalen |= s->rregs[ESP_TCHI] << 16; s->dma_memory_read(s->dma_opaque, buf, dmalen); } else { dmalen = s->ti_size; @@ -226,6 +228,7 @@ static void esp_dma_done(ESPState *s) s->rregs[ESP_RFLAGS] = 0; s->rregs[ESP_TCLO] = 0; s->rregs[ESP_TCMID] = 0; + s->rregs[ESP_TCHI] = 0; esp_raise_irq(s); } @@ -328,7 +331,9 @@ static void handle_ti(ESPState *s) return; } - dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8); + dmalen = s->rregs[ESP_TCLO]; + dmalen |= s->rregs[ESP_TCMID] << 8; + dmalen |= s->rregs[ESP_TCHI] << 16; if (dmalen==0) { dmalen=0x10000; } @@ -429,6 +434,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) switch (saddr) { case ESP_TCLO: case ESP_TCMID: + case ESP_TCHI: s->rregs[ESP_RSTAT] &= ~STAT_TC; break; case ESP_FIFO: @@ -448,6 +454,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) /* Reload DMA counter. */ s->rregs[ESP_TCLO] = s->wregs[ESP_TCLO]; s->rregs[ESP_TCMID] = s->wregs[ESP_TCMID]; + s->rregs[ESP_TCHI] = s->wregs[ESP_TCHI]; } else { s->dma = 0; } @@ -530,13 +537,12 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) case ESP_WBUSID ... ESP_WSYNO: break; case ESP_CFG1: + case ESP_CFG2: case ESP_CFG3: + case ESP_RES3: case ESP_RES4: s->rregs[saddr] = val; break; case ESP_WCCF ... ESP_WTEST: break; - case ESP_CFG2 ... ESP_RES4: - s->rregs[saddr] = val; - break; default: trace_esp_error_invalid_write(val, saddr); return; @@ -544,7 +550,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) s->wregs[saddr] = val; } -static bool esp_mem_accepts(void *opaque, target_phys_addr_t addr, +static bool esp_mem_accepts(void *opaque, hwaddr addr, unsigned size, bool is_write) { return (size == 1) || (is_write && size == 4); @@ -579,7 +585,7 @@ typedef struct { ESPState esp; } SysBusESPState; -static void sysbus_esp_mem_write(void *opaque, target_phys_addr_t addr, +static void sysbus_esp_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned int size) { SysBusESPState *sysbus = opaque; @@ -589,7 +595,7 @@ static void sysbus_esp_mem_write(void *opaque, target_phys_addr_t addr, esp_reg_write(&sysbus->esp, saddr, val); } -static uint64_t sysbus_esp_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t sysbus_esp_mem_read(void *opaque, hwaddr addr, unsigned int size) { SysBusESPState *sysbus = opaque; @@ -606,7 +612,7 @@ static const MemoryRegionOps sysbus_esp_mem_ops = { .valid.accepts = esp_mem_accepts, }; -void esp_init(target_phys_addr_t espaddr, int it_shift, +void esp_init(hwaddr espaddr, int it_shift, ESPDMAMemoryReadWriteFunc dma_memory_read, ESPDMAMemoryReadWriteFunc dma_memory_write, void *dma_opaque, qemu_irq irq, qemu_irq *reset, @@ -6,7 +6,7 @@ /* esp.c */ #define ESP_MAX_DEVS 7 typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len); -void esp_init(target_phys_addr_t espaddr, int it_shift, +void esp_init(hwaddr espaddr, int it_shift, ESPDMAMemoryReadWriteFunc dma_memory_read, ESPDMAMemoryReadWriteFunc dma_memory_write, void *dma_opaque, qemu_irq irq, qemu_irq *reset, diff --git a/hw/etraxfs.h b/hw/etraxfs.h index c62f94b7b7..cc1d7a17a0 100644 --- a/hw/etraxfs.h +++ b/hw/etraxfs.h @@ -22,14 +22,17 @@ * THE SOFTWARE. */ -#include "net.h" +#ifndef HW_EXTRAXFS_H +#define HW_EXTRAXFS_H 1 + +#include "net/net.h" #include "etraxfs_dma.h" qemu_irq *cris_pic_init_cpu(CPUCRISState *env); /* Instantiate an ETRAXFS Ethernet MAC. */ static inline DeviceState * -etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr, +etraxfs_eth_init(NICInfo *nd, hwaddr base, int phyaddr, void *dma_out, void *dma_in) { DeviceState *dev; @@ -44,3 +47,5 @@ etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr, sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); return dev; } + +#endif diff --git a/hw/etraxfs_dma.c b/hw/etraxfs_dma.c index 332525cab1..d41500316f 100644 --- a/hw/etraxfs_dma.c +++ b/hw/etraxfs_dma.c @@ -24,9 +24,9 @@ #include <stdio.h> #include <sys/time.h> #include "hw.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #include "qemu-common.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "etraxfs_dma.h" @@ -212,7 +212,7 @@ static inline int channel_en(struct fs_dma_ctrl *ctrl, int c) && ctrl->channels[c].client; } -static inline int fs_channel(target_phys_addr_t addr) +static inline int fs_channel(hwaddr addr) { /* Every channel has a 0x2000 ctrl register map. */ return addr >> 13; @@ -221,7 +221,7 @@ static inline int fs_channel(target_phys_addr_t addr) #ifdef USE_THIS_DEAD_CODE static void channel_load_g(struct fs_dma_ctrl *ctrl, int c) { - target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP); + hwaddr addr = channel_reg(ctrl, c, RW_GROUP); /* Load and decode. FIXME: handle endianness. */ cpu_physical_memory_read (addr, @@ -253,7 +253,7 @@ static void dump_d(int ch, struct dma_descr_data *d) static void channel_load_c(struct fs_dma_ctrl *ctrl, int c) { - target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP_DOWN); + hwaddr addr = channel_reg(ctrl, c, RW_GROUP_DOWN); /* Load and decode. FIXME: handle endianness. */ cpu_physical_memory_read (addr, @@ -270,7 +270,7 @@ static void channel_load_c(struct fs_dma_ctrl *ctrl, int c) static void channel_load_d(struct fs_dma_ctrl *ctrl, int c) { - target_phys_addr_t addr = channel_reg(ctrl, c, RW_SAVED_DATA); + hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA); /* Load and decode. FIXME: handle endianness. */ D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr)); @@ -284,7 +284,7 @@ static void channel_load_d(struct fs_dma_ctrl *ctrl, int c) static void channel_store_c(struct fs_dma_ctrl *ctrl, int c) { - target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP_DOWN); + hwaddr addr = channel_reg(ctrl, c, RW_GROUP_DOWN); /* Encode and store. FIXME: handle endianness. */ D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr)); @@ -296,7 +296,7 @@ static void channel_store_c(struct fs_dma_ctrl *ctrl, int c) static void channel_store_d(struct fs_dma_ctrl *ctrl, int c) { - target_phys_addr_t addr = channel_reg(ctrl, c, RW_SAVED_DATA); + hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA); /* Encode and store. FIXME: handle endianness. */ D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr)); @@ -573,14 +573,14 @@ static inline int channel_in_run(struct fs_dma_ctrl *ctrl, int c) return 0; } -static uint32_t dma_rinvalid (void *opaque, target_phys_addr_t addr) +static uint32_t dma_rinvalid (void *opaque, hwaddr addr) { hw_error("Unsupported short raccess. reg=" TARGET_FMT_plx "\n", addr); return 0; } static uint64_t -dma_read(void *opaque, target_phys_addr_t addr, unsigned int size) +dma_read(void *opaque, hwaddr addr, unsigned int size) { struct fs_dma_ctrl *ctrl = opaque; int c; @@ -612,7 +612,7 @@ dma_read(void *opaque, target_phys_addr_t addr, unsigned int size) } static void -dma_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value) +dma_winvalid (void *opaque, hwaddr addr, uint32_t value) { hw_error("Unsupported short waccess. reg=" TARGET_FMT_plx "\n", addr); } @@ -627,7 +627,7 @@ dma_update_state(struct fs_dma_ctrl *ctrl, int c) } static void -dma_write(void *opaque, target_phys_addr_t addr, +dma_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { struct fs_dma_ctrl *ctrl = opaque; @@ -762,7 +762,7 @@ static void DMA_run(void *opaque) qemu_bh_schedule_idle(etraxfs_dmac->bh); } -void *etraxfs_dmac_init(target_phys_addr_t base, int nr_channels) +void *etraxfs_dmac_init(hwaddr base, int nr_channels) { struct fs_dma_ctrl *ctrl = NULL; diff --git a/hw/etraxfs_dma.h b/hw/etraxfs_dma.h index 021c52ae7d..38104a67b5 100644 --- a/hw/etraxfs_dma.h +++ b/hw/etraxfs_dma.h @@ -1,3 +1,6 @@ +#ifndef HW_ETRAXFS_DMA_H +#define HW_ETRAXFS_DMA_H 1 + struct dma_context_metadata { /* data descriptor md */ uint16_t metadata; @@ -20,10 +23,12 @@ struct etraxfs_dma_client } client; }; -void *etraxfs_dmac_init(target_phys_addr_t base, int nr_channels); +void *etraxfs_dmac_init(hwaddr base, int nr_channels); void etraxfs_dmac_connect(void *opaque, int channel, qemu_irq *line, int input); void etraxfs_dmac_connect_client(void *opaque, int c, struct etraxfs_dma_client *cl); int etraxfs_dmac_input(struct etraxfs_dma_client *client, void *buf, int len, int eop); + +#endif diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index b124f5bb3a..289a810edc 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -24,7 +24,7 @@ #include <stdio.h> #include "sysbus.h" -#include "net.h" +#include "net/net.h" #include "etraxfs.h" #define D(x) @@ -374,7 +374,7 @@ static void eth_validate_duplex(struct fs_eth *eth) } static uint64_t -eth_read(void *opaque, target_phys_addr_t addr, unsigned int size) +eth_read(void *opaque, hwaddr addr, unsigned int size) { struct fs_eth *eth = opaque; uint32_t r = 0; @@ -418,7 +418,7 @@ static void eth_update_ma(struct fs_eth *eth, int ma) } static void -eth_write(void *opaque, target_phys_addr_t addr, +eth_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { struct fs_eth *eth = opaque; diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c index dc27f88ac9..62a62a36af 100644 --- a/hw/etraxfs_pic.c +++ b/hw/etraxfs_pic.c @@ -79,7 +79,7 @@ static void pic_update(struct etrax_pic *fs) } static uint64_t -pic_read(void *opaque, target_phys_addr_t addr, unsigned int size) +pic_read(void *opaque, hwaddr addr, unsigned int size) { struct etrax_pic *fs = opaque; uint32_t rval; @@ -89,7 +89,7 @@ pic_read(void *opaque, target_phys_addr_t addr, unsigned int size) return rval; } -static void pic_write(void *opaque, target_phys_addr_t addr, +static void pic_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size) { struct etrax_pic *fs = opaque; diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c index 5f16b17835..7bde8004d0 100644 --- a/hw/etraxfs_ser.c +++ b/hw/etraxfs_ser.c @@ -23,8 +23,8 @@ */ #include "sysbus.h" -#include "qemu-char.h" -#include "qemu-log.h" +#include "char/char.h" +#include "qemu/log.h" #define D(x) @@ -75,7 +75,7 @@ static void ser_update_irq(struct etrax_serial *s) } static uint64_t -ser_read(void *opaque, target_phys_addr_t addr, unsigned int size) +ser_read(void *opaque, hwaddr addr, unsigned int size) { struct etrax_serial *s = opaque; D(CPUCRISState *env = s->env); @@ -110,7 +110,7 @@ ser_read(void *opaque, target_phys_addr_t addr, unsigned int size) } static void -ser_write(void *opaque, target_phys_addr_t addr, +ser_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { struct etrax_serial *s = opaque; diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c index 9076a49884..e9273cd95d 100644 --- a/hw/etraxfs_timer.c +++ b/hw/etraxfs_timer.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ #include "sysbus.h" -#include "sysemu.h" -#include "qemu-timer.h" +#include "sysemu/sysemu.h" +#include "qemu/timer.h" #include "ptimer.h" #define D(x) @@ -75,7 +75,7 @@ struct etrax_timer { }; static uint64_t -timer_read(void *opaque, target_phys_addr_t addr, unsigned int size) +timer_read(void *opaque, hwaddr addr, unsigned int size) { struct etrax_timer *t = opaque; uint32_t r = 0; @@ -242,7 +242,7 @@ static inline void timer_watchdog_update(struct etrax_timer *t, uint32_t value) } static void -timer_write(void *opaque, target_phys_addr_t addr, +timer_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { struct etrax_timer *t = opaque; diff --git a/hw/exynos4210.c b/hw/exynos4210.c index 00d4db8871..246a0fc1c3 100644 --- a/hw/exynos4210.c +++ b/hw/exynos4210.c @@ -22,11 +22,12 @@ */ #include "boards.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "sysbus.h" #include "arm-misc.h" #include "loader.h" #include "exynos4210.h" +#include "usb/hcd-ehci.h" #define EXYNOS4210_CHIPID_ADDR 0x10000000 @@ -72,6 +73,9 @@ /* Display controllers (FIMD) */ #define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000 +/* EHCI */ +#define EXYNOS4210_EHCI_BASE_ADDR 0x12580000 + static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43, 0x09, 0x00, 0x00, 0x00 }; @@ -80,12 +84,16 @@ void exynos4210_write_secondary(ARMCPU *cpu, { int n; uint32_t smpboot[] = { - 0xe59f3024, /* ldr r3, External gic_cpu_if */ - 0xe59f2024, /* ldr r2, Internal gic_cpu_if */ - 0xe59f0024, /* ldr r0, startaddr */ + 0xe59f3034, /* ldr r3, External gic_cpu_if */ + 0xe59f2034, /* ldr r2, Internal gic_cpu_if */ + 0xe59f0034, /* ldr r0, startaddr */ 0xe3a01001, /* mov r1, #1 */ 0xe5821000, /* str r1, [r2] */ 0xe5831000, /* str r1, [r3] */ + 0xe3a010ff, /* mov r1, #0xff */ + 0xe5821004, /* str r1, [r2, #4] */ + 0xe5831004, /* str r1, [r3, #4] */ + 0xf57ff04f, /* dsb */ 0xe320f003, /* wfi */ 0xe5901000, /* ldr r1, [r0] */ 0xe1110001, /* tst r1, r1 */ @@ -334,5 +342,8 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, s->irq_table[exynos4210_get_irq(11, 2)], NULL); + sysbus_create_simple(TYPE_EXYNOS4210_EHCI, EXYNOS4210_EHCI_BASE_ADDR, + s->irq_table[exynos4210_get_irq(28, 3)]); + return s; } diff --git a/hw/exynos4210.h b/hw/exynos4210.h index a43ba3aedc..bb9a1dddc8 100644 --- a/hw/exynos4210.h +++ b/hw/exynos4210.h @@ -27,7 +27,7 @@ #define EXYNOS4210_H_ #include "qemu-common.h" -#include "memory.h" +#include "exec/memory.h" #define EXYNOS4210_NCPUS 2 @@ -128,7 +128,7 @@ void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev, /* * exynos4210 UART */ -DeviceState *exynos4210_uart_create(target_phys_addr_t addr, +DeviceState *exynos4210_uart_create(hwaddr addr, int fifo_size, int channel, CharDriverState *chr, diff --git a/hw/exynos4210_combiner.c b/hw/exynos4210_combiner.c index 80af22cc33..84d36ed11f 100644 --- a/hw/exynos4210_combiner.c +++ b/hw/exynos4210_combiner.c @@ -174,7 +174,7 @@ void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev, } static uint64_t -exynos4210_combiner_read(void *opaque, target_phys_addr_t offset, unsigned size) +exynos4210_combiner_read(void *opaque, hwaddr offset, unsigned size) { struct Exynos4210CombinerState *s = (struct Exynos4210CombinerState *)opaque; @@ -266,7 +266,7 @@ static void exynos4210_combiner_update(void *opaque, uint8_t group_n) } } -static void exynos4210_combiner_write(void *opaque, target_phys_addr_t offset, +static void exynos4210_combiner_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { struct Exynos4210CombinerState *s = @@ -347,8 +347,6 @@ static void exynos4210_combiner_write(void *opaque, target_phys_addr_t offset, TARGET_FMT_plx "\n", offset); break; } - - return; } /* Get combiner group and bit from irq number */ @@ -380,8 +378,6 @@ static void exynos4210_combiner_handler(void *opaque, int irq, int level) } exynos4210_combiner_update(s, group_n); - - return; } static void exynos4210_combiner_reset(DeviceState *d) diff --git a/hw/exynos4210_fimd.c b/hw/exynos4210_fimd.c index 3313f00a71..5c29b5d01d 100644 --- a/hw/exynos4210_fimd.c +++ b/hw/exynos4210_fimd.c @@ -23,11 +23,11 @@ */ #include "qemu-common.h" -#include "cpu-all.h" +#include "exec/cpu-all.h" #include "sysbus.h" -#include "console.h" -#include "pixel_ops.h" -#include "bswap.h" +#include "ui/console.h" +#include "ui/pixel_ops.h" +#include "qemu/bswap.h" /* Debug messages configuration */ #define EXYNOS4210_FIMD_DEBUG 0 @@ -290,7 +290,7 @@ struct Exynos4210fimdWindow { uint16_t virtpage_offsize; /* VIDWADD2 register */ MemoryRegionSection mem_section; /* RAM fragment containing framebuffer */ uint8_t *host_fb_addr; /* Host pointer to window's framebuffer */ - target_phys_addr_t fb_len; /* Framebuffer length */ + hwaddr fb_len; /* Framebuffer length */ }; typedef struct { @@ -1110,7 +1110,7 @@ static inline int fimd_get_buffer_id(Exynos4210fimdWindow *w) static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win) { Exynos4210fimdWindow *w = &s->window[win]; - target_phys_addr_t fb_start_addr, fb_mapped_len; + hwaddr fb_start_addr, fb_mapped_len; if (!s->enabled || !(w->wincon & FIMD_WINCON_ENWIN) || FIMD_WINDOW_PROTECTED(s->shadowcon, win)) { @@ -1243,7 +1243,7 @@ static void exynos4210_fimd_update(void *opaque) Exynos4210fimdState *s = (Exynos4210fimdState *)opaque; Exynos4210fimdWindow *w; int i, line; - target_phys_addr_t fb_line_addr, inc_size; + hwaddr fb_line_addr, inc_size; int scrn_height; int first_line = -1, last_line = -1, scrn_width; bool blend = false; @@ -1307,7 +1307,7 @@ static void exynos4210_fimd_update(void *opaque) fimd_copy_line_toqemu(global_width, s->ifb + global_width * line * RGBA_SIZE, d + global_width * line * bpp); } - dpy_update(s->console, 0, 0, global_width, global_height); + dpy_gfx_update(s->console, 0, 0, global_width, global_height); } s->invalidate = false; s->vidintcon[1] |= FIMD_VIDINT_INTFRMPEND; @@ -1348,7 +1348,7 @@ static void exynos4210_fimd_reset(DeviceState *d) s->hueoffset = 0x01800080; } -static void exynos4210_fimd_write(void *opaque, target_phys_addr_t offset, +static void exynos4210_fimd_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { Exynos4210fimdState *s = (Exynos4210fimdState *)opaque; @@ -1649,7 +1649,7 @@ static void exynos4210_fimd_write(void *opaque, target_phys_addr_t offset, } } -static uint64_t exynos4210_fimd_read(void *opaque, target_phys_addr_t offset, +static uint64_t exynos4210_fimd_read(void *opaque, hwaddr offset, unsigned size) { Exynos4210fimdState *s = (Exynos4210fimdState *)opaque; diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c index 7d03dd9ae3..959de5679d 100644 --- a/hw/exynos4210_gic.c +++ b/hw/exynos4210_gic.c @@ -140,7 +140,7 @@ combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6, EXT_GIC_ID_I2C7 }, /* int combiner group 28 */ - { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 }, + { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 , EXT_GIC_ID_USB_HOST}, /* int combiner group 29 */ { EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2, EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC }, @@ -193,8 +193,6 @@ static void exynos4210_irq_handler(void *opaque, int irq, int level) /* Bypass */ qemu_set_irq(s->board_irqs[irq], level); - - return; } /* @@ -410,8 +408,6 @@ static void exynos4210_irq_gate_handler(void *opaque, int irq, int level) } qemu_irq_lower(s->out); - - return; } static void exynos4210_irq_gate_reset(DeviceState *d) diff --git a/hw/exynos4210_i2c.c b/hw/exynos4210_i2c.c index 3f72a5c464..cefd736092 100644 --- a/hw/exynos4210_i2c.c +++ b/hw/exynos4210_i2c.c @@ -20,7 +20,7 @@ * */ -#include "qemu-timer.h" +#include "qemu/timer.h" #include "sysbus.h" #include "i2c.h" @@ -129,7 +129,7 @@ static void exynos4210_i2c_data_send(void *opaque) exynos4210_i2c_raise_interrupt(s); } -static uint64_t exynos4210_i2c_read(void *opaque, target_phys_addr_t offset, +static uint64_t exynos4210_i2c_read(void *opaque, hwaddr offset, unsigned size) { Exynos4210I2CState *s = (Exynos4210I2CState *)opaque; @@ -168,7 +168,7 @@ static uint64_t exynos4210_i2c_read(void *opaque, target_phys_addr_t offset, return value; } -static void exynos4210_i2c_write(void *opaque, target_phys_addr_t offset, +static void exynos4210_i2c_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { Exynos4210I2CState *s = (Exynos4210I2CState *)opaque; diff --git a/hw/exynos4210_mct.c b/hw/exynos4210_mct.c index 7a22b1f900..41cd142227 100644 --- a/hw/exynos4210_mct.c +++ b/hw/exynos4210_mct.c @@ -53,7 +53,7 @@ */ #include "sysbus.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "qemu-common.h" #include "ptimer.h" @@ -568,14 +568,12 @@ static void exynos4210_gfrc_event(void *opaque) /* Reload FRC to reach nearest comparator */ s->g_timer.curr_comp = exynos4210_gcomp_find(s); distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp); - if (distance > MCT_GT_COUNTER_STEP) { + if (distance > MCT_GT_COUNTER_STEP || !distance) { distance = MCT_GT_COUNTER_STEP; } exynos4210_gfrc_set_count(&s->g_timer, distance); exynos4210_gfrc_start(&s->g_timer); - - return; } /* @@ -987,7 +985,7 @@ static void exynos4210_mct_reset(DeviceState *d) } /* Multi Core Timer read */ -static uint64_t exynos4210_mct_read(void *opaque, target_phys_addr_t offset, +static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset, unsigned size) { Exynos4210MCTState *s = (Exynos4210MCTState *)opaque; @@ -1100,7 +1098,7 @@ static uint64_t exynos4210_mct_read(void *opaque, target_phys_addr_t offset, } /* MCT write */ -static void exynos4210_mct_write(void *opaque, target_phys_addr_t offset, +static void exynos4210_mct_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { Exynos4210MCTState *s = (Exynos4210MCTState *)opaque; diff --git a/hw/exynos4210_pmu.c b/hw/exynos4210_pmu.c index c12d7501cc..a22b8f181a 100644 --- a/hw/exynos4210_pmu.c +++ b/hw/exynos4210_pmu.c @@ -392,7 +392,7 @@ typedef struct Exynos4210PmuState { uint32_t reg[PMU_NUM_OF_REGISTERS]; } Exynos4210PmuState; -static uint64_t exynos4210_pmu_read(void *opaque, target_phys_addr_t offset, +static uint64_t exynos4210_pmu_read(void *opaque, hwaddr offset, unsigned size) { Exynos4210PmuState *s = (Exynos4210PmuState *)opaque; @@ -411,7 +411,7 @@ static uint64_t exynos4210_pmu_read(void *opaque, target_phys_addr_t offset, return 0; } -static void exynos4210_pmu_write(void *opaque, target_phys_addr_t offset, +static void exynos4210_pmu_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { Exynos4210PmuState *s = (Exynos4210PmuState *)opaque; diff --git a/hw/exynos4210_pwm.c b/hw/exynos4210_pwm.c index 0c228280a9..3a3eb8c27a 100644 --- a/hw/exynos4210_pwm.c +++ b/hw/exynos4210_pwm.c @@ -21,7 +21,7 @@ */ #include "sysbus.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "qemu-common.h" #include "ptimer.h" @@ -208,7 +208,7 @@ static void exynos4210_pwm_tick(void *opaque) /* * PWM Read */ -static uint64_t exynos4210_pwm_read(void *opaque, target_phys_addr_t offset, +static uint64_t exynos4210_pwm_read(void *opaque, hwaddr offset, unsigned size) { Exynos4210PWMState *s = (Exynos4210PWMState *)opaque; @@ -259,7 +259,7 @@ static uint64_t exynos4210_pwm_read(void *opaque, target_phys_addr_t offset, /* * PWM Write */ -static void exynos4210_pwm_write(void *opaque, target_phys_addr_t offset, +static void exynos4210_pwm_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { Exynos4210PWMState *s = (Exynos4210PWMState *)opaque; diff --git a/hw/exynos4210_rtc.c b/hw/exynos4210_rtc.c index 42a4ddc327..5694a6207b 100644 --- a/hw/exynos4210_rtc.c +++ b/hw/exynos4210_rtc.c @@ -26,13 +26,13 @@ */ #include "sysbus.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "qemu-common.h" #include "ptimer.h" #include "hw.h" -#include "qemu-timer.h" -#include "sysemu.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" #include "exynos4210.h" @@ -299,7 +299,7 @@ static void exynos4210_rtc_1Hz_tick(void *opaque) /* * RTC Read */ -static uint64_t exynos4210_rtc_read(void *opaque, target_phys_addr_t offset, +static uint64_t exynos4210_rtc_read(void *opaque, hwaddr offset, unsigned size) { uint32_t value = 0; @@ -376,7 +376,7 @@ static uint64_t exynos4210_rtc_read(void *opaque, target_phys_addr_t offset, /* * RTC Write */ -static void exynos4210_rtc_write(void *opaque, target_phys_addr_t offset, +static void exynos4210_rtc_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { Exynos4210RTCState *s = (Exynos4210RTCState *)opaque; diff --git a/hw/exynos4210_uart.c b/hw/exynos4210_uart.c index ccc47804f9..4f23079095 100644 --- a/hw/exynos4210_uart.c +++ b/hw/exynos4210_uart.c @@ -20,8 +20,8 @@ */ #include "sysbus.h" -#include "sysemu.h" -#include "qemu-char.h" +#include "sysemu/sysemu.h" +#include "char/char.h" #include "exynos4210.h" @@ -96,7 +96,7 @@ typedef struct Exynos4210UartReg { const char *name; /* the only reason is the debug output */ - target_phys_addr_t offset; + hwaddr offset; uint32_t reset_value; } Exynos4210UartReg; @@ -184,7 +184,7 @@ typedef struct { #if DEBUG_UART /* Used only for debugging inside PRINT_DEBUG_... macros */ -static const char *exynos4210_uart_regname(target_phys_addr_t offset) +static const char *exynos4210_uart_regname(hwaddr offset) { int regs_number = sizeof(exynos4210_uart_regs) / sizeof(Exynos4210UartReg); @@ -348,7 +348,7 @@ static void exynos4210_uart_update_parameters(Exynos4210UartState *s) s->channel, speed, parity, data_bits, stop_bits); } -static void exynos4210_uart_write(void *opaque, target_phys_addr_t offset, +static void exynos4210_uart_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { Exynos4210UartState *s = (Exynos4210UartState *)opaque; @@ -423,7 +423,7 @@ static void exynos4210_uart_write(void *opaque, target_phys_addr_t offset, break; } } -static uint64_t exynos4210_uart_read(void *opaque, target_phys_addr_t offset, +static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset, unsigned size) { Exynos4210UartState *s = (Exynos4210UartState *)opaque; @@ -581,7 +581,7 @@ static const VMStateDescription vmstate_exynos4210_uart = { } }; -DeviceState *exynos4210_uart_create(target_phys_addr_t addr, +DeviceState *exynos4210_uart_create(hwaddr addr, int fifo_size, int channel, CharDriverState *chr, @@ -617,7 +617,7 @@ DeviceState *exynos4210_uart_create(target_phys_addr_t addr, bus = sysbus_from_qdev(dev); qdev_init_nofail(dev); - if (addr != (target_phys_addr_t)-1) { + if (addr != (hwaddr)-1) { sysbus_mmio_map(bus, 0, addr); } sysbus_connect_irq(bus, 0, irq); diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c index 4bb0a60cb1..b26796847b 100644 --- a/hw/exynos4_boards.c +++ b/hw/exynos4_boards.c @@ -21,11 +21,11 @@ * */ -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "sysbus.h" -#include "net.h" +#include "net/net.h" #include "arm-misc.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #include "exynos4210.h" #include "boards.h" @@ -93,11 +93,8 @@ static void lan9215_init(uint32_t base, qemu_irq irq) } } -static Exynos4210State *exynos4_boards_init_common( - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - Exynos4BoardType board_type) +static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args, + Exynos4BoardType board_type) { if (smp_cpus != EXYNOS4210_NCPUS) { fprintf(stderr, "%s board supports only %d CPU cores. Ignoring smp_cpus" @@ -110,9 +107,9 @@ static Exynos4210State *exynos4_boards_init_common( exynos4_board_binfo.board_id = exynos4_board_id[board_type]; exynos4_board_binfo.smp_bootreg_addr = exynos4_board_smp_bootreg_addr[board_type]; - exynos4_board_binfo.kernel_filename = kernel_filename; - exynos4_board_binfo.initrd_filename = initrd_filename; - exynos4_board_binfo.kernel_cmdline = kernel_cmdline; + exynos4_board_binfo.kernel_filename = args->kernel_filename; + exynos4_board_binfo.initrd_filename = args->initrd_filename; + exynos4_board_binfo.kernel_cmdline = args->kernel_cmdline; exynos4_board_binfo.gic_cpu_if_addr = EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100; @@ -122,32 +119,25 @@ static Exynos4210State *exynos4_boards_init_common( " initrd_filename: %s\n", exynos4_board_ram_size[board_type] / 1048576, exynos4_board_ram_size[board_type], - kernel_filename, - kernel_cmdline, - initrd_filename); + args->kernel_filename, + args->kernel_cmdline, + args->initrd_filename); return exynos4210_init(get_system_memory(), exynos4_board_ram_size[board_type]); } -static void nuri_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void nuri_init(QEMUMachineInitArgs *args) { - exynos4_boards_init_common(kernel_filename, kernel_cmdline, - initrd_filename, EXYNOS4_BOARD_NURI); + exynos4_boards_init_common(args, EXYNOS4_BOARD_NURI); arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo); } -static void smdkc210_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void smdkc210_init(QEMUMachineInitArgs *args) { - Exynos4210State *s = exynos4_boards_init_common(kernel_filename, - kernel_cmdline, initrd_filename, EXYNOS4_BOARD_SMDKC210); + Exynos4210State *s = exynos4_boards_init_common(args, + EXYNOS4_BOARD_SMDKC210); lan9215_init(SMDK_LAN9118_BASE_ADDR, qemu_irq_invert(s->irq_table[exynos4210_get_irq(37, 1)])); @@ -29,14 +29,14 @@ #include "hw.h" #include "fdc.h" -#include "qemu-error.h" -#include "qemu-timer.h" +#include "qemu/error-report.h" +#include "qemu/timer.h" #include "isa.h" #include "sysbus.h" #include "qdev-addr.h" -#include "blockdev.h" -#include "sysemu.h" -#include "qemu-log.h" +#include "sysemu/blockdev.h" +#include "sysemu/sysemu.h" +#include "qemu/log.h" /********************************************************/ /* debug Floppy devices */ @@ -327,7 +327,7 @@ static void fdctrl_reset(FDCtrl *fdctrl, int do_irq); static void fdctrl_reset_fifo(FDCtrl *fdctrl); static int fdctrl_transfer_handler (void *opaque, int nchan, int dma_pos, int dma_len); -static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0); +static void fdctrl_raise_irq(FDCtrl *fdctrl); static FDrive *get_cur_drv(FDCtrl *fdctrl); static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl); @@ -349,12 +349,12 @@ enum { FD_DIR_SCANE = 2, FD_DIR_SCANL = 3, FD_DIR_SCANH = 4, + FD_DIR_VERIFY = 5, }; enum { FD_STATE_MULTI = 0x01, /* multi track flag */ FD_STATE_FORMAT = 0x02, /* format flag */ - FD_STATE_SEEK = 0x04, /* seek flag */ }; enum { @@ -496,7 +496,6 @@ enum { }; #define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI) -#define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK) #define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT) struct FDCtrl { @@ -626,13 +625,13 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value) } } -static uint64_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg, +static uint64_t fdctrl_read_mem (void *opaque, hwaddr reg, unsigned ize) { return fdctrl_read(opaque, (uint32_t)reg); } -static void fdctrl_write_mem (void *opaque, target_phys_addr_t reg, +static void fdctrl_write_mem (void *opaque, hwaddr reg, uint64_t value, unsigned size) { fdctrl_write(opaque, (uint32_t)reg, value); @@ -799,6 +798,7 @@ static void fdctrl_handle_tc(void *opaque, int irq, int level) /* Change IRQ state */ static void fdctrl_reset_irq(FDCtrl *fdctrl) { + fdctrl->status0 = 0; if (!(fdctrl->sra & FD_SRA_INTPEND)) return; FLOPPY_DPRINTF("Reset interrupt\n"); @@ -806,14 +806,13 @@ static void fdctrl_reset_irq(FDCtrl *fdctrl) fdctrl->sra &= ~FD_SRA_INTPEND; } -static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0) +static void fdctrl_raise_irq(FDCtrl *fdctrl) { /* Sparc mutation */ if (fdctrl->sun4m && (fdctrl->msr & FD_MSR_CMDBUSY)) { /* XXX: not sure */ fdctrl->msr &= ~FD_MSR_CMDBUSY; fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO; - fdctrl->status0 = status0; return; } if (!(fdctrl->sra & FD_SRA_INTPEND)) { @@ -822,7 +821,6 @@ static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0) } fdctrl->reset_sensei = 0; - fdctrl->status0 = status0; FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0); } @@ -851,7 +849,8 @@ static void fdctrl_reset(FDCtrl *fdctrl, int do_irq) fd_recalibrate(&fdctrl->drives[i]); fdctrl_reset_fifo(fdctrl); if (do_irq) { - fdctrl_raise_irq(fdctrl, FD_SR0_RDYCHG); + fdctrl->status0 |= FD_SR0_RDYCHG; + fdctrl_raise_irq(fdctrl); fdctrl->reset_sensei = FD_RESET_SENSEI_COUNT; } } @@ -1079,15 +1078,12 @@ static void fdctrl_reset_fifo(FDCtrl *fdctrl) } /* Set FIFO status for the host to read */ -static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len, uint8_t status0) +static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len) { fdctrl->data_dir = FD_DIR_READ; fdctrl->data_len = fifo_len; fdctrl->data_pos = 0; fdctrl->msr |= FD_MSR_CMDBUSY | FD_MSR_RQM | FD_MSR_DIO; - if (status0) { - fdctrl_raise_irq(fdctrl, status0); - } } /* Set an error: unimplemented/unknown command */ @@ -1096,7 +1092,7 @@ static void fdctrl_unimplemented(FDCtrl *fdctrl, int direction) qemu_log_mask(LOG_UNIMP, "fdc: unimplemented command 0x%02x\n", fdctrl->fifo[0]); fdctrl->fifo[0] = FD_SR0_INVCMD; - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); } /* Seek to next sector @@ -1126,11 +1122,13 @@ static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv) } else { new_head = 0; new_track++; + fdctrl->status0 |= FD_SR0_SEEK; if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) { ret = 0; } } } else { + fdctrl->status0 |= FD_SR0_SEEK; new_track++; ret = 0; } @@ -1150,10 +1148,14 @@ static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0, uint8_t status1, uint8_t status2) { FDrive *cur_drv; - cur_drv = get_cur_drv(fdctrl); - fdctrl->status0 = status0 | FD_SR0_SEEK | (cur_drv->head << 2) | - GET_CUR_DRV(fdctrl); + + fdctrl->status0 &= ~(FD_SR0_DS0 | FD_SR0_DS1 | FD_SR0_HEAD); + fdctrl->status0 |= GET_CUR_DRV(fdctrl); + if (cur_drv->head) { + fdctrl->status0 |= FD_SR0_HEAD; + } + fdctrl->status0 |= status0; FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n", status0, status1, status2, fdctrl->status0); @@ -1170,7 +1172,9 @@ static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0, } fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO; fdctrl->msr &= ~FD_MSR_NONDMA; - fdctrl_set_fifo(fdctrl, 7, fdctrl->status0); + + fdctrl_set_fifo(fdctrl, 7); + fdctrl_raise_irq(fdctrl); } /* Prepare a data transfer (either DMA or FIFO) */ @@ -1178,7 +1182,6 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) { FDrive *cur_drv; uint8_t kh, kt, ks; - int did_seek = 0; SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK); cur_drv = get_cur_drv(fdctrl); @@ -1212,7 +1215,7 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) fdctrl->fifo[5] = ks; return; case 1: - did_seek = 1; + fdctrl->status0 |= FD_SR0_SEEK; break; default: break; @@ -1234,16 +1237,12 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) /* Set the FIFO state */ fdctrl->data_dir = direction; fdctrl->data_pos = 0; - fdctrl->msr |= FD_MSR_CMDBUSY; + assert(fdctrl->msr & FD_MSR_CMDBUSY); if (fdctrl->fifo[0] & 0x80) fdctrl->data_state |= FD_STATE_MULTI; else fdctrl->data_state &= ~FD_STATE_MULTI; - if (did_seek) - fdctrl->data_state |= FD_STATE_SEEK; - else - fdctrl->data_state &= ~FD_STATE_SEEK; - if (fdctrl->fifo[5] == 00) { + if (fdctrl->fifo[5] == 0) { fdctrl->data_len = fdctrl->fifo[8]; } else { int tmp; @@ -1266,14 +1265,21 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL || direction == FD_DIR_SCANH) && dma_mode == 0) || (direction == FD_DIR_WRITE && dma_mode == 2) || - (direction == FD_DIR_READ && dma_mode == 1)) { + (direction == FD_DIR_READ && dma_mode == 1) || + (direction == FD_DIR_VERIFY)) { /* No access is allowed until DMA transfer has completed */ fdctrl->msr &= ~FD_MSR_RQM; - /* Now, we just have to wait for the DMA controller to - * recall us... - */ - DMA_hold_DREQ(fdctrl->dma_chann); - DMA_schedule(fdctrl->dma_chann); + if (direction != FD_DIR_VERIFY) { + /* Now, we just have to wait for the DMA controller to + * recall us... + */ + DMA_hold_DREQ(fdctrl->dma_chann); + DMA_schedule(fdctrl->dma_chann); + } else { + /* Start transfer */ + fdctrl_transfer_handler(fdctrl, fdctrl->dma_chann, 0, + fdctrl->data_len); + } return; } else { FLOPPY_DPRINTF("bad dma_mode=%d direction=%d\n", dma_mode, @@ -1285,9 +1291,7 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) if (direction != FD_DIR_WRITE) fdctrl->msr |= FD_MSR_DIO; /* IO based transfer: calculate len */ - fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); - - return; + fdctrl_raise_irq(fdctrl); } /* Prepare a transfer of deleted data */ @@ -1378,6 +1382,9 @@ static int fdctrl_transfer_handler (void *opaque, int nchan, goto transfer_error; } break; + case FD_DIR_VERIFY: + /* VERIFY commands */ + break; default: /* SCAN commands */ { @@ -1413,8 +1420,6 @@ static int fdctrl_transfer_handler (void *opaque, int nchan, fdctrl->data_dir == FD_DIR_SCANL || fdctrl->data_dir == FD_DIR_SCANH) status2 = FD_SR2_SEH; - if (FD_DID_SEEK(fdctrl->data_state)) - status0 |= FD_SR0_SEEK; fdctrl->data_len -= len; fdctrl_stop_transfer(fdctrl, status0, status1, status2); transfer_error: @@ -1460,7 +1465,7 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl) * then from status mode to command mode */ if (fdctrl->msr & FD_MSR_NONDMA) { - fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); } else { fdctrl_reset_fifo(fdctrl); fdctrl_reset_irq(fdctrl); @@ -1508,7 +1513,7 @@ static void fdctrl_format_sector(FDCtrl *fdctrl) fdctrl->fifo[5] = ks; return; case 1: - fdctrl->data_state |= FD_STATE_SEEK; + fdctrl->status0 |= FD_SR0_SEEK; break; default: break; @@ -1522,10 +1527,7 @@ static void fdctrl_format_sector(FDCtrl *fdctrl) if (cur_drv->sect == cur_drv->last_sect) { fdctrl->data_state &= ~FD_STATE_FORMAT; /* Last sector done */ - if (FD_DID_SEEK(fdctrl->data_state)) - fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00); - else - fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); } else { /* More to do */ fdctrl->data_pos = 0; @@ -1538,7 +1540,7 @@ static void fdctrl_handle_lock(FDCtrl *fdctrl, int direction) { fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0; fdctrl->fifo[0] = fdctrl->lock << 4; - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); } static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction) @@ -1563,20 +1565,20 @@ static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction) (cur_drv->perpendicular << 2); fdctrl->fifo[8] = fdctrl->config; fdctrl->fifo[9] = fdctrl->precomp_trk; - fdctrl_set_fifo(fdctrl, 10, 0); + fdctrl_set_fifo(fdctrl, 10); } static void fdctrl_handle_version(FDCtrl *fdctrl, int direction) { /* Controller's version */ fdctrl->fifo[0] = fdctrl->version; - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); } static void fdctrl_handle_partid(FDCtrl *fdctrl, int direction) { fdctrl->fifo[0] = 0x41; /* Stepping 1 */ - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); } static void fdctrl_handle_restore(FDCtrl *fdctrl, int direction) @@ -1629,7 +1631,7 @@ static void fdctrl_handle_save(FDCtrl *fdctrl, int direction) fdctrl->fifo[12] = fdctrl->pwrd; fdctrl->fifo[13] = 0; fdctrl->fifo[14] = 0; - fdctrl_set_fifo(fdctrl, 15, 0); + fdctrl_set_fifo(fdctrl, 15); } static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction) @@ -1652,7 +1654,6 @@ static void fdctrl_handle_format_track(FDCtrl *fdctrl, int direction) fdctrl->data_state |= FD_STATE_MULTI; else fdctrl->data_state &= ~FD_STATE_MULTI; - fdctrl->data_state &= ~FD_STATE_SEEK; cur_drv->bps = fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2]; #if 0 @@ -1695,7 +1696,7 @@ static void fdctrl_handle_sense_drive_status(FDCtrl *fdctrl, int direction) (cur_drv->head << 2) | GET_CUR_DRV(fdctrl) | 0x28; - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); } static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction) @@ -1707,7 +1708,8 @@ static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction) fd_recalibrate(cur_drv); fdctrl_reset_fifo(fdctrl); /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); + fdctrl->status0 |= FD_SR0_SEEK; + fdctrl_raise_irq(fdctrl); } static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction) @@ -1720,7 +1722,7 @@ static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction) fdctrl->reset_sensei--; } else if (!(fdctrl->sra & FD_SRA_INTPEND)) { fdctrl->fifo[0] = FD_SR0_INVCMD; - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); return; } else { fdctrl->fifo[0] = @@ -1729,7 +1731,7 @@ static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction) } fdctrl->fifo[1] = cur_drv->track; - fdctrl_set_fifo(fdctrl, 2, 0); + fdctrl_set_fifo(fdctrl, 2); fdctrl_reset_irq(fdctrl); fdctrl->status0 = FD_SR0_RDYCHG; } @@ -1746,7 +1748,8 @@ static void fdctrl_handle_seek(FDCtrl *fdctrl, int direction) */ fd_seek(cur_drv, cur_drv->head, fdctrl->fifo[2], cur_drv->sect, 1); /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); + fdctrl->status0 |= FD_SR0_SEEK; + fdctrl_raise_irq(fdctrl); } static void fdctrl_handle_perpendicular_mode(FDCtrl *fdctrl, int direction) @@ -1771,7 +1774,7 @@ static void fdctrl_handle_powerdown_mode(FDCtrl *fdctrl, int direction) { fdctrl->pwrd = fdctrl->fifo[1]; fdctrl->fifo[0] = fdctrl->fifo[1]; - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); } static void fdctrl_handle_option(FDCtrl *fdctrl, int direction) @@ -1790,7 +1793,7 @@ static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direct fdctrl->fifo[0] = fdctrl->fifo[1]; fdctrl->fifo[2] = 0; fdctrl->fifo[3] = 0; - fdctrl_set_fifo(fdctrl, 4, 0); + fdctrl_set_fifo(fdctrl, 4); } else { fdctrl_reset_fifo(fdctrl); } @@ -1798,7 +1801,7 @@ static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direct /* ERROR */ fdctrl->fifo[0] = 0x80 | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl); - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); } } @@ -1817,7 +1820,8 @@ static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction) } fdctrl_reset_fifo(fdctrl); /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); + fdctrl->status0 |= FD_SR0_SEEK; + fdctrl_raise_irq(fdctrl); } static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction) @@ -1834,7 +1838,8 @@ static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction) } fdctrl_reset_fifo(fdctrl); /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); + fdctrl->status0 |= FD_SR0_SEEK; + fdctrl_raise_irq(fdctrl); } static const struct { @@ -1856,7 +1861,7 @@ static const struct { { FD_CMD_SAVE, 0xff, "SAVE", 0, fdctrl_handle_save }, /* part of READ DELETED DATA */ { FD_CMD_READ_DELETED, 0x1f, "READ DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_READ }, { FD_CMD_SCAN_EQUAL, 0x1f, "SCAN EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANE }, - { FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_unimplemented }, + { FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_start_transfer, FD_DIR_VERIFY }, { FD_CMD_SCAN_LOW_OR_EQUAL, 0x1f, "SCAN LOW OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANL }, { FD_CMD_SCAN_HIGH_OR_EQUAL, 0x1f, "SCAN HIGH OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANH }, { FD_CMD_WRITE_DELETED, 0x3f, "WRITE DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_WRITE }, @@ -1920,7 +1925,7 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value) * then from status mode to command mode */ if (fdctrl->data_pos == fdctrl->data_len) - fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); return; } if (fdctrl->data_pos == 0) { @@ -1994,11 +1999,11 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl) drive->fdctrl = fdctrl; if (drive->bs) { - if (bdrv_get_on_error(drive->bs, 0) != BLOCK_ERR_STOP_ENOSPC) { + if (bdrv_get_on_error(drive->bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) { error_report("fdc doesn't support drive option werror"); return -1; } - if (bdrv_get_on_error(drive->bs, 1) != BLOCK_ERR_REPORT) { + if (bdrv_get_on_error(drive->bs, 1) != BLOCKDEV_ON_ERROR_REPORT) { error_report("fdc doesn't support drive option rerror"); return -1; } @@ -2034,7 +2039,7 @@ ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds) } void fdctrl_init_sysbus(qemu_irq irq, int dma_chann, - target_phys_addr_t mmio_base, DriveInfo **fds) + hwaddr mmio_base, DriveInfo **fds) { FDCtrl *fdctrl; DeviceState *dev; @@ -2055,7 +2060,7 @@ void fdctrl_init_sysbus(qemu_irq irq, int dma_chann, sysbus_mmio_map(&sys->busdev, 0, mmio_base); } -void sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base, +void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base, DriveInfo **fds, qemu_irq *fdc_tc) { DeviceState *dev; @@ -15,8 +15,8 @@ typedef enum FDriveType { ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds); void fdctrl_init_sysbus(qemu_irq irq, int dma_chann, - target_phys_addr_t mmio_base, DriveInfo **fds); -void sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base, + hwaddr mmio_base, DriveInfo **fds); +void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base, DriveInfo **fds, qemu_irq *fdc_tc); FDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i); diff --git a/hw/fifo.c b/hw/fifo.c new file mode 100644 index 0000000000..68a955a77b --- /dev/null +++ b/hw/fifo.c @@ -0,0 +1,78 @@ +/* + * Generic FIFO component, implemented as a circular buffer. + * + * Copyright (c) 2012 Peter A. G. Crosthwaite + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "fifo.h" + +void fifo8_create(Fifo8 *fifo, uint32_t capacity) +{ + fifo->data = g_new(uint8_t, capacity); + fifo->capacity = capacity; + fifo->head = 0; + fifo->num = 0; +} + +void fifo8_destroy(Fifo8 *fifo) +{ + g_free(fifo->data); +} + +void fifo8_push(Fifo8 *fifo, uint8_t data) +{ + if (fifo->num == fifo->capacity) { + abort(); + } + fifo->data[(fifo->head + fifo->num) % fifo->capacity] = data; + fifo->num++; +} + +uint8_t fifo8_pop(Fifo8 *fifo) +{ + uint8_t ret; + + if (fifo->num == 0) { + abort(); + } + ret = fifo->data[fifo->head++]; + fifo->head %= fifo->capacity; + fifo->num--; + return ret; +} + +void fifo8_reset(Fifo8 *fifo) +{ + fifo->num = 0; +} + +bool fifo8_is_empty(Fifo8 *fifo) +{ + return (fifo->num == 0); +} + +bool fifo8_is_full(Fifo8 *fifo) +{ + return (fifo->num == fifo->capacity); +} + +const VMStateDescription vmstate_fifo8 = { + .name = "Fifo8", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_VBUFFER_UINT32(data, Fifo8, 1, NULL, 0, capacity), + VMSTATE_UINT32(head, Fifo8), + VMSTATE_UINT32(num, Fifo8), + VMSTATE_END_OF_LIST() + } +}; diff --git a/hw/fifo.h b/hw/fifo.h new file mode 100644 index 0000000000..f23890abf4 --- /dev/null +++ b/hw/fifo.h @@ -0,0 +1,99 @@ +#ifndef FIFO_H +#define FIFO_H + +#include "hw.h" + +typedef struct { + /* All fields are private */ + uint8_t *data; + uint32_t capacity; + uint32_t head; + uint32_t num; +} Fifo8; + +/** + * fifo8_create: + * @fifo: struct Fifo8 to initialise with new FIFO + * @capacity: capacity of the newly created FIFO + * + * Create a FIFO of the specified size. Clients should call fifo8_destroy() + * when finished using the fifo. The FIFO is initially empty. + */ + +void fifo8_create(Fifo8 *fifo, uint32_t capacity); + +/** + * fifo8_destroy: + * @fifo: FIFO to cleanup + * + * Cleanup a FIFO created with fifo8_create(). Frees memory created for FIFO + *storage. The FIFO is no longer usable after this has been called. + */ + +void fifo8_destroy(Fifo8 *fifo); + +/** + * fifo8_push: + * @fifo: FIFO to push to + * @data: data byte to push + * + * Push a data byte to the FIFO. Behaviour is undefined if the FIFO is full. + * Clients are responsible for checking for fullness using fifo8_is_full(). + */ + +void fifo8_push(Fifo8 *fifo, uint8_t data); + +/** + * fifo8_pop: + * @fifo: fifo to pop from + * + * Pop a data byte from the FIFO. Behaviour is undefined if the FIFO is empty. + * Clients are responsible for checking for emptyness using fifo8_is_empty(). + * + * Returns: The popped data byte. + */ + +uint8_t fifo8_pop(Fifo8 *fifo); + +/** + * fifo8_reset: + * @fifo: FIFO to reset + * + * Reset a FIFO. All data is discarded and the FIFO is emptied. + */ + +void fifo8_reset(Fifo8 *fifo); + +/** + * fifo8_is_empty: + * @fifo: FIFO to check + * + * Check if a FIFO is empty. + * + * Returns: True if the fifo is empty, false otherwise. + */ + +bool fifo8_is_empty(Fifo8 *fifo); + +/** + * fifo8_is_full: + * @fifo: FIFO to check + * + * Check if a FIFO is full. + * + * Returns: True if the fifo is full, false otherwise. + */ + +bool fifo8_is_full(Fifo8 *fifo); + +extern const VMStateDescription vmstate_fifo8; + +#define VMSTATE_FIFO8(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(Fifo8), \ + .vmsd = &vmstate_fifo8, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, Fifo8), \ +} + +#endif /* FIFO_H */ diff --git a/hw/flash.h b/hw/flash.h index 9c9e5265b7..920d7596e3 100644 --- a/hw/flash.h +++ b/hw/flash.h @@ -1,22 +1,25 @@ +#ifndef HW_FLASH_H +#define HW_FLASH_H 1 + /* NOR flash devices */ -#include "memory.h" +#include "exec/memory.h" typedef struct pflash_t pflash_t; /* pflash_cfi01.c */ -pflash_t *pflash_cfi01_register(target_phys_addr_t base, +pflash_t *pflash_cfi01_register(hwaddr base, DeviceState *qdev, const char *name, - target_phys_addr_t size, + hwaddr size, BlockDriverState *bs, uint32_t sector_len, int nb_blocs, int width, uint16_t id0, uint16_t id1, uint16_t id2, uint16_t id3, int be); /* pflash_cfi02.c */ -pflash_t *pflash_cfi02_register(target_phys_addr_t base, +pflash_t *pflash_cfi02_register(hwaddr base, DeviceState *qdev, const char *name, - target_phys_addr_t size, + hwaddr size, BlockDriverState *bs, uint32_t sector_len, int nb_blocs, int nb_mappings, int width, uint16_t id0, uint16_t id1, @@ -57,3 +60,5 @@ typedef struct { uint8_t ecc_digest(ECCState *s, uint8_t sample); void ecc_reset(ECCState *s); extern VMStateDescription vmstate_ecc_state; + +#endif diff --git a/hw/framebuffer.c b/hw/framebuffer.c index 85a00a5798..2a870961bc 100644 --- a/hw/framebuffer.c +++ b/hw/framebuffer.c @@ -18,7 +18,7 @@ */ #include "hw.h" -#include "console.h" +#include "ui/console.h" #include "framebuffer.h" /* Render an image from a shared memory framebuffer. */ @@ -26,7 +26,7 @@ void framebuffer_update_display( DisplayState *ds, MemoryRegion *address_space, - target_phys_addr_t base, + hwaddr base, int cols, /* Width in pixels. */ int rows, /* Height in pixels. */ int src_width, /* Length of source line, in bytes. */ @@ -38,7 +38,7 @@ void framebuffer_update_display( int *first_row, /* Input and output. */ int *last_row /* Output only */) { - target_phys_addr_t src_len; + hwaddr src_len; uint8_t *dest; uint8_t *src; uint8_t *src_base; @@ -107,5 +107,4 @@ void framebuffer_update_display( DIRTY_MEMORY_VGA); *first_row = first; *last_row = last; - return; } diff --git a/hw/framebuffer.h b/hw/framebuffer.h index 527a6b85f8..11f53edec0 100644 --- a/hw/framebuffer.h +++ b/hw/framebuffer.h @@ -1,7 +1,7 @@ #ifndef QEMU_FRAMEBUFFER_H #define QEMU_FRAMEBUFFER_H -#include "memory.h" +#include "exec/memory.h" /* Framebuffer device helper routines. */ @@ -10,7 +10,7 @@ typedef void (*drawfn)(void *, uint8_t *, const uint8_t *, int, int); void framebuffer_update_display( DisplayState *ds, MemoryRegion *address_space, - target_phys_addr_t base, + hwaddr base, int cols, int rows, int src_width, diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index 7b3b5769a2..26f7125fe2 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -22,11 +22,12 @@ * THE SOFTWARE. */ #include "hw.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "isa.h" #include "fw_cfg.h" #include "sysbus.h" -#include "qemu-error.h" +#include "qemu/error-report.h" +#include "qemu/config-file.h" /* debug firmware config */ //#define DEBUG_FW_CFG @@ -183,6 +184,30 @@ static void fw_cfg_bootsplash(FWCfgState *s) } } +static void fw_cfg_reboot(FWCfgState *s) +{ + int reboot_timeout = -1; + char *p; + const char *temp; + + /* get user configuration */ + QemuOptsList *plist = qemu_find_opts("boot-opts"); + QemuOpts *opts = QTAILQ_FIRST(&plist->head); + if (opts != NULL) { + temp = qemu_opt_get(opts, "reboot-timeout"); + if (temp != NULL) { + p = (char *)temp; + reboot_timeout = strtol(p, (char **)&p, 10); + } + } + /* validate the input */ + if (reboot_timeout > 0xffff) { + error_report("reboot timeout is larger than 65535, force it to 65535."); + reboot_timeout = 0xffff; + } + fw_cfg_add_file(s, "etc/boot-fail-wait", g_memdup(&reboot_timeout, 4), 4); +} + static void fw_cfg_write(FWCfgState *s, uint8_t value) { int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL); @@ -234,37 +259,37 @@ static uint8_t fw_cfg_read(FWCfgState *s) return ret; } -static uint64_t fw_cfg_data_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t fw_cfg_data_mem_read(void *opaque, hwaddr addr, unsigned size) { return fw_cfg_read(opaque); } -static void fw_cfg_data_mem_write(void *opaque, target_phys_addr_t addr, +static void fw_cfg_data_mem_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { fw_cfg_write(opaque, (uint8_t)value); } -static void fw_cfg_ctl_mem_write(void *opaque, target_phys_addr_t addr, +static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { fw_cfg_select(opaque, (uint16_t)value); } -static bool fw_cfg_ctl_mem_valid(void *opaque, target_phys_addr_t addr, +static bool fw_cfg_ctl_mem_valid(void *opaque, hwaddr addr, unsigned size, bool is_write) { return is_write && size == 2; } -static uint64_t fw_cfg_comb_read(void *opaque, target_phys_addr_t addr, +static uint64_t fw_cfg_comb_read(void *opaque, hwaddr addr, unsigned size) { return fw_cfg_read(opaque); } -static void fw_cfg_comb_write(void *opaque, target_phys_addr_t addr, +static void fw_cfg_comb_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { switch (size) { @@ -277,7 +302,7 @@ static void fw_cfg_comb_write(void *opaque, target_phys_addr_t addr, } } -static bool fw_cfg_comb_valid(void *opaque, target_phys_addr_t addr, +static bool fw_cfg_comb_valid(void *opaque, hwaddr addr, unsigned size, bool is_write) { return (size == 1) || (is_write && size == 2); @@ -470,7 +495,7 @@ static void fw_cfg_machine_ready(struct Notifier *n, void *data) } FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, - target_phys_addr_t ctl_addr, target_phys_addr_t data_addr) + hwaddr ctl_addr, hwaddr data_addr) { DeviceState *dev; SysBusDevice *d; @@ -497,6 +522,7 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, fw_cfg_add_i16(s, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu); fw_cfg_bootsplash(s); + fw_cfg_reboot(s); s->machine_ready.notify = fw_cfg_machine_ready; qemu_add_machine_init_done_notifier(&s->machine_ready); diff --git a/hw/fw_cfg.h b/hw/fw_cfg.h index 856bf9199d..619a39432a 100644 --- a/hw/fw_cfg.h +++ b/hw/fw_cfg.h @@ -63,7 +63,7 @@ int fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback, int fw_cfg_add_file(FWCfgState *s, const char *filename, uint8_t *data, uint32_t len); FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, - target_phys_addr_t crl_addr, target_phys_addr_t data_addr); + hwaddr crl_addr, hwaddr data_addr); #endif /* NO_QEMU_PROTOS */ diff --git a/hw/g364fb.c b/hw/g364fb.c index 3a0b68fbae..b46a044607 100644 --- a/hw/g364fb.c +++ b/hw/g364fb.c @@ -18,8 +18,8 @@ */ #include "hw.h" -#include "console.h" -#include "pixel_ops.h" +#include "ui/console.h" +#include "ui/pixel_ops.h" #include "trace.h" #include "sysbus.h" @@ -197,7 +197,8 @@ static void g364fb_draw_graphic8(G364State *s) reset_dirty(s, page_min, page_max); page_min = (ram_addr_t)-1; page_max = 0; - dpy_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); + dpy_gfx_update(s->ds, xmin, ymin, + xmax - xmin + 1, ymax - ymin + 1); xmin = s->width; xmax = 0; ymin = s->height; @@ -216,7 +217,7 @@ static void g364fb_draw_graphic8(G364State *s) done: if (page_min != (ram_addr_t)-1) { - dpy_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); + dpy_gfx_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); reset_dirty(s, page_min, page_max); } } @@ -238,7 +239,7 @@ static void g364fb_draw_blank(G364State *s) d += ds_get_linesize(s->ds); } - dpy_update(s->ds, 0, 0, s->width, s->height); + dpy_gfx_update(s->ds, 0, 0, s->width, s->height); s->blanked = 1; } @@ -289,10 +290,11 @@ static void g364fb_reset(G364State *s) g364fb_invalidate_display(s); } -static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch) +static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp) { G364State *s = opaque; - int y, x; + int ret, y, x; uint8_t index; uint8_t *data_buffer; FILE *f; @@ -300,40 +302,68 @@ static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch) qemu_flush_coalesced_mmio_buffer(); if (s->depth != 8) { - error_report("g364: unknown guest depth %d", s->depth); + error_setg(errp, "g364: unknown guest depth %d", s->depth); return; } f = fopen(filename, "wb"); - if (!f) + if (!f) { + error_setg(errp, "failed to open file '%s': %s", filename, + strerror(errno)); return; + } if (s->ctla & CTLA_FORCE_BLANK) { /* blank screen */ - fprintf(f, "P4\n%d %d\n", - s->width, s->height); + ret = fprintf(f, "P4\n%d %d\n", s->width, s->height); + if (ret < 0) { + goto write_err; + } for (y = 0; y < s->height; y++) - for (x = 0; x < s->width; x++) - fputc(0, f); + for (x = 0; x < s->width; x++) { + ret = fputc(0, f); + if (ret == EOF) { + goto write_err; + } + } } else { data_buffer = s->vram + s->top_of_screen; - fprintf(f, "P6\n%d %d\n%d\n", - s->width, s->height, 255); + ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); + if (ret < 0) { + goto write_err; + } for (y = 0; y < s->height; y++) for (x = 0; x < s->width; x++, data_buffer++) { index = *data_buffer; - fputc(s->color_palette[index][0], f); - fputc(s->color_palette[index][1], f); - fputc(s->color_palette[index][2], f); + ret = fputc(s->color_palette[index][0], f); + if (ret == EOF) { + goto write_err; + } + ret = fputc(s->color_palette[index][1], f); + if (ret == EOF) { + goto write_err; + } + ret = fputc(s->color_palette[index][2], f); + if (ret == EOF) { + goto write_err; + } } } +out: fclose(f); + return; + +write_err: + error_setg(errp, "failed to write to file '%s': %s", filename, + strerror(errno)); + unlink(filename); + goto out; } /* called for accesses to io ports */ static uint64_t g364fb_ctrl_read(void *opaque, - target_phys_addr_t addr, + hwaddr addr, unsigned int size) { G364State *s = opaque; @@ -395,7 +425,7 @@ static void g364_invalidate_cursor_position(G364State *s) } static void g364fb_ctrl_write(void *opaque, - target_phys_addr_t addr, + hwaddr addr, uint64_t val, unsigned int size) { diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 81ff3a339a..948416632a 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -23,10 +23,9 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "pci/pci_host.h" #include "ppc_mac.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" /* debug Grackle */ //#define DEBUG_GRACKLE @@ -38,9 +37,12 @@ #define GRACKLE_DPRINTF(fmt, ...) #endif +#define GRACKLE_PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(GrackleState, (obj), TYPE_GRACKLE_PCI_HOST_BRIDGE) + typedef struct GrackleState { - SysBusDevice busdev; - PCIHostState host_state; + PCIHostState parent_obj; + MemoryRegion pci_mmio; MemoryRegion pci_hole; } GrackleState; @@ -59,22 +61,20 @@ static void pci_grackle_set_irq(void *opaque, int irq_num, int level) qemu_set_irq(pic[irq_num + 0x15], level); } -static void pci_grackle_reset(void *opaque) -{ -} - PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic, MemoryRegion *address_space_mem, MemoryRegion *address_space_io) { DeviceState *dev; SysBusDevice *s; + PCIHostState *phb; GrackleState *d; - dev = qdev_create(NULL, "grackle-pcihost"); + dev = qdev_create(NULL, TYPE_GRACKLE_PCI_HOST_BRIDGE); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); - d = FROM_SYSBUS(GrackleState, s); + s = SYS_BUS_DEVICE(dev); + phb = PCI_HOST_BRIDGE(dev); + d = GRACKLE_PCI_HOST_BRIDGE(dev); memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL); memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio, @@ -82,36 +82,35 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic, memory_region_add_subregion(address_space_mem, 0x80000000ULL, &d->pci_hole); - d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci", - pci_grackle_set_irq, - pci_grackle_map_irq, - pic, - &d->pci_mmio, - address_space_io, - 0, 4); + phb->bus = pci_register_bus(dev, "pci", + pci_grackle_set_irq, + pci_grackle_map_irq, + pic, + &d->pci_mmio, + address_space_io, + 0, 4); - pci_create_simple(d->host_state.bus, 0, "grackle"); + pci_create_simple(phb->bus, 0, "grackle"); sysbus_mmio_map(s, 0, base); sysbus_mmio_map(s, 1, base + 0x00200000); - return d->host_state.bus; + return phb->bus; } static int pci_grackle_init_device(SysBusDevice *dev) { - GrackleState *s; + PCIHostState *phb; - s = FROM_SYSBUS(GrackleState, dev); + phb = PCI_HOST_BRIDGE(dev); - memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops, - &s->host_state, "pci-conf-idx", 0x1000); - memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops, - &s->host_state, "pci-data-idx", 0x1000); - sysbus_init_mmio(dev, &s->host_state.conf_mem); - sysbus_init_mmio(dev, &s->host_state.data_mem); + memory_region_init_io(&phb->conf_mem, &pci_host_conf_le_ops, + dev, "pci-conf-idx", 0x1000); + memory_region_init_io(&phb->data_mem, &pci_host_data_le_ops, + dev, "pci-data-idx", 0x1000); + sysbus_init_mmio(dev, &phb->conf_mem); + sysbus_init_mmio(dev, &phb->data_mem); - qemu_register_reset(pci_grackle_reset, &s->host_state); return 0; } @@ -134,7 +133,7 @@ static void grackle_pci_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo grackle_pci_info = { +static const TypeInfo grackle_pci_info = { .name = "grackle", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), @@ -150,9 +149,9 @@ static void pci_grackle_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo grackle_pci_host_info = { - .name = "grackle-pcihost", - .parent = TYPE_SYS_BUS_DEVICE, +static const TypeInfo grackle_pci_host_info = { + .name = TYPE_GRACKLE_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(GrackleState), .class_init = pci_grackle_class_init, }; diff --git a/hw/grlib.h b/hw/grlib.h index e1c41378d4..35c22f5994 100644 --- a/hw/grlib.h +++ b/hw/grlib.h @@ -41,7 +41,7 @@ void grlib_irqmp_set_irq(void *opaque, int irq, int level); void grlib_irqmp_ack(DeviceState *dev, int intno); static inline -DeviceState *grlib_irqmp_create(target_phys_addr_t base, +DeviceState *grlib_irqmp_create(hwaddr base, CPUSPARCState *env, qemu_irq **cpu_irqs, uint32_t nr_irqs, @@ -73,7 +73,7 @@ DeviceState *grlib_irqmp_create(target_phys_addr_t base, /* GPTimer */ static inline -DeviceState *grlib_gptimer_create(target_phys_addr_t base, +DeviceState *grlib_gptimer_create(hwaddr base, uint32_t nr_timers, uint32_t freq, qemu_irq *cpu_irqs, @@ -103,7 +103,7 @@ DeviceState *grlib_gptimer_create(target_phys_addr_t base, /* APB UART */ static inline -DeviceState *grlib_apbuart_create(target_phys_addr_t base, +DeviceState *grlib_apbuart_create(hwaddr base, CharDriverState *serial, qemu_irq irq) { diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c index 73fc9894db..88c46780d1 100644 --- a/hw/grlib_apbuart.c +++ b/hw/grlib_apbuart.c @@ -23,7 +23,7 @@ */ #include "sysbus.h" -#include "qemu-char.h" +#include "char/char.h" #include "trace.h" @@ -151,7 +151,7 @@ static void grlib_apbuart_event(void *opaque, int event) } -static uint64_t grlib_apbuart_read(void *opaque, target_phys_addr_t addr, +static uint64_t grlib_apbuart_read(void *opaque, hwaddr addr, unsigned size) { UART *uart = opaque; @@ -181,7 +181,7 @@ static uint64_t grlib_apbuart_read(void *opaque, target_phys_addr_t addr, } } -static void grlib_apbuart_write(void *opaque, target_phys_addr_t addr, +static void grlib_apbuart_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { UART *uart = opaque; diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c index 41770a9e6c..252ba893e3 100644 --- a/hw/grlib_gptimer.c +++ b/hw/grlib_gptimer.c @@ -23,7 +23,7 @@ */ #include "sysbus.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "ptimer.h" #include "trace.h" @@ -155,11 +155,11 @@ static void grlib_gptimer_hit(void *opaque) } } -static uint64_t grlib_gptimer_read(void *opaque, target_phys_addr_t addr, +static uint64_t grlib_gptimer_read(void *opaque, hwaddr addr, unsigned size) { GPTimerUnit *unit = opaque; - target_phys_addr_t timer_addr; + hwaddr timer_addr; int id; uint32_t value = 0; @@ -214,11 +214,11 @@ static uint64_t grlib_gptimer_read(void *opaque, target_phys_addr_t addr, return 0; } -static void grlib_gptimer_write(void *opaque, target_phys_addr_t addr, +static void grlib_gptimer_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { GPTimerUnit *unit = opaque; - target_phys_addr_t timer_addr; + hwaddr timer_addr; int id; addr &= 0xff; diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c index 0f6e65cf20..23a6a02bc5 100644 --- a/hw/grlib_irqmp.c +++ b/hw/grlib_irqmp.c @@ -162,7 +162,7 @@ void grlib_irqmp_set_irq(void *opaque, int irq, int level) } } -static uint64_t grlib_irqmp_read(void *opaque, target_phys_addr_t addr, +static uint64_t grlib_irqmp_read(void *opaque, hwaddr addr, unsigned size) { IRQMP *irqmp = opaque; @@ -226,7 +226,7 @@ static uint64_t grlib_irqmp_read(void *opaque, target_phys_addr_t addr, return 0; } -static void grlib_irqmp_write(void *opaque, target_phys_addr_t addr, +static void grlib_irqmp_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { IRQMP *irqmp = opaque; diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index a2d0e5a2c3..977a2c5e69 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -24,10 +24,10 @@ #include "hw.h" #include "mips.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" #include "pc.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" //#define DEBUG @@ -225,13 +225,18 @@ #define GT_PCI1_SERR1MASK (0xca8 >> 2) #define PCI_MAPPING_ENTRY(regname) \ - target_phys_addr_t regname ##_start; \ - target_phys_addr_t regname ##_length; \ + hwaddr regname ##_start; \ + hwaddr regname ##_length; \ MemoryRegion regname ##_mem +#define TYPE_GT64120_PCI_HOST_BRIDGE "gt64120" + +#define GT64120_PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(GT64120State, (obj), TYPE_GT64120_PCI_HOST_BRIDGE) + typedef struct GT64120State { - SysBusDevice busdev; - PCIHostState pci; + PCIHostState parent_obj; + uint32_t regs[GT_REGS]; PCI_MAPPING_ENTRY(PCI0IO); PCI_MAPPING_ENTRY(ISD); @@ -240,11 +245,11 @@ typedef struct GT64120State { /* Adjust range to avoid touching space which isn't mappable via PCI */ /* XXX: Hardcoded values for Malta: 0x1e000000 - 0x1f100000 0x1fc00000 - 0x1fd00000 */ -static void check_reserved_space (target_phys_addr_t *start, - target_phys_addr_t *length) +static void check_reserved_space (hwaddr *start, + hwaddr *length) { - target_phys_addr_t begin = *start; - target_phys_addr_t end = *start + *length; + hwaddr begin = *start; + hwaddr end = *start + *length; if (end >= 0x1e000000LL && end < 0x1f100000LL) end = 0x1e000000LL; @@ -266,8 +271,8 @@ static void check_reserved_space (target_phys_addr_t *start, static void gt64120_isd_mapping(GT64120State *s) { - target_phys_addr_t start = s->regs[GT_ISD] << 21; - target_phys_addr_t length = 0x1000; + hwaddr start = s->regs[GT_ISD] << 21; + hwaddr length = 0x1000; if (s->ISD_length) { memory_region_del_subregion(get_system_memory(), &s->ISD_mem); @@ -306,10 +311,11 @@ static void gt64120_pci_mapping(GT64120State *s) } } -static void gt64120_writel (void *opaque, target_phys_addr_t addr, +static void gt64120_writel (void *opaque, hwaddr addr, uint64_t val, unsigned size) { GT64120State *s = opaque; + PCIHostState *phb = PCI_HOST_BRIDGE(s); uint32_t saddr; if (!(s->regs[GT_CPU] & 0x00001000)) @@ -530,13 +536,15 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, /* not implemented */ break; case GT_PCI0_CFGADDR: - s->pci.config_reg = val & 0x80fffffc; + phb->config_reg = val & 0x80fffffc; break; case GT_PCI0_CFGDATA: - if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci.config_reg & 0x00fff800)) + if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) { val = bswap32(val); - if (s->pci.config_reg & (1u << 31)) - pci_data_write(s->pci.bus, s->pci.config_reg, val, 4); + } + if (phb->config_reg & (1u << 31)) { + pci_data_write(phb->bus, phb->config_reg, val, 4); + } break; /* Interrupts */ @@ -586,9 +594,10 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr, } static uint64_t gt64120_readl (void *opaque, - target_phys_addr_t addr, unsigned size) + hwaddr addr, unsigned size) { GT64120State *s = opaque; + PCIHostState *phb = PCI_HOST_BRIDGE(s); uint32_t val; uint32_t saddr; @@ -770,15 +779,17 @@ static uint64_t gt64120_readl (void *opaque, /* PCI Internal */ case GT_PCI0_CFGADDR: - val = s->pci.config_reg; + val = phb->config_reg; break; case GT_PCI0_CFGDATA: - if (!(s->pci.config_reg & (1 << 31))) + if (!(phb->config_reg & (1 << 31))) { val = 0xffffffff; - else - val = pci_data_read(s->pci.bus, s->pci.config_reg, 4); - if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci.config_reg & 0x00fff800)) + } else { + val = pci_data_read(phb->bus, phb->config_reg, 4); + } + if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) { val = bswap32(val); + } break; case GT_PCI0_CMD: @@ -1083,31 +1094,31 @@ static void gt64120_reset(void *opaque) PCIBus *gt64120_register(qemu_irq *pic) { - SysBusDevice *s; GT64120State *d; + PCIHostState *phb; DeviceState *dev; - dev = qdev_create(NULL, "gt64120"); + dev = qdev_create(NULL, TYPE_GT64120_PCI_HOST_BRIDGE); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); - d = FROM_SYSBUS(GT64120State, s); - d->pci.bus = pci_register_bus(&d->busdev.qdev, "pci", - gt64120_pci_set_irq, gt64120_pci_map_irq, - pic, - get_system_memory(), - get_system_io(), - PCI_DEVFN(18, 0), 4); + d = GT64120_PCI_HOST_BRIDGE(dev); + phb = PCI_HOST_BRIDGE(dev); + phb->bus = pci_register_bus(dev, "pci", + gt64120_pci_set_irq, gt64120_pci_map_irq, + pic, + get_system_memory(), + get_system_io(), + PCI_DEVFN(18, 0), 4); memory_region_init_io(&d->ISD_mem, &isd_mem_ops, d, "isd-mem", 0x1000); - pci_create_simple(d->pci.bus, PCI_DEVFN(0, 0), "gt64120_pci"); - return d->pci.bus; + pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "gt64120_pci"); + return phb->bus; } static int gt64120_init(SysBusDevice *dev) { GT64120State *s; - s = FROM_SYSBUS(GT64120State, dev); + s = GT64120_PCI_HOST_BRIDGE(dev); /* FIXME: This value is computed from registers during reset, but some devices (e.g. VGA card) need to know it when they are registered. @@ -1147,7 +1158,7 @@ static void gt64120_pci_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_HOST; } -static TypeInfo gt64120_pci_info = { +static const TypeInfo gt64120_pci_info = { .name = "gt64120_pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), @@ -1161,9 +1172,9 @@ static void gt64120_class_init(ObjectClass *klass, void *data) sdc->init = gt64120_init; } -static TypeInfo gt64120_info = { - .name = "gt64120", - .parent = TYPE_SYS_BUS_DEVICE, +static const TypeInfo gt64120_info = { + .name = TYPE_GT64120_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(GT64120State), .class_init = gt64120_class_init, }; diff --git a/hw/gumstix.c b/hw/gumstix.c index 13a36ea5c5..6fb068386c 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -36,19 +36,16 @@ #include "hw.h" #include "pxa.h" -#include "net.h" +#include "net/net.h" #include "flash.h" #include "devices.h" #include "boards.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" static const int sector_len = 128 * 1024; -static void connex_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void connex_init(QEMUMachineInitArgs *args) { PXA2xxState *cpu; DriveInfo *dinfo; @@ -84,11 +81,9 @@ static void connex_init(ram_addr_t ram_size, qdev_get_gpio_in(cpu->gpio, 36)); } -static void verdex_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void verdex_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; PXA2xxState *cpu; DriveInfo *dinfo; int be; diff --git a/hw/hd-geometry.c b/hw/hd-geometry.c index 1cdb9fb753..c30514364f 100644 --- a/hw/hd-geometry.c +++ b/hw/hd-geometry.c @@ -30,7 +30,7 @@ * THE SOFTWARE. */ -#include "block.h" +#include "block/block.h" #include "hw/block-common.h" #include "trace.h" diff --git a/hw/hda-audio.c b/hw/hda-audio.c index 36761dd2de..92a91b5ab1 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -18,7 +18,7 @@ */ #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "intel-hda.h" #include "intel-hda-defs.h" #include "audio/audio.h" diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c index 16f48d12e1..b9ec8e7b4d 100644 --- a/hw/heathrow_pic.c +++ b/hw/heathrow_pic.c @@ -63,7 +63,7 @@ static void heathrow_pic_update(HeathrowPICS *s) } } -static void pic_write(void *opaque, target_phys_addr_t addr, +static void pic_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { HeathrowPICS *s = opaque; @@ -91,7 +91,7 @@ static void pic_write(void *opaque, target_phys_addr_t addr, } } -static uint64_t pic_read(void *opaque, target_phys_addr_t addr, +static uint64_t pic_read(void *opaque, hwaddr addr, unsigned size) { HeathrowPICS *s = opaque; @@ -23,8 +23,8 @@ * THE SOFTWARE. */ #include "hw.h" -#include "console.h" -#include "qemu-timer.h" +#include "ui/console.h" +#include "qemu/timer.h" #include "hid.h" #define HID_USAGE_ERROR_ROLLOVER 0x01 @@ -71,12 +71,38 @@ static const uint8_t hid_usage_keys[0x100] = { bool hid_has_events(HIDState *hs) { - return hs->n > 0; + return hs->n > 0 || hs->idle_pending; } -void hid_set_next_idle(HIDState *hs, int64_t curtime) +static void hid_idle_timer(void *opaque) { - hs->next_idle_clock = curtime + (get_ticks_per_sec() * hs->idle * 4) / 1000; + HIDState *hs = opaque; + + hs->idle_pending = true; + hs->event(hs); +} + +static void hid_del_idle_timer(HIDState *hs) +{ + if (hs->idle_timer) { + qemu_del_timer(hs->idle_timer); + qemu_free_timer(hs->idle_timer); + hs->idle_timer = NULL; + } +} + +void hid_set_next_idle(HIDState *hs) +{ + if (hs->idle) { + uint64_t expire_time = qemu_get_clock_ns(vm_clock) + + get_ticks_per_sec() * hs->idle * 4 / 1000; + if (!hs->idle_timer) { + hs->idle_timer = qemu_new_timer_ns(vm_clock, hid_idle_timer, hs); + } + qemu_mod_timer_ns(hs->idle_timer, expire_time); + } else { + hid_del_idle_timer(hs); + } } static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons) @@ -232,6 +258,8 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) int index; HIDPointerEvent *e; + hs->idle_pending = false; + hid_pointer_activate(hs); /* When the buffer is empty, return the last event. Relative @@ -319,6 +347,8 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len) { + hs->idle_pending = false; + if (len < 2) { return 0; } @@ -377,6 +407,8 @@ void hid_reset(HIDState *hs) hs->n = 0; hs->protocol = 1; hs->idle = 0; + hs->idle_pending = false; + hid_del_idle_timer(hs); } void hid_free(HIDState *hs) @@ -390,6 +422,7 @@ void hid_free(HIDState *hs) qemu_remove_mouse_event_handler(hs->ptr.eh_entry); break; } + hid_del_idle_timer(hs); } void hid_init(HIDState *hs, int kind, HIDEventFunc event) @@ -412,9 +445,7 @@ static int hid_post_load(void *opaque, int version_id) { HIDState *s = opaque; - if (s->idle) { - hid_set_next_idle(s, qemu_get_clock_ns(vm_clock)); - } + hid_set_next_idle(s); return 0; } @@ -1,7 +1,7 @@ #ifndef QEMU_HID_H #define QEMU_HID_H -#include "vmstate.h" +#include "migration/vmstate.h" #define HID_MOUSE 1 #define HID_TABLET 2 @@ -43,7 +43,8 @@ struct HIDState { int kind; int32_t protocol; uint8_t idle; - int64_t next_idle_clock; + bool idle_pending; + QEMUTimer *idle_timer; HIDEventFunc event; }; @@ -52,7 +53,7 @@ void hid_reset(HIDState *hs); void hid_free(HIDState *hs); bool hid_has_events(HIDState *hs); -void hid_set_next_idle(HIDState *hs, int64_t curtime); +void hid_set_next_idle(HIDState *hs); void hid_pointer_activate(HIDState *hs); int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len); int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len); diff --git a/hw/highbank.c b/hw/highbank.c index 11aa1312c0..6005622f3a 100644 --- a/hw/highbank.c +++ b/hw/highbank.c @@ -21,12 +21,12 @@ #include "arm-misc.h" #include "devices.h" #include "loader.h" -#include "net.h" -#include "sysemu.h" +#include "net/net.h" +#include "sysemu/sysemu.h" #include "boards.h" #include "sysbus.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" #define SMP_BOOT_ADDR 0x100 #define SMP_BOOT_REG 0x40 @@ -44,9 +44,12 @@ static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) 0xe210000f, /* ands r0, r0, #0x0f */ 0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */ 0xe0830200, /* add r0, r3, r0, lsl #4 */ - 0xe59f2018, /* ldr r2, privbase */ + 0xe59f2024, /* ldr r2, privbase */ 0xe3a01001, /* mov r1, #1 */ - 0xe5821100, /* str r1, [r2, #256] */ + 0xe5821100, /* str r1, [r2, #256] - set GICC_CTLR.Enable */ + 0xe3a010ff, /* mov r1, #0xff */ + 0xe5821104, /* str r1, [r2, #260] - set GICC_PMR.Priority to 0xff */ + 0xf57ff04f, /* dsb */ 0xe320f003, /* wfi */ 0xe5901000, /* ldr r1, [r0] */ 0xe1110001, /* tst r1, r1 */ @@ -79,7 +82,7 @@ static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info) } #define NUM_REGS 0x200 -static void hb_regs_write(void *opaque, target_phys_addr_t offset, +static void hb_regs_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { uint32_t *regs = opaque; @@ -95,7 +98,7 @@ static void hb_regs_write(void *opaque, target_phys_addr_t offset, regs[offset/4] = value; } -static uint64_t hb_regs_read(void *opaque, target_phys_addr_t offset, +static uint64_t hb_regs_read(void *opaque, hwaddr offset, unsigned size) { uint32_t *regs = opaque; @@ -187,11 +190,13 @@ static struct arm_boot_info highbank_binfo; * 32-bit host, set the reg value of memory to 0xf7ff00000 in the * device tree and pass -m 2047 to QEMU. */ -static void highbank_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void highbank_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; DeviceState *dev; SysBusDevice *busdev; qemu_irq *irqp; @@ -324,7 +329,7 @@ static QEMUMachine highbank_machine = { .name = "highbank", .desc = "Calxeda Highbank (ECX-1000)", .init = highbank_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, .max_cpus = 4, }; @@ -26,8 +26,8 @@ #include "hw.h" #include "pc.h" -#include "console.h" -#include "qemu-timer.h" +#include "ui/console.h" +#include "qemu/timer.h" #include "hpet_emul.h" #include "sysbus.h" #include "mc146818rtc.h" @@ -370,20 +370,20 @@ static void hpet_del_timer(HPETTimer *t) } #ifdef HPET_DEBUG -static uint32_t hpet_ram_readb(void *opaque, target_phys_addr_t addr) +static uint32_t hpet_ram_readb(void *opaque, hwaddr addr) { printf("qemu: hpet_read b at %" PRIx64 "\n", addr); return 0; } -static uint32_t hpet_ram_readw(void *opaque, target_phys_addr_t addr) +static uint32_t hpet_ram_readw(void *opaque, hwaddr addr) { printf("qemu: hpet_read w at %" PRIx64 "\n", addr); return 0; } #endif -static uint64_t hpet_ram_read(void *opaque, target_phys_addr_t addr, +static uint64_t hpet_ram_read(void *opaque, hwaddr addr, unsigned size) { HPETState *s = opaque; @@ -455,7 +455,7 @@ static uint64_t hpet_ram_read(void *opaque, target_phys_addr_t addr, return 0; } -static void hpet_ram_write(void *opaque, target_phys_addr_t addr, +static void hpet_ram_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { int i; @@ -4,14 +4,16 @@ #include "qemu-common.h" -#if defined(TARGET_PHYS_ADDR_BITS) && !defined(NEED_CPU_H) -#include "cpu-common.h" +#if !defined(CONFIG_USER_ONLY) && !defined(NEED_CPU_H) +#include "exec/cpu-common.h" #endif -#include "ioport.h" +#include "exec/ioport.h" #include "irq.h" -#include "qemu-file.h" -#include "vmstate.h" +#include "block/aio.h" +#include "migration/qemu-file.h" +#include "migration/vmstate.h" +#include "qemu/log.h" #ifdef NEED_CPU_H #if TARGET_LONG_BITS == 64 @@ -73,9 +73,6 @@ void *wm8750_dac_buffer(void *opaque, int samples); void wm8750_dac_commit(void *opaque); void wm8750_set_bclk_in(void *opaque, int new_hz); -/* tmp105.c */ -void tmp105_set(I2CSlave *i2c, int temp); - /* lm832x.c */ void lm832x_key_event(DeviceState *dev, int key, int state); diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 8c764bbfef..025803aa66 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -2,14 +2,16 @@ obj-y += mc146818rtc.o pc.o obj-y += apic_common.o apic.o kvmvapic.o obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o obj-y += vmport.o -obj-y += pci-hotplug.o smbios.o wdt_ib700.o -obj-y += debugcon.o multiboot.o +obj-y += pci/pci-hotplug.o smbios.o wdt_ib700.o +obj-y += debugcon.o debugexit.o multiboot.o obj-y += pc_piix.o obj-y += pc_sysfw.o +obj-y += lpc_ich9.o q35.o pc_q35.o obj-$(CONFIG_XEN) += xen_platform.o xen_apic.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o obj-y += kvm/ obj-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o +obj-y += pc-testdev.o obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/i82378.c b/hw/i82378.c index 9b11d907eb..c6b0b5ec55 100644 --- a/hw/i82378.c +++ b/hw/i82378.c @@ -17,7 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "pci.h" +#include "pci/pci.h" #include "pc.h" #include "i8254.h" #include "pcspk.h" @@ -59,7 +59,7 @@ static const VMStateDescription vmstate_pci_i82378 = { }, }; -static void i82378_io_write(void *opaque, target_phys_addr_t addr, +static void i82378_io_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size) { switch (size) { @@ -83,7 +83,7 @@ static void i82378_io_write(void *opaque, target_phys_addr_t addr, } } -static uint64_t i82378_io_read(void *opaque, target_phys_addr_t addr, +static uint64_t i82378_io_read(void *opaque, hwaddr addr, unsigned int size) { DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr); @@ -105,7 +105,7 @@ static const MemoryRegionOps i82378_io_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static void i82378_mem_write(void *opaque, target_phys_addr_t addr, +static void i82378_mem_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size) { switch (size) { @@ -129,7 +129,7 @@ static void i82378_mem_write(void *opaque, target_phys_addr_t addr, } } -static uint64_t i82378_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t i82378_mem_read(void *opaque, hwaddr addr, unsigned int size) { DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr); @@ -225,7 +225,6 @@ static int pci_i82378_init(PCIDevice *dev) pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io); memory_region_init_io(&s->mem, &i82378_mem_ops, s, "i82378-mem", 0x01000000); - memory_region_set_coalescing(&s->mem); pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem); /* Make I/O address read only */ diff --git a/hw/i8254.c b/hw/i8254.c index 77bd5e8222..7c2aa6238d 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -24,7 +24,7 @@ #include "hw.h" #include "pc.h" #include "isa.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "i8254.h" #include "i8254_internal.h" @@ -111,7 +111,8 @@ static void pit_latch_count(PITChannelState *s) } } -static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void pit_ioport_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { PITCommonState *pit = opaque; int channel, access; @@ -178,7 +179,8 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t pit_ioport_read(void *opaque, uint32_t addr) +static uint64_t pit_ioport_read(void *opaque, hwaddr addr, + unsigned size) { PITCommonState *pit = opaque; int ret, count; @@ -290,14 +292,14 @@ static void pit_irq_control(void *opaque, int n, int enable) } } -static const MemoryRegionPortio pit_portio[] = { - { 0, 4, 1, .write = pit_ioport_write }, - { 0, 3, 1, .read = pit_ioport_read }, - PORTIO_END_OF_LIST() -}; - static const MemoryRegionOps pit_ioport_ops = { - .old_portio = pit_portio + .read = pit_ioport_read, + .write = pit_ioport_write, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static void pit_post_load(PITCommonState *s) diff --git a/hw/i8254_common.c b/hw/i8254_common.c index a03d7cd458..08ab8d14bd 100644 --- a/hw/i8254_common.c +++ b/hw/i8254_common.c @@ -25,7 +25,7 @@ #include "hw.h" #include "pc.h" #include "isa.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "i8254.h" #include "i8254_internal.h" diff --git a/hw/i8259.c b/hw/i8259.c index 53daf78652..8fc6339250 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -24,8 +24,8 @@ #include "hw.h" #include "pc.h" #include "isa.h" -#include "monitor.h" -#include "qemu-timer.h" +#include "monitor/monitor.h" +#include "qemu/timer.h" #include "i8259_internal.h" /* debug PIC */ @@ -235,7 +235,7 @@ static void pic_reset(DeviceState *dev) pic_init_reset(s); } -static void pic_ioport_write(void *opaque, target_phys_addr_t addr64, +static void pic_ioport_write(void *opaque, hwaddr addr64, uint64_t val64, unsigned size) { PICCommonState *s = opaque; @@ -329,7 +329,7 @@ static void pic_ioport_write(void *opaque, target_phys_addr_t addr64, } } -static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr, +static uint64_t pic_ioport_read(void *opaque, hwaddr addr, unsigned size) { PICCommonState *s = opaque; @@ -366,14 +366,14 @@ int pic_get_output(DeviceState *d) return (pic_get_irq(s) >= 0); } -static void elcr_ioport_write(void *opaque, target_phys_addr_t addr, +static void elcr_ioport_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { PICCommonState *s = opaque; s->elcr = val & s->elcr_mask; } -static uint64_t elcr_ioport_read(void *opaque, target_phys_addr_t addr, +static uint64_t elcr_ioport_read(void *opaque, hwaddr addr, unsigned size) { PICCommonState *s = opaque; diff --git a/hw/i8259_internal.h b/hw/i8259_internal.h index 4137b61703..8785b1da3f 100644 --- a/hw/i8259_internal.h +++ b/hw/i8259_internal.h @@ -33,7 +33,7 @@ typedef struct PICCommonState PICCommonState; #define TYPE_PIC_COMMON "pic-common" #define PIC_COMMON(obj) \ - OBJECT_CHECK(PICCommon, (obj), TYPE_PIC_COMMON) + OBJECT_CHECK(PICCommonState, (obj), TYPE_PIC_COMMON) #define PIC_COMMON_CLASS(klass) \ OBJECT_CLASS_CHECK(PICCommonClass, (klass), TYPE_PIC_COMMON) #define PIC_COMMON_GET_CLASS(obj) \ diff --git a/hw/i82801b11.c b/hw/i82801b11.c new file mode 100644 index 0000000000..3dc10000a4 --- /dev/null +++ b/hw/i82801b11.c @@ -0,0 +1,125 @@ +/* + * 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. + */ +/* + * QEMU i82801b11 dmi-to-pci Bridge Emulation + * + * Copyright (c) 2009, 2010, 2011 + * Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * Copyright (C) 2012 Jason Baron <jbaron@redhat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/> + */ + +#include "pci/pci.h" +#include "ich9.h" + + +/*****************************************************************************/ +/* ICH9 DMI-to-PCI bridge */ +#define I82801ba_SSVID_OFFSET 0x50 +#define I82801ba_SSVID_SVID 0 +#define I82801ba_SSVID_SSID 0 + +typedef struct I82801b11Bridge { + PCIBridge br; +} I82801b11Bridge; + +static int i82801b11_bridge_initfn(PCIDevice *d) +{ + int rc; + + rc = pci_bridge_initfn(d); + if (rc < 0) { + return rc; + } + + rc = pci_bridge_ssvid_init(d, I82801ba_SSVID_OFFSET, + I82801ba_SSVID_SVID, I82801ba_SSVID_SSID); + if (rc < 0) { + goto err_bridge; + } + pci_config_set_prog_interface(d->config, PCI_CLASS_BRDIGE_PCI_INF_SUB); + return 0; + +err_bridge: + pci_bridge_exitfn(d); + + return rc; +} + +static void i82801b11_bridge_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->is_bridge = 1; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82801BA_11; + k->revision = ICH9_D2P_A2_REVISION; + k->init = i82801b11_bridge_initfn; +} + +static const TypeInfo i82801b11_bridge_info = { + .name = "i82801b11-bridge", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(I82801b11Bridge), + .class_init = i82801b11_bridge_class_init, +}; + +PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus) +{ + PCIDevice *d; + PCIBridge *br; + char buf[16]; + DeviceState *qdev; + + d = pci_create_multifunction(bus, devfn, true, "i82801b11-bridge"); + if (!d) { + return NULL; + } + br = DO_UPCAST(PCIBridge, dev, d); + qdev = &br->dev.qdev; + + snprintf(buf, sizeof(buf), "pci.%d", sec_bus); + pci_bridge_map_irq(br, buf, pci_swizzle_map_irq_fn); + qdev_init_nofail(qdev); + + return pci_bridge_get_sec_bus(br); +} + +static void d2pbr_register(void) +{ + type_register_static(&i82801b11_bridge_info); +} + +type_init(d2pbr_register); diff --git a/hw/ich9.h b/hw/ich9.h new file mode 100644 index 0000000000..b8d8e6d3df --- /dev/null +++ b/hw/ich9.h @@ -0,0 +1,208 @@ +#ifndef HW_ICH9_H +#define HW_ICH9_H + +#include "hw.h" +#include "qemu/range.h" +#include "isa.h" +#include "sysbus.h" +#include "pc.h" +#include "apm.h" +#include "ioapic.h" +#include "pci/pci.h" +#include "pci/pcie_host.h" +#include "pci/pci_bridge.h" +#include "acpi.h" +#include "acpi_ich9.h" +#include "pam.h" +#include "pci/pci_bus.h" + +void ich9_lpc_set_irq(void *opaque, int irq_num, int level); +int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx); +void ich9_lpc_pm_init(PCIDevice *pci_lpc, qemu_irq cmos_s3); +PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus); +i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base); + +#define ICH9_CC_SIZE (16 * 1024) /* 16KB */ + +#define TYPE_ICH9_LPC_DEVICE "ICH9 LPC" +#define ICH9_LPC_DEVICE(obj) \ + OBJECT_CHECK(ICH9LPCState, (obj), TYPE_ICH9_LPC_DEVICE) + +typedef struct ICH9LPCState { + /* ICH9 LPC PCI to ISA bridge */ + PCIDevice d; + + /* (pci device, intx) -> pirq + * In real chipset case, the unused slots are never used + * as ICH9 supports only D25-D32 irq routing. + * On the other hand in qemu case, any slot/function can be populated + * via command line option. + * So fallback interrupt routing for any devices in any slots is necessary. + */ + uint8_t irr[PCI_SLOT_MAX][PCI_NUM_PINS]; + + APMState apm; + ICH9LPCPMRegs pm; + uint32_t sci_level; /* track sci level */ + + /* 10.1 Chipset Configuration registers(Memory Space) + which is pointed by RCBA */ + uint8_t chip_config[ICH9_CC_SIZE]; + /* isa bus */ + ISABus *isa_bus; + MemoryRegion rbca_mem; + Notifier machine_ready; + + qemu_irq *pic; + qemu_irq *ioapic; +} ICH9LPCState; + +#define Q35_MASK(bit, ms_bit, ls_bit) \ +((uint##bit##_t)(((1ULL << ((ms_bit) + 1)) - 1) & ~((1ULL << ls_bit) - 1))) + +/* ICH9: Chipset Configuration Registers */ +#define ICH9_CC_ADDR_MASK (ICH9_CC_SIZE - 1) + +#define ICH9_CC +#define ICH9_CC_D28IP 0x310C +#define ICH9_CC_D28IP_SHIFT 4 +#define ICH9_CC_D28IP_MASK 0xf +#define ICH9_CC_D28IP_DEFAULT 0x00214321 +#define ICH9_CC_D31IR 0x3140 +#define ICH9_CC_D30IR 0x3142 +#define ICH9_CC_D29IR 0x3144 +#define ICH9_CC_D28IR 0x3146 +#define ICH9_CC_D27IR 0x3148 +#define ICH9_CC_D26IR 0x314C +#define ICH9_CC_D25IR 0x3150 +#define ICH9_CC_DIR_DEFAULT 0x3210 +#define ICH9_CC_D30IR_DEFAULT 0x0 +#define ICH9_CC_DIR_SHIFT 4 +#define ICH9_CC_DIR_MASK 0x7 +#define ICH9_CC_OIC 0x31FF +#define ICH9_CC_OIC_AEN 0x1 + +/* D28:F[0-5] */ +#define ICH9_PCIE_DEV 28 +#define ICH9_PCIE_FUNC_MAX 6 + + +/* D29:F0 USB UHCI Controller #1 */ +#define ICH9_USB_UHCI1_DEV 29 +#define ICH9_USB_UHCI1_FUNC 0 + +/* D30:F0 DMI-to-PCI brdige */ +#define ICH9_D2P_BRIDGE "ICH9 D2P BRIDGE" +#define ICH9_D2P_BRIDGE_SAVEVM_VERSION 0 + +#define ICH9_D2P_BRIDGE_DEV 30 +#define ICH9_D2P_BRIDGE_FUNC 0 + +#define ICH9_D2P_SECONDARY_DEFAULT (256 - 8) + +#define ICH9_D2P_A2_REVISION 0x92 + + +/* D31:F1 LPC controller */ +#define ICH9_A2_LPC "ICH9 A2 LPC" +#define ICH9_A2_LPC_SAVEVM_VERSION 0 + +#define ICH9_LPC_DEV 31 +#define ICH9_LPC_FUNC 0 + +#define ICH9_A2_LPC_REVISION 0x2 +#define ICH9_LPC_NB_PIRQS 8 /* PCI A-H */ + +#define ICH9_LPC_PMBASE 0x40 +#define ICH9_LPC_PMBASE_BASE_ADDRESS_MASK Q35_MASK(32, 15, 7) +#define ICH9_LPC_PMBASE_RTE 0x1 +#define ICH9_LPC_PMBASE_DEFAULT 0x1 +#define ICH9_LPC_ACPI_CTRL 0x44 +#define ICH9_LPC_ACPI_CTRL_ACPI_EN 0x80 +#define ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK Q35_MASK(8, 2, 0) +#define ICH9_LPC_ACPI_CTRL_9 0x0 +#define ICH9_LPC_ACPI_CTRL_10 0x1 +#define ICH9_LPC_ACPI_CTRL_11 0x2 +#define ICH9_LPC_ACPI_CTRL_20 0x4 +#define ICH9_LPC_ACPI_CTRL_21 0x5 +#define ICH9_LPC_ACPI_CTRL_DEFAULT 0x0 + +#define ICH9_LPC_PIRQA_ROUT 0x60 +#define ICH9_LPC_PIRQB_ROUT 0x61 +#define ICH9_LPC_PIRQC_ROUT 0x62 +#define ICH9_LPC_PIRQD_ROUT 0x63 + +#define ICH9_LPC_PIRQE_ROUT 0x68 +#define ICH9_LPC_PIRQF_ROUT 0x69 +#define ICH9_LPC_PIRQG_ROUT 0x6a +#define ICH9_LPC_PIRQH_ROUT 0x6b + +#define ICH9_LPC_PIRQ_ROUT_IRQEN 0x80 +#define ICH9_LPC_PIRQ_ROUT_MASK Q35_MASK(8, 3, 0) +#define ICH9_LPC_PIRQ_ROUT_DEFAULT 0x80 + +#define ICH9_LPC_RCBA 0xf0 +#define ICH9_LPC_RCBA_BA_MASK Q35_MASK(32, 31, 14) +#define ICH9_LPC_RCBA_EN 0x1 +#define ICH9_LPC_RCBA_DEFAULT 0x0 + +#define ICH9_LPC_PIC_NUM_PINS 16 +#define ICH9_LPC_IOAPIC_NUM_PINS 24 + +/* D31:F2 SATA Controller #1 */ +#define ICH9_SATA1_DEV 31 +#define ICH9_SATA1_FUNC 2 + +/* D30:F1 power management I/O registers + offset from the address ICH9_LPC_PMBASE */ + +/* ICH9 LPC PM I/O registers are 128 ports and 128-aligned */ +#define ICH9_PMIO_SIZE 128 +#define ICH9_PMIO_MASK (ICH9_PMIO_SIZE - 1) + +#define ICH9_PMIO_PM1_STS 0x00 +#define ICH9_PMIO_PM1_EN 0x02 +#define ICH9_PMIO_PM1_CNT 0x04 +#define ICH9_PMIO_PM1_TMR 0x08 +#define ICH9_PMIO_GPE0_STS 0x20 +#define ICH9_PMIO_GPE0_EN 0x28 +#define ICH9_PMIO_GPE0_LEN 16 +#define ICH9_PMIO_SMI_EN 0x30 +#define ICH9_PMIO_SMI_EN_APMC_EN (1 << 5) +#define ICH9_PMIO_SMI_STS 0x34 + +/* FADT ACPI_ENABLE/ACPI_DISABLE */ +#define ICH9_APM_ACPI_ENABLE 0x2 +#define ICH9_APM_ACPI_DISABLE 0x3 + + +/* D31:F3 SMBus controller */ +#define ICH9_A2_SMB_REVISION 0x02 +#define ICH9_SMB_PI 0x00 + +#define ICH9_SMB_SMBMBAR0 0x10 +#define ICH9_SMB_SMBMBAR1 0x14 +#define ICH9_SMB_SMBM_BAR 0 +#define ICH9_SMB_SMBM_SIZE (1 << 8) +#define ICH9_SMB_SMB_BASE 0x20 +#define ICH9_SMB_SMB_BASE_BAR 4 +#define ICH9_SMB_SMB_BASE_SIZE (1 << 5) +#define ICH9_SMB_HOSTC 0x40 +#define ICH9_SMB_HOSTC_SSRESET ((uint8_t)(1 << 3)) +#define ICH9_SMB_HOSTC_I2C_EN ((uint8_t)(1 << 2)) +#define ICH9_SMB_HOSTC_SMB_SMI_EN ((uint8_t)(1 << 1)) +#define ICH9_SMB_HOSTC_HST_EN ((uint8_t)(1 << 0)) + +/* D31:F3 SMBus I/O and memory mapped I/O registers */ +#define ICH9_SMB_DEV 31 +#define ICH9_SMB_FUNC 3 + +#define ICH9_SMB_HST_STS 0x00 +#define ICH9_SMB_HST_CNT 0x02 +#define ICH9_SMB_HST_CMD 0x03 +#define ICH9_SMB_XMIT_SLVA 0x04 +#define ICH9_SMB_HST_D0 0x05 +#define ICH9_SMB_HST_D1 0x06 +#define ICH9_SMB_HOST_BLOCK_DB 0x07 + +#endif /* HW_ICH9_H */ @@ -2,8 +2,8 @@ #define HW_IDE_H #include "isa.h" -#include "pci.h" -#include "memory.h" +#include "pci/pci.h" +#include "exec/memory.h" #define MAX_IDE_DEVS 2 @@ -24,7 +24,7 @@ MemoryRegion *pmac_ide_init (DriveInfo **hd_table, qemu_irq irq, void *dbdma, int channel, qemu_irq dma_irq); /* ide-mmio.c */ -void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2, +void mmio_ide_init (hwaddr membase, hwaddr membase2, MemoryRegion *address_space, qemu_irq irq, int shift, DriveInfo *hd0, DriveInfo *hd1); diff --git a/hw/ide/Makefile.objs b/hw/ide/Makefile.objs index cf718dd016..5c8c22aad7 100644 --- a/hw/ide/Makefile.objs +++ b/hw/ide/Makefile.objs @@ -1,10 +1,10 @@ -hw-obj-$(CONFIG_IDE_CORE) += core.o atapi.o -hw-obj-$(CONFIG_IDE_QDEV) += qdev.o -hw-obj-$(CONFIG_IDE_PCI) += pci.o -hw-obj-$(CONFIG_IDE_ISA) += isa.o -hw-obj-$(CONFIG_IDE_PIIX) += piix.o -hw-obj-$(CONFIG_IDE_CMD646) += cmd646.o -hw-obj-$(CONFIG_IDE_MACIO) += macio.o -hw-obj-$(CONFIG_IDE_VIA) += via.o -hw-obj-$(CONFIG_AHCI) += ahci.o -hw-obj-$(CONFIG_AHCI) += ich.o +common-obj-$(CONFIG_IDE_CORE) += core.o atapi.o +common-obj-$(CONFIG_IDE_QDEV) += qdev.o +common-obj-$(CONFIG_IDE_PCI) += pci.o +common-obj-$(CONFIG_IDE_ISA) += isa.o +common-obj-$(CONFIG_IDE_PIIX) += piix.o +common-obj-$(CONFIG_IDE_CMD646) += cmd646.o +common-obj-$(CONFIG_IDE_MACIO) += macio.o +common-obj-$(CONFIG_IDE_VIA) += via.o +common-obj-$(CONFIG_AHCI) += ahci.o +common-obj-$(CONFIG_AHCI) += ich.o diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 5ea3cadb01..d0724499c7 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -22,14 +22,14 @@ */ #include <hw/hw.h> -#include <hw/msi.h> +#include <hw/pci/msi.h> #include <hw/pc.h> -#include <hw/pci.h> +#include <hw/pci/pci.h> #include <hw/sysbus.h> -#include "monitor.h" -#include "dma.h" -#include "cpu-common.h" +#include "monitor/monitor.h" +#include "sysemu/dma.h" +#include "exec/cpu-common.h" #include "internal.h" #include <hw/ide/pci.h> #include <hw/ide/ahci.h> @@ -174,7 +174,7 @@ static void ahci_trigger_irq(AHCIState *s, AHCIDevice *d, static void map_page(uint8_t **ptr, uint64_t addr, uint32_t wanted) { - target_phys_addr_t len = wanted; + hwaddr len = wanted; if (*ptr) { cpu_physical_memory_unmap(*ptr, len, 1, len); @@ -279,7 +279,7 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) } } -static uint64_t ahci_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t ahci_mem_read(void *opaque, hwaddr addr, unsigned size) { AHCIState *s = opaque; @@ -317,7 +317,7 @@ static uint64_t ahci_mem_read(void *opaque, target_phys_addr_t addr, -static void ahci_mem_write(void *opaque, target_phys_addr_t addr, +static void ahci_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { AHCIState *s = opaque; @@ -373,7 +373,7 @@ static const MemoryRegionOps ahci_mem_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static uint64_t ahci_idp_read(void *opaque, target_phys_addr_t addr, +static uint64_t ahci_idp_read(void *opaque, hwaddr addr, unsigned size) { AHCIState *s = opaque; @@ -389,7 +389,7 @@ static uint64_t ahci_idp_read(void *opaque, target_phys_addr_t addr, } } -static void ahci_idp_write(void *opaque, target_phys_addr_t addr, +static void ahci_idp_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { AHCIState *s = opaque; @@ -1175,7 +1175,6 @@ void ahci_init(AHCIState *s, DeviceState *qdev, DMAContext *dma, int ports) ad->port_no = i; ad->port.dma = &ad->dma; ad->port.dma->ops = &ahci_dma_ops; - ad->port_regs.cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON; } } @@ -1199,6 +1198,7 @@ void ahci_reset(AHCIState *s) pr->irq_stat = 0; pr->irq_mask = 0; pr->scr_ctl = 0; + pr->cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON; ahci_reset_port(s, i); } } diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index f7f714c726..861fd2bec3 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -875,6 +875,12 @@ static void cmd_start_stop_unit(IDEState *s, uint8_t* buf) int sense; bool start = buf[4] & 1; bool loej = buf[4] & 2; /* load on start, eject on !start */ + int pwrcnd = buf[4] & 0xf0; + + if (pwrcnd) { + /* eject/load only happens for power condition == 0 */ + return; + } if (loej) { if (!start && !s->tray_open && s->tray_locked) { @@ -1118,12 +1124,17 @@ void ide_atapi_cmd(IDEState *s) * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close * states rely on this behavior. */ - if (!s->tray_open && bdrv_is_inserted(s->bs) && s->cdrom_changed) { - ide_atapi_cmd_error(s, NOT_READY, ASC_MEDIUM_NOT_PRESENT); + if (!(atapi_cmd_table[s->io_buffer[0]].flags & ALLOW_UA) && + !s->tray_open && bdrv_is_inserted(s->bs) && s->cdrom_changed) { + + if (s->cdrom_changed == 1) { + ide_atapi_cmd_error(s, NOT_READY, ASC_MEDIUM_NOT_PRESENT); + s->cdrom_changed = 2; + } else { + ide_atapi_cmd_error(s, UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED); + s->cdrom_changed = 0; + } - s->cdrom_changed = 0; - s->sense_key = UNIT_ATTENTION; - s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED; return; } diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index e0b9443496..ee855b670f 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -24,11 +24,11 @@ */ #include <hw/hw.h> #include <hw/pc.h> -#include <hw/pci.h> +#include <hw/pci/pci.h> #include <hw/isa.h> -#include "block.h" -#include "sysemu.h" -#include "dma.h" +#include "block/block.h" +#include "sysemu/sysemu.h" +#include "sysemu/dma.h" #include <hw/ide/pci.h> @@ -43,7 +43,7 @@ static void cmd646_update_irq(PCIIDEState *d); -static uint64_t cmd646_cmd_read(void *opaque, target_phys_addr_t addr, +static uint64_t cmd646_cmd_read(void *opaque, hwaddr addr, unsigned size) { CMD646BAR *cmd646bar = opaque; @@ -54,7 +54,7 @@ static uint64_t cmd646_cmd_read(void *opaque, target_phys_addr_t addr, return ide_status_read(cmd646bar->bus, addr + 2); } -static void cmd646_cmd_write(void *opaque, target_phys_addr_t addr, +static void cmd646_cmd_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { CMD646BAR *cmd646bar = opaque; @@ -71,7 +71,7 @@ static const MemoryRegionOps cmd646_cmd_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static uint64_t cmd646_data_read(void *opaque, target_phys_addr_t addr, +static uint64_t cmd646_data_read(void *opaque, hwaddr addr, unsigned size) { CMD646BAR *cmd646bar = opaque; @@ -88,7 +88,7 @@ static uint64_t cmd646_data_read(void *opaque, target_phys_addr_t addr, return ((uint64_t)1 << (size * 8)) - 1; } -static void cmd646_data_write(void *opaque, target_phys_addr_t addr, +static void cmd646_data_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { CMD646BAR *cmd646bar = opaque; @@ -121,7 +121,7 @@ static void setup_cmd646_bar(PCIIDEState *d, int bus_num) memory_region_init_io(&bar->data, &cmd646_data_ops, bar, "cmd646-data", 8); } -static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr, +static uint64_t bmdma_read(void *opaque, hwaddr addr, unsigned size) { BMDMAState *bm = opaque; @@ -159,7 +159,7 @@ static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr, return val; } -static void bmdma_write(void *opaque, target_phys_addr_t addr, +static void bmdma_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { BMDMAState *bm = opaque; diff --git a/hw/ide/core.c b/hw/ide/core.c index d65ef3d58d..6f1938a0a8 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -24,14 +24,14 @@ */ #include <hw/hw.h> #include <hw/pc.h> -#include <hw/pci.h> +#include <hw/pci/pci.h> #include <hw/isa.h> -#include "qemu-error.h" -#include "qemu-timer.h" -#include "sysemu.h" -#include "dma.h" +#include "qemu/error-report.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" +#include "sysemu/dma.h" #include "hw/block-common.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" #include <hw/ide/internal.h> @@ -53,8 +53,6 @@ static const int smart_attributes[][12] = { { 0x0c, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* airflow-temperature-celsius */ { 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32}, - /* end of list */ - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; static int ide_handle_rw_error(IDEState *s, int error, int op); @@ -338,7 +336,7 @@ static void trim_aio_cancel(BlockDriverAIOCB *acb) qemu_aio_release(iocb); } -static AIOPool trim_aio_pool = { +static const AIOCBInfo trim_aiocb_info = { .aiocb_size = sizeof(TrimAIOCB), .cancel = trim_aio_cancel, }; @@ -362,7 +360,7 @@ BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs, TrimAIOCB *iocb; int i, j, ret; - iocb = qemu_aio_get(&trim_aio_pool, bs, cb, opaque); + iocb = qemu_aio_get(&trim_aiocb_info, bs, cb, opaque); iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb); iocb->ret = 0; @@ -558,32 +556,22 @@ void ide_dma_error(IDEState *s) static int ide_handle_rw_error(IDEState *s, int error, int op) { - int is_read = (op & BM_STATUS_RETRY_READ); - BlockErrorAction action = bdrv_get_on_error(s->bs, is_read); + bool is_read = (op & BM_STATUS_RETRY_READ) != 0; + BlockErrorAction action = bdrv_get_error_action(s->bs, is_read, error); - if (action == BLOCK_ERR_IGNORE) { - bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_IGNORE, is_read); - return 0; - } - - if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) - || action == BLOCK_ERR_STOP_ANY) { + if (action == BDRV_ACTION_STOP) { s->bus->dma->ops->set_unit(s->bus->dma, s->unit); s->bus->error_status = op; - bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_STOP, is_read); - vm_stop(RUN_STATE_IO_ERROR); - bdrv_iostatus_set_err(s->bs, error); - } else { + } else if (action == BDRV_ACTION_REPORT) { if (op & BM_STATUS_DMA_RETRY) { dma_buf_commit(s); ide_dma_error(s); } else { ide_rw_error(s); } - bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_REPORT, is_read); } - - return 1; + bdrv_error_action(s->bs, action, is_read, error); + return action != BDRV_ACTION_IGNORE; } void ide_dma_cb(void *opaque, int ret) @@ -591,6 +579,7 @@ void ide_dma_cb(void *opaque, int ret) IDEState *s = opaque; int n; int64_t sector_num; + bool stay_active = false; if (ret < 0) { int op = BM_STATUS_DMA_RETRY; @@ -606,6 +595,14 @@ void ide_dma_cb(void *opaque, int ret) } n = s->io_buffer_size >> 9; + if (n > s->nsector) { + /* The PRDs were longer than needed for this request. Shorten them so + * we don't get a negative remainder. The Active bit must remain set + * after the request completes. */ + n = s->nsector; + stay_active = true; + } + sector_num = ide_get_sector(s); if (n > 0) { dma_buf_commit(s); @@ -628,6 +625,7 @@ void ide_dma_cb(void *opaque, int ret) if (s->bus->dma->ops->prepare_buf(s->bus->dma, ide_cmd_is_read(s)) == 0) { /* The PRDs were too short. Reset the Active bit, but don't raise an * interrupt. */ + s->status = READY_STAT | SEEK_STAT; goto eot; } @@ -658,6 +656,9 @@ eot: bdrv_acct_done(s->bs, &s->acct); } ide_set_inactive(s); + if (stay_active) { + s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_DMAING); + } } static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd) @@ -1468,9 +1469,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) case SMART_READ_THRESH: memset(s->io_buffer, 0, 0x200); s->io_buffer[0] = 0x01; /* smart struct version */ - for (n=0; n<30; n++) { - if (smart_attributes[n][0] == 0) - break; + for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) { s->io_buffer[2+0+(n*12)] = smart_attributes[n][0]; s->io_buffer[2+1+(n*12)] = smart_attributes[n][11]; } @@ -1484,10 +1483,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) case SMART_READ_DATA: memset(s->io_buffer, 0, 0x200); s->io_buffer[0] = 0x01; /* smart struct version */ - for (n=0; n<30; n++) { - if (smart_attributes[n][0] == 0) { - break; - } + for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) { int i; for(i = 0; i < 11; i++) { s->io_buffer[2+i+(n*12)] = smart_attributes[n][i]; @@ -1873,6 +1869,8 @@ static void ide_reset(IDEState *s) s->io_buffer_index = 0; s->cd_sector_size = 0; s->atapi_dma = 0; + s->tray_locked = 0; + s->tray_open = 0; /* ATA DMA state */ s->io_buffer_size = 0; s->req_nb_sectors = 0; @@ -2164,12 +2162,6 @@ static int ide_drive_post_load(void *opaque, int version_id) { IDEState *s = opaque; - if (version_id < 3) { - if (s->sense_key == UNIT_ATTENTION && - s->asc == ASC_MEDIUM_MAY_HAVE_CHANGED) { - s->cdrom_changed = 1; - } - } if (s->identify_set) { bdrv_set_enable_write_cache(s->bs, !!(s->identify_data[85] & (1 << 5))); } diff --git a/hw/ide/ich.c b/hw/ide/ich.c index 272b7734b5..de39b3067a 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -61,12 +61,12 @@ */ #include <hw/hw.h> -#include <hw/msi.h> +#include <hw/pci/msi.h> #include <hw/pc.h> -#include <hw/pci.h> +#include <hw/pci/pci.h> #include <hw/isa.h> -#include "block.h" -#include "dma.h" +#include "block/block.h" +#include "sysemu/dma.h" #include <hw/ide/pci.h> #include <hw/ide/ahci.h> diff --git a/hw/ide/internal.h b/hw/ide/internal.h index bf7d313cf4..d80360e85b 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -8,9 +8,9 @@ */ #include <hw/ide.h> #include <hw/isa.h> -#include "iorange.h" -#include "dma.h" -#include "sysemu.h" +#include "exec/iorange.h" +#include "sysemu/dma.h" +#include "sysemu/sysemu.h" #include "hw/block-common.h" #include "hw/scsi-defs.h" diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 8ab2718eea..aa0e7fa22d 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -25,8 +25,8 @@ #include <hw/hw.h> #include <hw/pc.h> #include <hw/isa.h> -#include "block.h" -#include "dma.h" +#include "block/block.h" +#include "sysemu/dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 848cb31429..d8f9b4bce1 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -25,8 +25,8 @@ #include <hw/hw.h> #include <hw/ppc_mac.h> #include <hw/mac_dbdma.h> -#include "block.h" -#include "dma.h" +#include "block/block.h" +#include "sysemu/dma.h" #include <hw/ide/internal.h> @@ -76,7 +76,8 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) s->io_buffer_size = io->len; - qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1, NULL); + qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1, + &dma_context_memory); qemu_sglist_add(&s->sg, io->addr, io->len); io->addr += io->len; io->len = 0; @@ -89,7 +90,6 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) done: bdrv_acct_done(s->bs, &s->acct); io->dma_end(opaque); - return; } static void pmac_ide_transfer_cb(void *opaque, int ret) @@ -133,7 +133,8 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) s->io_buffer_index = 0; s->io_buffer_size = io->len; - qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1, NULL); + qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1, + &dma_context_memory); qemu_sglist_add(&s->sg, io->addr, io->len); io->addr += io->len; io->len = 0; @@ -199,7 +200,7 @@ static void pmac_ide_flush(DBDMA_io *io) /* PowerMac IDE memory IO */ static void pmac_ide_writeb (void *opaque, - target_phys_addr_t addr, uint32_t val) + hwaddr addr, uint32_t val) { MACIOIDEState *d = opaque; @@ -217,7 +218,7 @@ static void pmac_ide_writeb (void *opaque, } } -static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr) +static uint32_t pmac_ide_readb (void *opaque,hwaddr addr) { uint8_t retval; MACIOIDEState *d = opaque; @@ -239,7 +240,7 @@ static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr) } static void pmac_ide_writew (void *opaque, - target_phys_addr_t addr, uint32_t val) + hwaddr addr, uint32_t val) { MACIOIDEState *d = opaque; @@ -250,7 +251,7 @@ static void pmac_ide_writew (void *opaque, } } -static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr) +static uint32_t pmac_ide_readw (void *opaque,hwaddr addr) { uint16_t retval; MACIOIDEState *d = opaque; @@ -266,7 +267,7 @@ static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr) } static void pmac_ide_writel (void *opaque, - target_phys_addr_t addr, uint32_t val) + hwaddr addr, uint32_t val) { MACIOIDEState *d = opaque; @@ -277,7 +278,7 @@ static void pmac_ide_writel (void *opaque, } } -static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr) +static uint32_t pmac_ide_readl (void *opaque,hwaddr addr) { uint32_t retval; MACIOIDEState *d = opaque; diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index 9eee5b50ba..642774ef98 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -25,8 +25,8 @@ #include <hw/hw.h> #include <hw/pc.h> #include <hw/pcmcia.h> -#include "block.h" -#include "dma.h" +#include "block/block.h" +#include "sysemu/dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c index fcfb09eeab..eb59976eda 100644 --- a/hw/ide/mmio.c +++ b/hw/ide/mmio.c @@ -23,8 +23,8 @@ * THE SOFTWARE. */ #include <hw/hw.h> -#include "block.h" -#include "dma.h" +#include "block/block.h" +#include "sysemu/dma.h" #include <hw/ide/internal.h> @@ -47,7 +47,7 @@ static void mmio_ide_reset(void *opaque) ide_bus_reset(&s->bus); } -static uint64_t mmio_ide_read(void *opaque, target_phys_addr_t addr, +static uint64_t mmio_ide_read(void *opaque, hwaddr addr, unsigned size) { MMIOState *s = opaque; @@ -58,7 +58,7 @@ static uint64_t mmio_ide_read(void *opaque, target_phys_addr_t addr, return ide_data_readw(&s->bus, 0); } -static void mmio_ide_write(void *opaque, target_phys_addr_t addr, +static void mmio_ide_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { MMIOState *s = opaque; @@ -75,14 +75,14 @@ static const MemoryRegionOps mmio_ide_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint64_t mmio_ide_status_read(void *opaque, target_phys_addr_t addr, +static uint64_t mmio_ide_status_read(void *opaque, hwaddr addr, unsigned size) { MMIOState *s= opaque; return ide_status_read(&s->bus, 0); } -static void mmio_ide_cmd_write(void *opaque, target_phys_addr_t addr, +static void mmio_ide_cmd_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { MMIOState *s = opaque; @@ -107,7 +107,7 @@ static const VMStateDescription vmstate_ide_mmio = { } }; -void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2, +void mmio_ide_init (hwaddr membase, hwaddr membase2, MemoryRegion *address_space, qemu_irq irq, int shift, DriveInfo *hd0, DriveInfo *hd1) diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 88c0942e34..e6226e3197 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -24,10 +24,10 @@ */ #include <hw/hw.h> #include <hw/pc.h> -#include <hw/pci.h> +#include <hw/pci/pci.h> #include <hw/isa.h> -#include "block.h" -#include "dma.h" +#include "block/block.h" +#include "sysemu/dma.h" #include <hw/ide/pci.h> @@ -188,7 +188,7 @@ static void bmdma_restart_bh(void *opaque) { BMDMAState *bm = opaque; IDEBus *bus = bm->bus; - int is_read; + bool is_read; int error_status; qemu_bh_delete(bm->bh); @@ -198,7 +198,7 @@ static void bmdma_restart_bh(void *opaque) return; } - is_read = !!(bus->error_status & BM_STATUS_RETRY_READ); + is_read = (bus->error_status & BM_STATUS_RETRY_READ) != 0; /* The error status must be cleared before resubmitting the request: The * request may fail again, and this case can only be distinguished if the @@ -327,7 +327,7 @@ void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val) bm->cmd = val & 0x09; } -static uint64_t bmdma_addr_read(void *opaque, target_phys_addr_t addr, +static uint64_t bmdma_addr_read(void *opaque, hwaddr addr, unsigned width) { BMDMAState *bm = opaque; @@ -341,7 +341,7 @@ static uint64_t bmdma_addr_read(void *opaque, target_phys_addr_t addr, return data; } -static void bmdma_addr_write(void *opaque, target_phys_addr_t addr, +static void bmdma_addr_write(void *opaque, hwaddr addr, uint64_t data, unsigned width) { BMDMAState *bm = opaque; diff --git a/hw/ide/piix.c b/hw/ide/piix.c index 4ded9ee13d..df95aec195 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -25,15 +25,15 @@ #include <hw/hw.h> #include <hw/pc.h> -#include <hw/pci.h> +#include <hw/pci/pci.h> #include <hw/isa.h> -#include "blockdev.h" -#include "sysemu.h" -#include "dma.h" +#include "sysemu/blockdev.h" +#include "sysemu/sysemu.h" +#include "sysemu/dma.h" #include <hw/ide/pci.h> -static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t bmdma_read(void *opaque, hwaddr addr, unsigned size) { BMDMAState *bm = opaque; uint32_t val; @@ -59,7 +59,7 @@ static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr, unsigned size) return val; } -static void bmdma_write(void *opaque, target_phys_addr_t addr, +static void bmdma_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { BMDMAState *bm = opaque; diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 5ea9b8f4b2..d2fe77398f 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -17,12 +17,12 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include <hw/hw.h> -#include "dma.h" -#include "qemu-error.h" +#include "sysemu/dma.h" +#include "qemu/error-report.h" #include <hw/ide/internal.h> -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "hw/block-common.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" /* --------------------------------- */ @@ -60,7 +60,7 @@ static char *idebus_get_fw_dev_path(DeviceState *dev) snprintf(path, sizeof(path), "%s@%d", qdev_fw_name(dev), ((IDEBus*)dev->parent_bus)->bus_id); - return strdup(path); + return g_strdup(path); } static int ide_qdev_init(DeviceState *qdev) diff --git a/hw/ide/via.c b/hw/ide/via.c index b20e4f094e..14acb3ac04 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -25,15 +25,15 @@ */ #include <hw/hw.h> #include <hw/pc.h> -#include <hw/pci.h> +#include <hw/pci/pci.h> #include <hw/isa.h> -#include "block.h" -#include "sysemu.h" -#include "dma.h" +#include "block/block.h" +#include "sysemu/sysemu.h" +#include "sysemu/dma.h" #include <hw/ide/pci.h> -static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr, +static uint64_t bmdma_read(void *opaque, hwaddr addr, unsigned size) { BMDMAState *bm = opaque; @@ -60,7 +60,7 @@ static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr, return val; } -static void bmdma_write(void *opaque, target_phys_addr_t addr, +static void bmdma_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { BMDMAState *bm = opaque; @@ -11,7 +11,7 @@ #ifndef IMX_H #define IMX_H -void imx_serial_create(int uart, const target_phys_addr_t addr, qemu_irq irq); +void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq); typedef enum { NOCLK, @@ -23,10 +23,10 @@ typedef enum { uint32_t imx_clock_frequency(DeviceState *s, IMXClk clock); -void imx_timerp_create(const target_phys_addr_t addr, +void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm); -void imx_timerg_create(const target_phys_addr_t addr, +void imx_timerg_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm); diff --git a/hw/imx_avic.c b/hw/imx_avic.c index 4f010e8ee2..f1f066cf9c 100644 --- a/hw/imx_avic.c +++ b/hw/imx_avic.c @@ -6,9 +6,9 @@ * * Copyright (c) 2008 OKL * Copyright (c) 2011 NICTA Pty Ltd - * Originally Written by Hans Jiang + * Originally written by Hans Jiang * - * This code is licenced under the GPL version 2 or later. See + * This code is licensed under the GPL version 2 or later. See * the COPYING file in the top-level directory. * * TODO: implement vectors. @@ -16,7 +16,7 @@ #include "hw.h" #include "sysbus.h" -#include "host-utils.h" +#include "qemu/host-utils.h" #define DEBUG_INT 1 #undef DEBUG_INT /* comment out for debugging */ @@ -152,7 +152,7 @@ static void imx_avic_set_irq(void *opaque, int irq, int level) static uint64_t imx_avic_read(void *opaque, - target_phys_addr_t offset, unsigned size) + hwaddr offset, unsigned size) { IMXAVICState *s = (IMXAVICState *)opaque; @@ -259,7 +259,7 @@ static uint64_t imx_avic_read(void *opaque, } } -static void imx_avic_write(void *opaque, target_phys_addr_t offset, +static void imx_avic_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { IMXAVICState *s = (IMXAVICState *)opaque; diff --git a/hw/imx_ccm.c b/hw/imx_ccm.c index 10952c6ea1..46962e4df9 100644 --- a/hw/imx_ccm.c +++ b/hw/imx_ccm.c @@ -12,7 +12,7 @@ #include "hw.h" #include "sysbus.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "imx.h" #define CKIH_FREQ 26000000 /* 26MHz crystal input */ @@ -191,7 +191,7 @@ static void imx_ccm_reset(DeviceState *dev) update_clocks(s); } -static uint64_t imx_ccm_read(void *opaque, target_phys_addr_t offset, +static uint64_t imx_ccm_read(void *opaque, hwaddr offset, unsigned size) { IMXCCMState *s = (IMXCCMState *)opaque; @@ -232,7 +232,7 @@ static uint64_t imx_ccm_read(void *opaque, target_phys_addr_t offset, return 0; } -static void imx_ccm_write(void *opaque, target_phys_addr_t offset, +static void imx_ccm_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { IMXCCMState *s = (IMXCCMState *)opaque; diff --git a/hw/imx_serial.c b/hw/imx_serial.c index d4eae430f5..124dbb2860 100644 --- a/hw/imx_serial.c +++ b/hw/imx_serial.c @@ -19,8 +19,8 @@ #include "hw.h" #include "sysbus.h" -#include "sysemu.h" -#include "qemu-char.h" +#include "sysemu/sysemu.h" +#include "char/char.h" #include "imx.h" //#define DEBUG_SERIAL 1 @@ -183,7 +183,7 @@ static void imx_serial_reset_at_boot(DeviceState *dev) } -static uint64_t imx_serial_read(void *opaque, target_phys_addr_t offset, +static uint64_t imx_serial_read(void *opaque, hwaddr offset, unsigned size) { IMXSerialState *s = (IMXSerialState *)opaque; @@ -244,7 +244,7 @@ static uint64_t imx_serial_read(void *opaque, target_phys_addr_t offset, } } -static void imx_serial_write(void *opaque, target_phys_addr_t offset, +static void imx_serial_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { IMXSerialState *s = (IMXSerialState *)opaque; @@ -401,7 +401,7 @@ static int imx_serial_init(SysBusDevice *dev) return 0; } -void imx_serial_create(int uart, const target_phys_addr_t addr, qemu_irq irq) +void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq) { DeviceState *dev; SysBusDevice *bus; @@ -427,7 +427,7 @@ void imx_serial_create(int uart, const target_phys_addr_t addr, qemu_irq irq) qdev_prop_set_chr(dev, "chardev", chr); bus = sysbus_from_qdev(dev); qdev_init_nofail(dev); - if (addr != (target_phys_addr_t)-1) { + if (addr != (hwaddr)-1) { sysbus_mmio_map(bus, 0, addr); } sysbus_connect_irq(bus, 0, irq); diff --git a/hw/imx_timer.c b/hw/imx_timer.c index 16215ccf04..e924c747c5 100644 --- a/hw/imx_timer.c +++ b/hw/imx_timer.c @@ -3,16 +3,16 @@ * * Copyright (c) 2008 OK Labs * Copyright (c) 2011 NICTA Pty Ltd - * Originally Written by Hans Jiang + * Originally written by Hans Jiang * Updated by Peter Chubb * - * This code is licenced under GPL version 2 or later. See + * This code is licensed under GPL version 2 or later. See * the COPYING file in the top-level directory. * */ #include "hw.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "ptimer.h" #include "sysbus.h" #include "imx.h" @@ -194,7 +194,7 @@ static void imx_timerg_reload(IMXTimerGState *s, uint32_t timeout) ptimer_set_count(s->timer, diff_cnt); } -static uint64_t imx_timerg_read(void *opaque, target_phys_addr_t offset, +static uint64_t imx_timerg_read(void *opaque, hwaddr offset, unsigned size) { IMXTimerGState *s = (IMXTimerGState *)opaque; @@ -251,7 +251,7 @@ static void imx_timerg_reset(DeviceState *dev) imx_timerg_set_freq(s); } -static void imx_timerg_write(void *opaque, target_phys_addr_t offset, +static void imx_timerg_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { IMXTimerGState *s = (IMXTimerGState *)opaque; @@ -468,7 +468,7 @@ static void imx_timerp_reset(DeviceState *dev) ptimer_set_count(s->timer, TIMER_MAX); } -static uint64_t imx_timerp_read(void *opaque, target_phys_addr_t offset, +static uint64_t imx_timerp_read(void *opaque, hwaddr offset, unsigned size) { IMXTimerPState *s = (IMXTimerPState *)opaque; @@ -517,7 +517,7 @@ static void set_timerp_freq(IMXTimerPState *s) } } -static void imx_timerp_write(void *opaque, target_phys_addr_t offset, +static void imx_timerp_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { IMXTimerPState *s = (IMXTimerPState *)opaque; @@ -580,7 +580,7 @@ static void imx_timerp_tick(void *opaque) imx_timerp_update(s); } -void imx_timerp_create(const target_phys_addr_t addr, +void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm) { @@ -634,7 +634,7 @@ static int imx_timerp_init(SysBusDevice *dev) } -void imx_timerg_create(const target_phys_addr_t addr, +void imx_timerg_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm) { diff --git a/hw/integratorcp.c b/hw/integratorcp.c index d0e2e9068e..47fc9cb944 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -11,9 +11,9 @@ #include "devices.h" #include "boards.h" #include "arm-misc.h" -#include "net.h" -#include "exec-memory.h" -#include "sysemu.h" +#include "net/net.h" +#include "exec/address-spaces.h" +#include "sysemu/sysemu.h" typedef struct { SysBusDevice busdev; @@ -38,7 +38,7 @@ static uint8_t integrator_spd[128] = { 0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40 }; -static uint64_t integratorcm_read(void *opaque, target_phys_addr_t offset, +static uint64_t integratorcm_read(void *opaque, hwaddr offset, unsigned size) { integratorcm_state *s = (integratorcm_state *)opaque; @@ -141,7 +141,7 @@ static void integratorcm_update(integratorcm_state *s) hw_error("Core module interrupt\n"); } -static void integratorcm_write(void *opaque, target_phys_addr_t offset, +static void integratorcm_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { integratorcm_state *s = (integratorcm_state *)opaque; @@ -295,7 +295,7 @@ static void icp_pic_set_irq(void *opaque, int irq, int level) icp_pic_update(s); } -static uint64_t icp_pic_read(void *opaque, target_phys_addr_t offset, +static uint64_t icp_pic_read(void *opaque, hwaddr offset, unsigned size) { icp_pic_state *s = (icp_pic_state *)opaque; @@ -324,7 +324,7 @@ static uint64_t icp_pic_read(void *opaque, target_phys_addr_t offset, } } -static void icp_pic_write(void *opaque, target_phys_addr_t offset, +static void icp_pic_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { icp_pic_state *s = (icp_pic_state *)opaque; @@ -381,7 +381,7 @@ static int icp_pic_init(SysBusDevice *dev) /* CP control registers. */ -static uint64_t icp_control_read(void *opaque, target_phys_addr_t offset, +static uint64_t icp_control_read(void *opaque, hwaddr offset, unsigned size) { switch (offset >> 2) { @@ -399,7 +399,7 @@ static uint64_t icp_control_read(void *opaque, target_phys_addr_t offset, } } -static void icp_control_write(void *opaque, target_phys_addr_t offset, +static void icp_control_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { switch (offset >> 2) { @@ -419,7 +419,7 @@ static const MemoryRegionOps icp_control_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void icp_control_init(target_phys_addr_t base) +static void icp_control_init(hwaddr base) { MemoryRegion *io; @@ -438,11 +438,13 @@ static struct arm_boot_info integrator_binfo = { .board_id = 0x113, }; -static void integratorcp_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void integratorcp_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/intel-hda.c b/hw/intel-hda.c index 127e81888b..98ff93679d 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -18,13 +18,13 @@ */ #include "hw.h" -#include "pci.h" -#include "msi.h" -#include "qemu-timer.h" +#include "pci/pci.h" +#include "pci/msi.h" +#include "qemu/timer.h" #include "audiodev.h" #include "intel-hda.h" #include "intel-hda-defs.h" -#include "dma.h" +#include "sysemu/dma.h" /* --------------------------------------------------------------------- */ /* hda bus */ @@ -206,17 +206,11 @@ static void intel_hda_reset(DeviceState *dev); /* --------------------------------------------------------------------- */ -static target_phys_addr_t intel_hda_addr(uint32_t lbase, uint32_t ubase) +static hwaddr intel_hda_addr(uint32_t lbase, uint32_t ubase) { - target_phys_addr_t addr; - -#if TARGET_PHYS_ADDR_BITS == 32 - addr = lbase; -#else - addr = ubase; - addr <<= 32; - addr |= lbase; -#endif + hwaddr addr; + + addr = ((uint64_t)ubase << 32) | lbase; return addr; } @@ -301,7 +295,7 @@ static int intel_hda_send_command(IntelHDAState *d, uint32_t verb) static void intel_hda_corb_run(IntelHDAState *d) { - target_phys_addr_t addr; + hwaddr addr; uint32_t rp, verb; if (d->ics & ICH6_IRS_BUSY) { @@ -338,7 +332,7 @@ static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t res { HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus); IntelHDAState *d = container_of(bus, IntelHDAState, codecs); - target_phys_addr_t addr; + hwaddr addr; uint32_t wp, ex; if (d->ics & ICH6_IRS_BUSY) { @@ -387,7 +381,7 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, { HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus); IntelHDAState *d = container_of(bus, IntelHDAState, codecs); - target_phys_addr_t addr; + hwaddr addr; uint32_t s, copy, left; IntelHDAStream *st; bool irq = false; @@ -459,7 +453,7 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st) { - target_phys_addr_t addr; + hwaddr addr; uint8_t buf[16]; uint32_t i; @@ -896,7 +890,7 @@ static const struct IntelHDAReg regtab[] = { }; -static const IntelHDAReg *intel_hda_reg_find(IntelHDAState *d, target_phys_addr_t addr) +static const IntelHDAReg *intel_hda_reg_find(IntelHDAState *d, hwaddr addr) { const IntelHDAReg *reg; @@ -1039,7 +1033,7 @@ static void intel_hda_regs_reset(IntelHDAState *d) /* --------------------------------------------------------------------- */ -static void intel_hda_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void intel_hda_mmio_writeb(void *opaque, hwaddr addr, uint32_t val) { IntelHDAState *d = opaque; const IntelHDAReg *reg = intel_hda_reg_find(d, addr); @@ -1047,7 +1041,7 @@ static void intel_hda_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_ intel_hda_reg_write(d, reg, val, 0xff); } -static void intel_hda_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +static void intel_hda_mmio_writew(void *opaque, hwaddr addr, uint32_t val) { IntelHDAState *d = opaque; const IntelHDAReg *reg = intel_hda_reg_find(d, addr); @@ -1055,7 +1049,7 @@ static void intel_hda_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_ intel_hda_reg_write(d, reg, val, 0xffff); } -static void intel_hda_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void intel_hda_mmio_writel(void *opaque, hwaddr addr, uint32_t val) { IntelHDAState *d = opaque; const IntelHDAReg *reg = intel_hda_reg_find(d, addr); @@ -1063,7 +1057,7 @@ static void intel_hda_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_ intel_hda_reg_write(d, reg, val, 0xffffffff); } -static uint32_t intel_hda_mmio_readb(void *opaque, target_phys_addr_t addr) +static uint32_t intel_hda_mmio_readb(void *opaque, hwaddr addr) { IntelHDAState *d = opaque; const IntelHDAReg *reg = intel_hda_reg_find(d, addr); @@ -1071,7 +1065,7 @@ static uint32_t intel_hda_mmio_readb(void *opaque, target_phys_addr_t addr) return intel_hda_reg_read(d, reg, 0xff); } -static uint32_t intel_hda_mmio_readw(void *opaque, target_phys_addr_t addr) +static uint32_t intel_hda_mmio_readw(void *opaque, hwaddr addr) { IntelHDAState *d = opaque; const IntelHDAReg *reg = intel_hda_reg_find(d, addr); @@ -1079,7 +1073,7 @@ static uint32_t intel_hda_mmio_readw(void *opaque, target_phys_addr_t addr) return intel_hda_reg_read(d, reg, 0xffff); } -static uint32_t intel_hda_mmio_readl(void *opaque, target_phys_addr_t addr) +static uint32_t intel_hda_mmio_readl(void *opaque, hwaddr addr) { IntelHDAState *d = opaque; const IntelHDAReg *reg = intel_hda_reg_find(d, addr); diff --git a/hw/ioapic.c b/hw/ioapic.c index e2e4796bb5..72730951a6 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -139,7 +139,7 @@ void ioapic_eoi_broadcast(int vector) } static uint64_t -ioapic_mem_read(void *opaque, target_phys_addr_t addr, unsigned int size) +ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size) { IOAPICCommonState *s = opaque; int index; @@ -181,7 +181,7 @@ ioapic_mem_read(void *opaque, target_phys_addr_t addr, unsigned int size) } static void -ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val, +ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned int size) { IOAPICCommonState *s = opaque; diff --git a/hw/ioapic_internal.h b/hw/ioapic_internal.h index e04c9f3c12..c8447d7f3b 100644 --- a/hw/ioapic_internal.h +++ b/hw/ioapic_internal.h @@ -23,7 +23,7 @@ #define QEMU_IOAPIC_INTERNAL_H #include "hw.h" -#include "memory.h" +#include "exec/memory.h" #include "sysbus.h" #define MAX_IOAPICS 1 diff --git a/hw/ioh3420.c b/hw/ioh3420.c index 94a537c9b3..d706e195df 100644 --- a/hw/ioh3420.c +++ b/hw/ioh3420.c @@ -20,9 +20,9 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "pci_ids.h" -#include "msi.h" -#include "pcie.h" +#include "pci/pci_ids.h" +#include "pci/msi.h" +#include "pci/pcie.h" #include "ioh3420.h" #define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */ @@ -125,7 +125,6 @@ static int ioh3420_initfn(PCIDevice *d) rc = pcie_chassis_add_slot(s); if (rc < 0) { goto err_pcie_cap; - return rc; } pcie_cap_root_init(d); rc = pcie_aer_init(d, IOH_EP_AER_OFFSET); diff --git a/hw/ioh3420.h b/hw/ioh3420.h index 68c523ab46..046cf2c281 100644 --- a/hw/ioh3420.h +++ b/hw/ioh3420.h @@ -1,7 +1,7 @@ #ifndef QEMU_IOH3420_H #define QEMU_IOH3420_H -#include "pcie_port.h" +#include "pci/pcie_port.h" PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction, const char *bus_name, pci_map_irq_fn map_irq, @@ -38,24 +38,37 @@ void qemu_set_irq(qemu_irq irq, int level) irq->handler(irq->opaque, irq->n, level); } -qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n) +qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler, + void *opaque, int n) { qemu_irq *s; struct IRQState *p; int i; - s = (qemu_irq *)g_malloc0(sizeof(qemu_irq) * n); - p = (struct IRQState *)g_malloc0(sizeof(struct IRQState) * n); - for (i = 0; i < n; i++) { - p->handler = handler; - p->opaque = opaque; - p->n = i; + if (!old) { + n_old = 0; + } + s = old ? g_renew(qemu_irq, old, n + n_old) : g_new(qemu_irq, n); + p = old ? g_renew(struct IRQState, s[0], n + n_old) : + g_new(struct IRQState, n); + for (i = 0; i < n + n_old; i++) { + if (i >= n_old) { + p->handler = handler; + p->opaque = opaque; + p->n = i; + } s[i] = p; p++; } return s; } +qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n) +{ + return qemu_extend_irqs(NULL, 0, handler, opaque, n); +} + + void qemu_free_irqs(qemu_irq *s) { g_free(s[0]); @@ -3,6 +3,8 @@ /* Generic IRQ/GPIO pin infrastructure. */ +typedef struct IRQState *qemu_irq; + typedef void (*qemu_irq_handler)(void *opaque, int n, int level); void qemu_set_irq(qemu_irq irq, int level); @@ -23,8 +25,17 @@ static inline void qemu_irq_pulse(qemu_irq irq) qemu_set_irq(irq, 0); } -/* Returns an array of N IRQs. */ +/* Returns an array of N IRQs. Each IRQ is assigned the argument handler and + * opaque data. + */ qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n); + +/* Extends an Array of IRQs. Old IRQs have their handlers and opaque data + * preserved. New IRQs are assigned the argument handler and opaque data. + */ +qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler, + void *opaque, int n); + void qemu_free_irqs(qemu_irq *s); /* Returns a new IRQ with opposite polarity. */ diff --git a/hw/isa-bus.c b/hw/isa-bus.c index f9b237387a..86b0bbd3d1 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -17,13 +17,14 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include "hw.h" -#include "monitor.h" +#include "monitor/monitor.h" #include "sysbus.h" +#include "sysemu/sysemu.h" #include "isa.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" static ISABus *isabus; -target_phys_addr_t isa_mem_base = 0; +hwaddr isa_mem_base = 0; static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent); static char *isabus_get_fw_dev_path(DeviceState *dev); @@ -166,6 +167,25 @@ ISADevice *isa_create_simple(ISABus *bus, const char *name) return dev; } +ISADevice *isa_vga_init(ISABus *bus) +{ + switch (vga_interface_type) { + case VGA_CIRRUS: + return isa_create_simple(bus, "isa-cirrus-vga"); + case VGA_QXL: + fprintf(stderr, "%s: qxl: no PCI bus\n", __func__); + return NULL; + case VGA_STD: + return isa_create_simple(bus, "isa-vga"); + case VGA_VMWARE: + fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __func__); + return NULL; + case VGA_NONE: + default: + return NULL; + } +} + static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent) { ISADevice *d = ISA_DEVICE(dev); @@ -236,7 +256,7 @@ static char *isabus_get_fw_dev_path(DeviceState *dev) snprintf(path + off, sizeof(path) - off, "@%04x", d->ioport_id); } - return strdup(path); + return g_strdup(path); } MemoryRegion *isa_address_space(ISADevice *dev) @@ -244,4 +264,13 @@ MemoryRegion *isa_address_space(ISADevice *dev) return get_system_memory(); } +MemoryRegion *isa_address_space_io(ISADevice *dev) +{ + if (dev) { + return isa_bus_from_device(dev)->address_space_io; + } + + return isabus->address_space_io; +} + type_init(isabus_register_types) @@ -3,8 +3,8 @@ /* ISA bus */ -#include "ioport.h" -#include "memory.h" +#include "exec/ioport.h" +#include "exec/memory.h" #include "qdev.h" #define ISA_NUM_IRQS 16 @@ -43,10 +43,13 @@ void isa_bus_irqs(ISABus *bus, qemu_irq *irqs); qemu_irq isa_get_irq(ISADevice *dev, int isairq); void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq); MemoryRegion *isa_address_space(ISADevice *dev); +MemoryRegion *isa_address_space_io(ISADevice *dev); ISADevice *isa_create(ISABus *bus, const char *name); ISADevice *isa_try_create(ISABus *bus, const char *name); ISADevice *isa_create_simple(ISABus *bus, const char *name); +ISADevice *isa_vga_init(ISABus *bus); + /** * isa_register_ioport: Install an I/O port region on the ISA bus. * @@ -82,10 +85,10 @@ static inline ISABus *isa_bus_from_device(ISADevice *d) return DO_UPCAST(ISABus, qbus, d->qdev.parent_bus); } -extern target_phys_addr_t isa_mem_base; +extern hwaddr isa_mem_base; -void isa_mmio_setup(MemoryRegion *mr, target_phys_addr_t size); -void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size); +void isa_mmio_setup(MemoryRegion *mr, hwaddr size); +void isa_mmio_init(hwaddr base, hwaddr size); /* dma.c */ int DMA_get_channel_mode (int nchan); diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c index fd755ab4a8..487cf6a8fb 100644 --- a/hw/isa_mmio.c +++ b/hw/isa_mmio.c @@ -24,37 +24,37 @@ #include "hw.h" #include "isa.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" -static void isa_mmio_writeb (void *opaque, target_phys_addr_t addr, +static void isa_mmio_writeb (void *opaque, hwaddr addr, uint32_t val) { cpu_outb(addr & IOPORTS_MASK, val); } -static void isa_mmio_writew(void *opaque, target_phys_addr_t addr, +static void isa_mmio_writew(void *opaque, hwaddr addr, uint32_t val) { cpu_outw(addr & IOPORTS_MASK, val); } -static void isa_mmio_writel(void *opaque, target_phys_addr_t addr, +static void isa_mmio_writel(void *opaque, hwaddr addr, uint32_t val) { cpu_outl(addr & IOPORTS_MASK, val); } -static uint32_t isa_mmio_readb (void *opaque, target_phys_addr_t addr) +static uint32_t isa_mmio_readb (void *opaque, hwaddr addr) { return cpu_inb(addr & IOPORTS_MASK); } -static uint32_t isa_mmio_readw(void *opaque, target_phys_addr_t addr) +static uint32_t isa_mmio_readw(void *opaque, hwaddr addr) { return cpu_inw(addr & IOPORTS_MASK); } -static uint32_t isa_mmio_readl(void *opaque, target_phys_addr_t addr) +static uint32_t isa_mmio_readl(void *opaque, hwaddr addr) { return cpu_inl(addr & IOPORTS_MASK); } @@ -67,12 +67,12 @@ static const MemoryRegionOps isa_mmio_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -void isa_mmio_setup(MemoryRegion *mr, target_phys_addr_t size) +void isa_mmio_setup(MemoryRegion *mr, hwaddr size) { memory_region_init_io(mr, &isa_mmio_ops, NULL, "isa-mmio", size); } -void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size) +void isa_mmio_init(hwaddr base, hwaddr size) { MemoryRegion *mr = g_malloc(sizeof(*mr)); diff --git a/hw/ivshmem.c b/hw/ivshmem.c index b4d65a6db5..fcf5d05bae 100644 --- a/hw/ivshmem.c +++ b/hw/ivshmem.c @@ -18,12 +18,13 @@ */ #include "hw.h" #include "pc.h" -#include "pci.h" -#include "msix.h" -#include "kvm.h" -#include "migration.h" -#include "qerror.h" -#include "event_notifier.h" +#include "pci/pci.h" +#include "pci/msix.h" +#include "sysemu/kvm.h" +#include "migration/migration.h" +#include "qapi/qmp/qerror.h" +#include "qemu/event_notifier.h" +#include "char/char.h" #include <sys/mman.h> #include <sys/types.h> @@ -71,6 +72,8 @@ typedef struct IVShmemState { MemoryRegion bar; MemoryRegion ivshmem; uint64_t ivshmem_size; /* size of shared memory region */ + uint32_t ivshmem_attr; + uint32_t ivshmem_64bit; int shm_fd; /* shared memory file descriptor */ Peer *peers; @@ -147,7 +150,6 @@ static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val) s->intrstatus = val; ivshmem_update_irq(s, val); - return; } static uint32_t ivshmem_IntrStatus_read(IVShmemState *s) @@ -162,7 +164,7 @@ static uint32_t ivshmem_IntrStatus_read(IVShmemState *s) return ret; } -static void ivshmem_io_write(void *opaque, target_phys_addr_t addr, +static void ivshmem_io_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { IVShmemState *s = opaque; @@ -201,7 +203,7 @@ static void ivshmem_io_write(void *opaque, target_phys_addr_t addr, } } -static uint64_t ivshmem_io_read(void *opaque, target_phys_addr_t addr, +static uint64_t ivshmem_io_read(void *opaque, hwaddr addr, unsigned size) { @@ -339,7 +341,7 @@ static void create_shared_memory_BAR(IVShmemState *s, int fd) { memory_region_add_subregion(&s->bar, 0, &s->ivshmem); /* region for shared memory */ - pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar); + pci_register_bar(&s->dev, 2, s->ivshmem_attr, &s->bar); } static void ivshmem_add_eventfd(IVShmemState *s, int posn, int i) @@ -366,6 +368,10 @@ static void close_guest_eventfds(IVShmemState *s, int posn) { int i, guest_curr_max; + if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) { + return; + } + guest_curr_max = s->peers[posn].nb_eventfds; memory_region_transaction_begin(); @@ -381,17 +387,6 @@ static void close_guest_eventfds(IVShmemState *s, int posn) s->peers[posn].nb_eventfds = 0; } -static void setup_ioeventfds(IVShmemState *s) { - - int i, j; - - for (i = 0; i <= s->max_peer; i++) { - for (j = 0; j < s->peers[i].nb_eventfds; j++) { - ivshmem_add_eventfd(s, i, j); - } - } -} - /* this function increase the dynamic storage need to store data about other * guests */ static void increase_dynamic_storage(IVShmemState *s, int new_min_size) { @@ -515,8 +510,6 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags) if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) { ivshmem_add_eventfd(s, incoming_posn, guest_max_eventfd); } - - return; } /* Select the MSI-X vectors used by device. @@ -541,7 +534,6 @@ static void ivshmem_reset(DeviceState *d) s->intrstatus = 0; ivshmem_use_msix(s); - return; } static uint64_t ivshmem_get_size(IVShmemState * s) { @@ -692,15 +684,16 @@ static int pci_ivshmem_init(PCIDevice *dev) memory_region_init_io(&s->ivshmem_mmio, &ivshmem_mmio_ops, s, "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE); - if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) { - setup_ioeventfds(s); - } - /* region for registers*/ pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ivshmem_mmio); memory_region_init(&s->bar, "ivshmem-bar2-container", s->ivshmem_size); + s->ivshmem_attr = PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_PREFETCH; + if (s->ivshmem_64bit) { + s->ivshmem_attr |= PCI_BASE_ADDRESS_MEM_TYPE_64; + } if ((s->server_chr != NULL) && (strncmp(s->server_chr->filename, "unix:", 5) == 0)) { @@ -726,8 +719,7 @@ static int pci_ivshmem_init(PCIDevice *dev) /* allocate/initialize space for interrupt handling */ s->peers = g_malloc0(s->nb_peers * sizeof(Peer)); - pci_register_bar(&s->dev, 2, - PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar); + pci_register_bar(&s->dev, 2, s->ivshmem_attr, &s->bar); s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *)); @@ -797,6 +789,7 @@ static Property ivshmem_properties[] = { DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true), DEFINE_PROP_STRING("shm", IVShmemState, shmobj), DEFINE_PROP_STRING("role", IVShmemState, role), + DEFINE_PROP_UINT32("use64", IVShmemState, ivshmem_64bit, 1), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/jazz_led.c b/hw/jazz_led.c index 648652302a..f4a040631e 100644 --- a/hw/jazz_led.c +++ b/hw/jazz_led.c @@ -22,8 +22,9 @@ * THE SOFTWARE. */ -#include "console.h" -#include "pixel_ops.h" +#include "qemu-common.h" +#include "ui/console.h" +#include "ui/pixel_ops.h" #include "trace.h" #include "sysbus.h" @@ -39,7 +40,7 @@ typedef struct LedState { screen_state_t state; } LedState; -static uint64_t jazz_led_read(void *opaque, target_phys_addr_t addr, +static uint64_t jazz_led_read(void *opaque, hwaddr addr, unsigned int size) { LedState *s = opaque; @@ -51,7 +52,7 @@ static uint64_t jazz_led_read(void *opaque, target_phys_addr_t addr, return val; } -static void jazz_led_write(void *opaque, target_phys_addr_t addr, +static void jazz_led_write(void *opaque, hwaddr addr, uint64_t val, unsigned int size) { LedState *s = opaque; @@ -196,7 +197,7 @@ static void jazz_led_update_display(void *opaque) } s->state = REDRAW_NONE; - dpy_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds)); + dpy_gfx_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds)); } static void jazz_led_invalidate_display(void *opaque) @@ -210,7 +211,7 @@ static void jazz_led_text_update(void *opaque, console_ch_t *chardata) LedState *s = opaque; char buf[2]; - dpy_cursor(s->ds, -1, -1); + dpy_text_cursor(s->ds, -1, -1); qemu_console_resize(s->ds, 2, 1); /* TODO: draw the segments */ @@ -218,7 +219,7 @@ static void jazz_led_text_update(void *opaque, console_ch_t *chardata) console_write_ch(chardata++, 0x00200100 | buf[0]); console_write_ch(chardata++, 0x00200100 | buf[1]); - dpy_update(s->ds, 0, 0, 2, 1); + dpy_text_update(s->ds, 0, 0, 2, 1); } static int jazz_led_post_load(void *opaque, int version_id) diff --git a/hw/kvm/Makefile.objs b/hw/kvm/Makefile.objs index 226497a58f..f620d7ff85 100644 --- a/hw/kvm/Makefile.objs +++ b/hw/kvm/Makefile.objs @@ -1 +1 @@ -obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o +obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o pci-assign.o diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c index 80e3e48333..a4e834744b 100644 --- a/hw/kvm/apic.c +++ b/hw/kvm/apic.c @@ -10,8 +10,8 @@ * See the COPYING file in the top-level directory. */ #include "hw/apic_internal.h" -#include "hw/msi.h" -#include "kvm.h" +#include "hw/pci/msi.h" +#include "sysemu/kvm.h" static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic, int reg_id, uint32_t val) @@ -104,7 +104,7 @@ static void kvm_apic_enable_tpr_reporting(APICCommonState *s, bool enable) .enabled = enable }; - kvm_vcpu_ioctl(s->cpu_env, KVM_TPR_ACCESS_REPORTING, &ctl); + kvm_vcpu_ioctl(CPU(s->cpu), KVM_TPR_ACCESS_REPORTING, &ctl); } static void kvm_apic_vapic_base_update(APICCommonState *s) @@ -114,7 +114,7 @@ static void kvm_apic_vapic_base_update(APICCommonState *s) }; int ret; - ret = kvm_vcpu_ioctl(s->cpu_env, KVM_SET_VAPIC_ADDR, &vapid_addr); + ret = kvm_vcpu_ioctl(CPU(s->cpu), KVM_SET_VAPIC_ADDR, &vapid_addr); if (ret < 0) { fprintf(stderr, "KVM: setting VAPIC address failed (%s)\n", strerror(-ret)); @@ -125,15 +125,15 @@ static void kvm_apic_vapic_base_update(APICCommonState *s) static void do_inject_external_nmi(void *data) { APICCommonState *s = data; - CPUX86State *env = s->cpu_env; + CPUState *cpu = CPU(s->cpu); uint32_t lvt; int ret; - cpu_synchronize_state(env); + cpu_synchronize_state(&s->cpu->env); lvt = s->lvt[APIC_LVT_LINT1]; if (!(lvt & APIC_LVT_MASKED) && ((lvt >> 8) & 7) == APIC_DM_NMI) { - ret = kvm_vcpu_ioctl(env, KVM_NMI); + ret = kvm_vcpu_ioctl(cpu, KVM_NMI); if (ret < 0) { fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n", strerror(-ret)); @@ -143,16 +143,16 @@ static void do_inject_external_nmi(void *data) static void kvm_apic_external_nmi(APICCommonState *s) { - run_on_cpu(s->cpu_env, do_inject_external_nmi, s); + run_on_cpu(CPU(s->cpu), do_inject_external_nmi, s); } -static uint64_t kvm_apic_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t kvm_apic_mem_read(void *opaque, hwaddr addr, unsigned size) { return ~(uint64_t)0; } -static void kvm_apic_mem_write(void *opaque, target_phys_addr_t addr, +static void kvm_apic_mem_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { MSIMessage msg = { .address = addr, .data = data }; diff --git a/hw/kvm/clock.c b/hw/kvm/clock.c index 824b978397..be24973df9 100644 --- a/hw/kvm/clock.c +++ b/hw/kvm/clock.c @@ -14,8 +14,8 @@ */ #include "qemu-common.h" -#include "sysemu.h" -#include "kvm.h" +#include "sysemu/sysemu.h" +#include "sysemu/kvm.h" #include "hw/sysbus.h" #include "hw/kvm/clock.h" @@ -76,7 +76,7 @@ static void kvmclock_vm_state_change(void *opaque, int running, return; } for (penv = first_cpu; penv != NULL; penv = penv->next_cpu) { - ret = kvm_vcpu_ioctl(penv, KVM_KVMCLOCK_CTRL, 0); + ret = kvm_vcpu_ioctl(ENV_GET_CPU(penv), KVM_KVMCLOCK_CTRL, 0); if (ret) { if (ret != -EINVAL) { fprintf(stderr, "%s: %s\n", __func__, strerror(-ret)); diff --git a/hw/kvm/i8254.c b/hw/kvm/i8254.c index 53d13e3123..57faf64ab2 100644 --- a/hw/kvm/i8254.c +++ b/hw/kvm/i8254.c @@ -22,11 +22,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "qemu-timer.h" -#include "sysemu.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" #include "hw/i8254.h" #include "hw/i8254_internal.h" -#include "kvm.h" +#include "sysemu/kvm.h" #define KVM_PIT_REINJECT_BIT 0 diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c index 1e24cd4f36..70e1d185de 100644 --- a/hw/kvm/i8259.c +++ b/hw/kvm/i8259.c @@ -11,7 +11,7 @@ */ #include "hw/i8259_internal.h" #include "hw/apic_internal.h" -#include "kvm.h" +#include "sysemu/kvm.h" static void kvm_pic_get(PICCommonState *s) { diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c index 6c3b8fe39a..30db6230b4 100644 --- a/hw/kvm/ioapic.c +++ b/hw/kvm/ioapic.c @@ -13,7 +13,47 @@ #include "hw/pc.h" #include "hw/ioapic_internal.h" #include "hw/apic_internal.h" -#include "kvm.h" +#include "sysemu/kvm.h" + +/* PC Utility function */ +void kvm_pc_setup_irq_routing(bool pci_enabled) +{ + KVMState *s = kvm_state; + int i; + + if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) { + for (i = 0; i < 8; ++i) { + if (i == 2) { + continue; + } + kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_MASTER, i); + } + for (i = 8; i < 16; ++i) { + kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8); + } + if (pci_enabled) { + for (i = 0; i < 24; ++i) { + if (i == 0) { + kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, 2); + } else if (i != 2) { + kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, i); + } + } + } + } +} + +void kvm_pc_gsi_handler(void *opaque, int n, int level) +{ + GSIState *s = opaque; + + if (n < ISA_NUM_IRQS) { + /* Kernel will forward to both PIC and IOAPIC */ + qemu_set_irq(s->i8259_irq[n], level); + } else { + qemu_set_irq(s->ioapic_irq[n], level); + } +} typedef struct KVMIOAPICState KVMIOAPICState; diff --git a/hw/kvm/pci-assign.c b/hw/kvm/pci-assign.c new file mode 100644 index 0000000000..8ee94287ff --- /dev/null +++ b/hw/kvm/pci-assign.c @@ -0,0 +1,1911 @@ +/* + * Copyright (c) 2007, Neocleus Corporation. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * + * Assign a PCI device from the host to a guest VM. + * + * This implementation uses the classic device assignment interface of KVM + * and is only available on x86 hosts. It is expected to be obsoleted by VFIO + * based device assignment. + * + * Adapted for KVM (qemu-kvm) by Qumranet. QEMU version was based on qemu-kvm + * revision 4144fe9d48. See its repository for the history. + * + * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com) + * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com) + * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com) + * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com) + * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com) + */ +#include <stdio.h> +#include <unistd.h> +#include <sys/io.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "hw/hw.h" +#include "hw/pc.h" +#include "qemu/error-report.h" +#include "ui/console.h" +#include "hw/loader.h" +#include "monitor/monitor.h" +#include "qemu/range.h" +#include "sysemu/sysemu.h" +#include "hw/pci/pci.h" +#include "hw/pci/msi.h" +#include "kvm_i386.h" + +#define MSIX_PAGE_SIZE 0x1000 + +/* From linux/ioport.h */ +#define IORESOURCE_IO 0x00000100 /* Resource type */ +#define IORESOURCE_MEM 0x00000200 +#define IORESOURCE_IRQ 0x00000400 +#define IORESOURCE_DMA 0x00000800 +#define IORESOURCE_PREFETCH 0x00002000 /* No side effects */ +#define IORESOURCE_MEM_64 0x00100000 + +//#define DEVICE_ASSIGNMENT_DEBUG + +#ifdef DEVICE_ASSIGNMENT_DEBUG +#define DEBUG(fmt, ...) \ + do { \ + fprintf(stderr, "%s: " fmt, __func__ , __VA_ARGS__); \ + } while (0) +#else +#define DEBUG(fmt, ...) +#endif + +typedef struct PCIRegion { + int type; /* Memory or port I/O */ + int valid; + uint64_t base_addr; + uint64_t size; /* size of the region */ + int resource_fd; +} PCIRegion; + +typedef struct PCIDevRegions { + uint8_t bus, dev, func; /* Bus inside domain, device and function */ + int irq; /* IRQ number */ + uint16_t region_number; /* number of active regions */ + + /* Port I/O or MMIO Regions */ + PCIRegion regions[PCI_NUM_REGIONS - 1]; + int config_fd; +} PCIDevRegions; + +typedef struct AssignedDevRegion { + MemoryRegion container; + MemoryRegion real_iomem; + union { + uint8_t *r_virtbase; /* mmapped access address for memory regions */ + uint32_t r_baseport; /* the base guest port for I/O regions */ + } u; + pcibus_t e_size; /* emulated size of region in bytes */ + pcibus_t r_size; /* real size of region in bytes */ + PCIRegion *region; +} AssignedDevRegion; + +#define ASSIGNED_DEVICE_PREFER_MSI_BIT 0 +#define ASSIGNED_DEVICE_SHARE_INTX_BIT 1 + +#define ASSIGNED_DEVICE_PREFER_MSI_MASK (1 << ASSIGNED_DEVICE_PREFER_MSI_BIT) +#define ASSIGNED_DEVICE_SHARE_INTX_MASK (1 << ASSIGNED_DEVICE_SHARE_INTX_BIT) + +typedef struct MSIXTableEntry { + uint32_t addr_lo; + uint32_t addr_hi; + uint32_t data; + uint32_t ctrl; +} MSIXTableEntry; + +typedef enum AssignedIRQType { + ASSIGNED_IRQ_NONE = 0, + ASSIGNED_IRQ_INTX_HOST_INTX, + ASSIGNED_IRQ_INTX_HOST_MSI, + ASSIGNED_IRQ_MSI, + ASSIGNED_IRQ_MSIX +} AssignedIRQType; + +typedef struct AssignedDevice { + PCIDevice dev; + PCIHostDeviceAddress host; + uint32_t dev_id; + uint32_t features; + int intpin; + AssignedDevRegion v_addrs[PCI_NUM_REGIONS - 1]; + PCIDevRegions real_device; + PCIINTxRoute intx_route; + AssignedIRQType assigned_irq_type; + struct { +#define ASSIGNED_DEVICE_CAP_MSI (1 << 0) +#define ASSIGNED_DEVICE_CAP_MSIX (1 << 1) + uint32_t available; +#define ASSIGNED_DEVICE_MSI_ENABLED (1 << 0) +#define ASSIGNED_DEVICE_MSIX_ENABLED (1 << 1) +#define ASSIGNED_DEVICE_MSIX_MASKED (1 << 2) + uint32_t state; + } cap; + uint8_t emulate_config_read[PCI_CONFIG_SPACE_SIZE]; + uint8_t emulate_config_write[PCI_CONFIG_SPACE_SIZE]; + int msi_virq_nr; + int *msi_virq; + MSIXTableEntry *msix_table; + hwaddr msix_table_addr; + uint16_t msix_max; + MemoryRegion mmio; + char *configfd_name; + int32_t bootindex; +} AssignedDevice; + +static void assigned_dev_update_irq_routing(PCIDevice *dev); + +static void assigned_dev_load_option_rom(AssignedDevice *dev); + +static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev); + +static uint64_t assigned_dev_ioport_rw(AssignedDevRegion *dev_region, + hwaddr addr, int size, + uint64_t *data) +{ + uint64_t val = 0; + int fd = dev_region->region->resource_fd; + + if (fd >= 0) { + if (data) { + DEBUG("pwrite data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx + ", addr="TARGET_FMT_plx"\n", *data, size, addr, addr); + if (pwrite(fd, data, size, addr) != size) { + error_report("%s - pwrite failed %s", + __func__, strerror(errno)); + } + } else { + if (pread(fd, &val, size, addr) != size) { + error_report("%s - pread failed %s", + __func__, strerror(errno)); + val = (1UL << (size * 8)) - 1; + } + DEBUG("pread val=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx + ", addr=" TARGET_FMT_plx "\n", val, size, addr, addr); + } + } else { + uint32_t port = addr + dev_region->u.r_baseport; + + if (data) { + DEBUG("out data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx + ", host=%x\n", *data, size, addr, port); + switch (size) { + case 1: + outb(*data, port); + break; + case 2: + outw(*data, port); + break; + case 4: + outl(*data, port); + break; + } + } else { + switch (size) { + case 1: + val = inb(port); + break; + case 2: + val = inw(port); + break; + case 4: + val = inl(port); + break; + } + DEBUG("in data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx + ", host=%x\n", val, size, addr, port); + } + } + return val; +} + +static void assigned_dev_ioport_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + assigned_dev_ioport_rw(opaque, addr, size, &data); +} + +static uint64_t assigned_dev_ioport_read(void *opaque, + hwaddr addr, unsigned size) +{ + return assigned_dev_ioport_rw(opaque, addr, size, NULL); +} + +static uint32_t slow_bar_readb(void *opaque, hwaddr addr) +{ + AssignedDevRegion *d = opaque; + uint8_t *in = d->u.r_virtbase + addr; + uint32_t r; + + r = *in; + DEBUG("slow_bar_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, r); + + return r; +} + +static uint32_t slow_bar_readw(void *opaque, hwaddr addr) +{ + AssignedDevRegion *d = opaque; + uint16_t *in = (uint16_t *)(d->u.r_virtbase + addr); + uint32_t r; + + r = *in; + DEBUG("slow_bar_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, r); + + return r; +} + +static uint32_t slow_bar_readl(void *opaque, hwaddr addr) +{ + AssignedDevRegion *d = opaque; + uint32_t *in = (uint32_t *)(d->u.r_virtbase + addr); + uint32_t r; + + r = *in; + DEBUG("slow_bar_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, r); + + return r; +} + +static void slow_bar_writeb(void *opaque, hwaddr addr, uint32_t val) +{ + AssignedDevRegion *d = opaque; + uint8_t *out = d->u.r_virtbase + addr; + + DEBUG("slow_bar_writeb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr, val); + *out = val; +} + +static void slow_bar_writew(void *opaque, hwaddr addr, uint32_t val) +{ + AssignedDevRegion *d = opaque; + uint16_t *out = (uint16_t *)(d->u.r_virtbase + addr); + + DEBUG("slow_bar_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr, val); + *out = val; +} + +static void slow_bar_writel(void *opaque, hwaddr addr, uint32_t val) +{ + AssignedDevRegion *d = opaque; + uint32_t *out = (uint32_t *)(d->u.r_virtbase + addr); + + DEBUG("slow_bar_writel addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, val); + *out = val; +} + +static const MemoryRegionOps slow_bar_ops = { + .old_mmio = { + .read = { slow_bar_readb, slow_bar_readw, slow_bar_readl, }, + .write = { slow_bar_writeb, slow_bar_writew, slow_bar_writel, }, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void assigned_dev_iomem_setup(PCIDevice *pci_dev, int region_num, + pcibus_t e_size) +{ + AssignedDevice *r_dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + AssignedDevRegion *region = &r_dev->v_addrs[region_num]; + PCIRegion *real_region = &r_dev->real_device.regions[region_num]; + + if (e_size > 0) { + memory_region_init(®ion->container, "assigned-dev-container", + e_size); + memory_region_add_subregion(®ion->container, 0, ®ion->real_iomem); + + /* deal with MSI-X MMIO page */ + if (real_region->base_addr <= r_dev->msix_table_addr && + real_region->base_addr + real_region->size > + r_dev->msix_table_addr) { + uint64_t offset = r_dev->msix_table_addr - real_region->base_addr; + + memory_region_add_subregion_overlap(®ion->container, + offset, + &r_dev->mmio, + 1); + } + } +} + +static const MemoryRegionOps assigned_dev_ioport_ops = { + .read = assigned_dev_ioport_read, + .write = assigned_dev_ioport_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void assigned_dev_ioport_setup(PCIDevice *pci_dev, int region_num, + pcibus_t size) +{ + AssignedDevice *r_dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + AssignedDevRegion *region = &r_dev->v_addrs[region_num]; + + region->e_size = size; + memory_region_init(®ion->container, "assigned-dev-container", size); + memory_region_init_io(®ion->real_iomem, &assigned_dev_ioport_ops, + r_dev->v_addrs + region_num, + "assigned-dev-iomem", size); + memory_region_add_subregion(®ion->container, 0, ®ion->real_iomem); +} + +static uint32_t assigned_dev_pci_read(PCIDevice *d, int pos, int len) +{ + AssignedDevice *pci_dev = DO_UPCAST(AssignedDevice, dev, d); + uint32_t val; + ssize_t ret; + int fd = pci_dev->real_device.config_fd; + +again: + ret = pread(fd, &val, len, pos); + if (ret != len) { + if ((ret < 0) && (errno == EINTR || errno == EAGAIN)) { + goto again; + } + + hw_error("pci read failed, ret = %zd errno = %d\n", ret, errno); + } + + return val; +} + +static uint8_t assigned_dev_pci_read_byte(PCIDevice *d, int pos) +{ + return (uint8_t)assigned_dev_pci_read(d, pos, 1); +} + +static void assigned_dev_pci_write(PCIDevice *d, int pos, uint32_t val, int len) +{ + AssignedDevice *pci_dev = DO_UPCAST(AssignedDevice, dev, d); + ssize_t ret; + int fd = pci_dev->real_device.config_fd; + +again: + ret = pwrite(fd, &val, len, pos); + if (ret != len) { + if ((ret < 0) && (errno == EINTR || errno == EAGAIN)) { + goto again; + } + + hw_error("pci write failed, ret = %zd errno = %d\n", ret, errno); + } +} + +static void assigned_dev_emulate_config_read(AssignedDevice *dev, + uint32_t offset, uint32_t len) +{ + memset(dev->emulate_config_read + offset, 0xff, len); +} + +static void assigned_dev_direct_config_read(AssignedDevice *dev, + uint32_t offset, uint32_t len) +{ + memset(dev->emulate_config_read + offset, 0, len); +} + +static void assigned_dev_direct_config_write(AssignedDevice *dev, + uint32_t offset, uint32_t len) +{ + memset(dev->emulate_config_write + offset, 0, len); +} + +static uint8_t pci_find_cap_offset(PCIDevice *d, uint8_t cap, uint8_t start) +{ + int id; + int max_cap = 48; + int pos = start ? start : PCI_CAPABILITY_LIST; + int status; + + status = assigned_dev_pci_read_byte(d, PCI_STATUS); + if ((status & PCI_STATUS_CAP_LIST) == 0) { + return 0; + } + + while (max_cap--) { + pos = assigned_dev_pci_read_byte(d, pos); + if (pos < 0x40) { + break; + } + + pos &= ~3; + id = assigned_dev_pci_read_byte(d, pos + PCI_CAP_LIST_ID); + + if (id == 0xff) { + break; + } + if (id == cap) { + return pos; + } + + pos += PCI_CAP_LIST_NEXT; + } + return 0; +} + +static int assigned_dev_register_regions(PCIRegion *io_regions, + unsigned long regions_num, + AssignedDevice *pci_dev) +{ + uint32_t i; + PCIRegion *cur_region = io_regions; + + for (i = 0; i < regions_num; i++, cur_region++) { + if (!cur_region->valid) { + continue; + } + + /* handle memory io regions */ + if (cur_region->type & IORESOURCE_MEM) { + int t = PCI_BASE_ADDRESS_SPACE_MEMORY; + if (cur_region->type & IORESOURCE_PREFETCH) { + t |= PCI_BASE_ADDRESS_MEM_PREFETCH; + } + if (cur_region->type & IORESOURCE_MEM_64) { + t |= PCI_BASE_ADDRESS_MEM_TYPE_64; + } + + /* map physical memory */ + pci_dev->v_addrs[i].u.r_virtbase = mmap(NULL, cur_region->size, + PROT_WRITE | PROT_READ, + MAP_SHARED, + cur_region->resource_fd, + (off_t)0); + + if (pci_dev->v_addrs[i].u.r_virtbase == MAP_FAILED) { + pci_dev->v_addrs[i].u.r_virtbase = NULL; + error_report("%s: Error: Couldn't mmap 0x%" PRIx64 "!", + __func__, cur_region->base_addr); + return -1; + } + + pci_dev->v_addrs[i].r_size = cur_region->size; + pci_dev->v_addrs[i].e_size = 0; + + /* add offset */ + pci_dev->v_addrs[i].u.r_virtbase += + (cur_region->base_addr & 0xFFF); + + if (cur_region->size & 0xFFF) { + error_report("PCI region %d at address 0x%" PRIx64 " has " + "size 0x%" PRIx64 ", which is not a multiple of " + "4K. You might experience some performance hit " + "due to that.", + i, cur_region->base_addr, cur_region->size); + memory_region_init_io(&pci_dev->v_addrs[i].real_iomem, + &slow_bar_ops, &pci_dev->v_addrs[i], + "assigned-dev-slow-bar", + cur_region->size); + } else { + void *virtbase = pci_dev->v_addrs[i].u.r_virtbase; + char name[32]; + snprintf(name, sizeof(name), "%s.bar%d", + object_get_typename(OBJECT(pci_dev)), i); + memory_region_init_ram_ptr(&pci_dev->v_addrs[i].real_iomem, + name, cur_region->size, + virtbase); + vmstate_register_ram(&pci_dev->v_addrs[i].real_iomem, + &pci_dev->dev.qdev); + } + + assigned_dev_iomem_setup(&pci_dev->dev, i, cur_region->size); + pci_register_bar((PCIDevice *) pci_dev, i, t, + &pci_dev->v_addrs[i].container); + continue; + } else { + /* handle port io regions */ + uint32_t val; + int ret; + + /* Test kernel support for ioport resource read/write. Old + * kernels return EIO. New kernels only allow 1/2/4 byte reads + * so should return EINVAL for a 3 byte read */ + ret = pread(pci_dev->v_addrs[i].region->resource_fd, &val, 3, 0); + if (ret >= 0) { + error_report("Unexpected return from I/O port read: %d", ret); + abort(); + } else if (errno != EINVAL) { + error_report("Kernel doesn't support ioport resource " + "access, hiding this region."); + close(pci_dev->v_addrs[i].region->resource_fd); + cur_region->valid = 0; + continue; + } + + pci_dev->v_addrs[i].u.r_baseport = cur_region->base_addr; + pci_dev->v_addrs[i].r_size = cur_region->size; + pci_dev->v_addrs[i].e_size = 0; + + assigned_dev_ioport_setup(&pci_dev->dev, i, cur_region->size); + pci_register_bar((PCIDevice *) pci_dev, i, + PCI_BASE_ADDRESS_SPACE_IO, + &pci_dev->v_addrs[i].container); + } + } + + /* success */ + return 0; +} + +static int get_real_id(const char *devpath, const char *idname, uint16_t *val) +{ + FILE *f; + char name[128]; + long id; + + snprintf(name, sizeof(name), "%s%s", devpath, idname); + f = fopen(name, "r"); + if (f == NULL) { + error_report("%s: %s: %m", __func__, name); + return -1; + } + if (fscanf(f, "%li\n", &id) == 1) { + *val = id; + } else { + return -1; + } + fclose(f); + + return 0; +} + +static int get_real_vendor_id(const char *devpath, uint16_t *val) +{ + return get_real_id(devpath, "vendor", val); +} + +static int get_real_device_id(const char *devpath, uint16_t *val) +{ + return get_real_id(devpath, "device", val); +} + +static int get_real_device(AssignedDevice *pci_dev, uint16_t r_seg, + uint8_t r_bus, uint8_t r_dev, uint8_t r_func) +{ + char dir[128], name[128]; + int fd, r = 0, v; + FILE *f; + uint64_t start, end, size, flags; + uint16_t id; + PCIRegion *rp; + PCIDevRegions *dev = &pci_dev->real_device; + + dev->region_number = 0; + + snprintf(dir, sizeof(dir), "/sys/bus/pci/devices/%04x:%02x:%02x.%x/", + r_seg, r_bus, r_dev, r_func); + + snprintf(name, sizeof(name), "%sconfig", dir); + + if (pci_dev->configfd_name && *pci_dev->configfd_name) { + dev->config_fd = monitor_handle_fd_param(cur_mon, pci_dev->configfd_name); + if (dev->config_fd < 0) { + return 1; + } + } else { + dev->config_fd = open(name, O_RDWR); + + if (dev->config_fd == -1) { + error_report("%s: %s: %m", __func__, name); + return 1; + } + } +again: + r = read(dev->config_fd, pci_dev->dev.config, + pci_config_size(&pci_dev->dev)); + if (r < 0) { + if (errno == EINTR || errno == EAGAIN) { + goto again; + } + error_report("%s: read failed, errno = %d", __func__, errno); + } + + /* Restore or clear multifunction, this is always controlled by qemu */ + if (pci_dev->dev.cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { + pci_dev->dev.config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION; + } else { + pci_dev->dev.config[PCI_HEADER_TYPE] &= ~PCI_HEADER_TYPE_MULTI_FUNCTION; + } + + /* Clear host resource mapping info. If we choose not to register a + * BAR, such as might be the case with the option ROM, we can get + * confusing, unwritable, residual addresses from the host here. */ + memset(&pci_dev->dev.config[PCI_BASE_ADDRESS_0], 0, 24); + memset(&pci_dev->dev.config[PCI_ROM_ADDRESS], 0, 4); + + snprintf(name, sizeof(name), "%sresource", dir); + + f = fopen(name, "r"); + if (f == NULL) { + error_report("%s: %s: %m", __func__, name); + return 1; + } + + for (r = 0; r < PCI_ROM_SLOT; r++) { + if (fscanf(f, "%" SCNi64 " %" SCNi64 " %" SCNi64 "\n", + &start, &end, &flags) != 3) { + break; + } + + rp = dev->regions + r; + rp->valid = 0; + rp->resource_fd = -1; + size = end - start + 1; + flags &= IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH + | IORESOURCE_MEM_64; + if (size == 0 || (flags & ~IORESOURCE_PREFETCH) == 0) { + continue; + } + if (flags & IORESOURCE_MEM) { + flags &= ~IORESOURCE_IO; + } else { + flags &= ~IORESOURCE_PREFETCH; + } + snprintf(name, sizeof(name), "%sresource%d", dir, r); + fd = open(name, O_RDWR); + if (fd == -1) { + continue; + } + rp->resource_fd = fd; + + rp->type = flags; + rp->valid = 1; + rp->base_addr = start; + rp->size = size; + pci_dev->v_addrs[r].region = rp; + DEBUG("region %d size %" PRIu64 " start 0x%" PRIx64 + " type %d resource_fd %d\n", + r, rp->size, start, rp->type, rp->resource_fd); + } + + fclose(f); + + /* read and fill vendor ID */ + v = get_real_vendor_id(dir, &id); + if (v) { + return 1; + } + pci_dev->dev.config[0] = id & 0xff; + pci_dev->dev.config[1] = (id & 0xff00) >> 8; + + /* read and fill device ID */ + v = get_real_device_id(dir, &id); + if (v) { + return 1; + } + pci_dev->dev.config[2] = id & 0xff; + pci_dev->dev.config[3] = (id & 0xff00) >> 8; + + pci_word_test_and_clear_mask(pci_dev->emulate_config_write + PCI_COMMAND, + PCI_COMMAND_MASTER | PCI_COMMAND_INTX_DISABLE); + + dev->region_number = r; + return 0; +} + +static void free_msi_virqs(AssignedDevice *dev) +{ + int i; + + for (i = 0; i < dev->msi_virq_nr; i++) { + if (dev->msi_virq[i] >= 0) { + kvm_irqchip_release_virq(kvm_state, dev->msi_virq[i]); + dev->msi_virq[i] = -1; + } + } + g_free(dev->msi_virq); + dev->msi_virq = NULL; + dev->msi_virq_nr = 0; +} + +static void free_assigned_device(AssignedDevice *dev) +{ + int i; + + if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) { + assigned_dev_unregister_msix_mmio(dev); + } + for (i = 0; i < dev->real_device.region_number; i++) { + PCIRegion *pci_region = &dev->real_device.regions[i]; + AssignedDevRegion *region = &dev->v_addrs[i]; + + if (!pci_region->valid) { + continue; + } + if (pci_region->type & IORESOURCE_IO) { + if (region->u.r_baseport) { + memory_region_del_subregion(®ion->container, + ®ion->real_iomem); + memory_region_destroy(®ion->real_iomem); + memory_region_destroy(®ion->container); + } + } else if (pci_region->type & IORESOURCE_MEM) { + if (region->u.r_virtbase) { + memory_region_del_subregion(®ion->container, + ®ion->real_iomem); + + /* Remove MSI-X table subregion */ + if (pci_region->base_addr <= dev->msix_table_addr && + pci_region->base_addr + pci_region->size > + dev->msix_table_addr) { + memory_region_del_subregion(®ion->container, + &dev->mmio); + } + + memory_region_destroy(®ion->real_iomem); + memory_region_destroy(®ion->container); + if (munmap(region->u.r_virtbase, + (pci_region->size + 0xFFF) & 0xFFFFF000)) { + error_report("Failed to unmap assigned device region: %s", + strerror(errno)); + } + } + } + if (pci_region->resource_fd >= 0) { + close(pci_region->resource_fd); + } + } + + if (dev->real_device.config_fd >= 0) { + close(dev->real_device.config_fd); + } + + free_msi_virqs(dev); +} + +static void assign_failed_examine(AssignedDevice *dev) +{ + char name[PATH_MAX], dir[PATH_MAX], driver[PATH_MAX] = {}, *ns; + uint16_t vendor_id, device_id; + int r; + + snprintf(dir, sizeof(dir), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/", + dev->host.domain, dev->host.bus, dev->host.slot, + dev->host.function); + + snprintf(name, sizeof(name), "%sdriver", dir); + + r = readlink(name, driver, sizeof(driver)); + if ((r <= 0) || r >= sizeof(driver)) { + goto fail; + } + + ns = strrchr(driver, '/'); + if (!ns) { + goto fail; + } + + ns++; + + if (get_real_vendor_id(dir, &vendor_id) || + get_real_device_id(dir, &device_id)) { + goto fail; + } + + error_report("*** The driver '%s' is occupying your device " + "%04x:%02x:%02x.%x.", + ns, dev->host.domain, dev->host.bus, dev->host.slot, + dev->host.function); + error_report("***"); + error_report("*** You can try the following commands to free it:"); + error_report("***"); + error_report("*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub/" + "new_id", vendor_id, device_id); + error_report("*** $ echo \"%04x:%02x:%02x.%x\" > /sys/bus/pci/drivers/" + "%s/unbind", + dev->host.domain, dev->host.bus, dev->host.slot, + dev->host.function, ns); + error_report("*** $ echo \"%04x:%02x:%02x.%x\" > /sys/bus/pci/drivers/" + "pci-stub/bind", + dev->host.domain, dev->host.bus, dev->host.slot, + dev->host.function); + error_report("*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub" + "/remove_id", vendor_id, device_id); + error_report("***"); + + return; + +fail: + error_report("Couldn't find out why."); +} + +static int assign_device(AssignedDevice *dev) +{ + uint32_t flags = KVM_DEV_ASSIGN_ENABLE_IOMMU; + int r; + + /* Only pass non-zero PCI segment to capable module */ + if (!kvm_check_extension(kvm_state, KVM_CAP_PCI_SEGMENT) && + dev->host.domain) { + error_report("Can't assign device inside non-zero PCI segment " + "as this KVM module doesn't support it."); + return -ENODEV; + } + + if (!kvm_check_extension(kvm_state, KVM_CAP_IOMMU)) { + error_report("No IOMMU found. Unable to assign device \"%s\"", + dev->dev.qdev.id); + return -ENODEV; + } + + if (dev->features & ASSIGNED_DEVICE_SHARE_INTX_MASK && + kvm_has_intx_set_mask()) { + flags |= KVM_DEV_ASSIGN_PCI_2_3; + } + + r = kvm_device_pci_assign(kvm_state, &dev->host, flags, &dev->dev_id); + if (r < 0) { + error_report("Failed to assign device \"%s\" : %s", + dev->dev.qdev.id, strerror(-r)); + + switch (r) { + case -EBUSY: + assign_failed_examine(dev); + break; + default: + break; + } + } + return r; +} + +static bool check_irqchip_in_kernel(void) +{ + if (kvm_irqchip_in_kernel()) { + return true; + } + error_report("pci-assign: error: requires KVM with in-kernel irqchip " + "enabled"); + return false; +} + +static int assign_intx(AssignedDevice *dev) +{ + AssignedIRQType new_type; + PCIINTxRoute intx_route; + bool intx_host_msi; + int r; + + /* Interrupt PIN 0 means don't use INTx */ + if (assigned_dev_pci_read_byte(&dev->dev, PCI_INTERRUPT_PIN) == 0) { + pci_device_set_intx_routing_notifier(&dev->dev, NULL); + return 0; + } + + if (!check_irqchip_in_kernel()) { + return -ENOTSUP; + } + + pci_device_set_intx_routing_notifier(&dev->dev, + assigned_dev_update_irq_routing); + + intx_route = pci_device_route_intx_to_irq(&dev->dev, dev->intpin); + assert(intx_route.mode != PCI_INTX_INVERTED); + + if (!pci_intx_route_changed(&dev->intx_route, &intx_route)) { + return 0; + } + + switch (dev->assigned_irq_type) { + case ASSIGNED_IRQ_INTX_HOST_INTX: + case ASSIGNED_IRQ_INTX_HOST_MSI: + intx_host_msi = dev->assigned_irq_type == ASSIGNED_IRQ_INTX_HOST_MSI; + r = kvm_device_intx_deassign(kvm_state, dev->dev_id, intx_host_msi); + break; + case ASSIGNED_IRQ_MSI: + r = kvm_device_msi_deassign(kvm_state, dev->dev_id); + break; + case ASSIGNED_IRQ_MSIX: + r = kvm_device_msix_deassign(kvm_state, dev->dev_id); + break; + default: + r = 0; + break; + } + if (r) { + perror("assign_intx: deassignment of previous interrupt failed"); + } + dev->assigned_irq_type = ASSIGNED_IRQ_NONE; + + if (intx_route.mode == PCI_INTX_DISABLED) { + dev->intx_route = intx_route; + return 0; + } + +retry: + if (dev->features & ASSIGNED_DEVICE_PREFER_MSI_MASK && + dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) { + intx_host_msi = true; + new_type = ASSIGNED_IRQ_INTX_HOST_MSI; + } else { + intx_host_msi = false; + new_type = ASSIGNED_IRQ_INTX_HOST_INTX; + } + + r = kvm_device_intx_assign(kvm_state, dev->dev_id, intx_host_msi, + intx_route.irq); + if (r < 0) { + if (r == -EIO && !(dev->features & ASSIGNED_DEVICE_PREFER_MSI_MASK) && + dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) { + /* Retry with host-side MSI. There might be an IRQ conflict and + * either the kernel or the device doesn't support sharing. */ + error_report("Host-side INTx sharing not supported, " + "using MSI instead.\n" + "Some devices do not to work properly in this mode."); + dev->features |= ASSIGNED_DEVICE_PREFER_MSI_MASK; + goto retry; + } + error_report("Failed to assign irq for \"%s\": %s", + dev->dev.qdev.id, strerror(-r)); + error_report("Perhaps you are assigning a device " + "that shares an IRQ with another device?"); + return r; + } + + dev->intx_route = intx_route; + dev->assigned_irq_type = new_type; + return r; +} + +static void deassign_device(AssignedDevice *dev) +{ + int r; + + r = kvm_device_pci_deassign(kvm_state, dev->dev_id); + assert(r == 0); +} + +/* The pci config space got updated. Check if irq numbers have changed + * for our devices + */ +static void assigned_dev_update_irq_routing(PCIDevice *dev) +{ + AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, dev); + Error *err = NULL; + int r; + + r = assign_intx(assigned_dev); + if (r < 0) { + qdev_unplug(&dev->qdev, &err); + assert(!err); + } +} + +static void assigned_dev_update_msi(PCIDevice *pci_dev) +{ + AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + uint8_t ctrl_byte = pci_get_byte(pci_dev->config + pci_dev->msi_cap + + PCI_MSI_FLAGS); + int r; + + /* Some guests gratuitously disable MSI even if they're not using it, + * try to catch this by only deassigning irqs if the guest is using + * MSI or intends to start. */ + if (assigned_dev->assigned_irq_type == ASSIGNED_IRQ_MSI || + (ctrl_byte & PCI_MSI_FLAGS_ENABLE)) { + r = kvm_device_msi_deassign(kvm_state, assigned_dev->dev_id); + /* -ENXIO means no assigned irq */ + if (r && r != -ENXIO) { + perror("assigned_dev_update_msi: deassign irq"); + } + + free_msi_virqs(assigned_dev); + + assigned_dev->assigned_irq_type = ASSIGNED_IRQ_NONE; + pci_device_set_intx_routing_notifier(pci_dev, NULL); + } + + if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) { + MSIMessage msg = msi_get_message(pci_dev, 0); + int virq; + + virq = kvm_irqchip_add_msi_route(kvm_state, msg); + if (virq < 0) { + perror("assigned_dev_update_msi: kvm_irqchip_add_msi_route"); + return; + } + + assigned_dev->msi_virq = g_malloc(sizeof(*assigned_dev->msi_virq)); + assigned_dev->msi_virq_nr = 1; + assigned_dev->msi_virq[0] = virq; + if (kvm_device_msi_assign(kvm_state, assigned_dev->dev_id, virq) < 0) { + perror("assigned_dev_update_msi: kvm_device_msi_assign"); + } + + assigned_dev->intx_route.mode = PCI_INTX_DISABLED; + assigned_dev->intx_route.irq = -1; + assigned_dev->assigned_irq_type = ASSIGNED_IRQ_MSI; + } else { + assign_intx(assigned_dev); + } +} + +static bool assigned_dev_msix_masked(MSIXTableEntry *entry) +{ + return (entry->ctrl & cpu_to_le32(0x1)) != 0; +} + +static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev) +{ + AssignedDevice *adev = DO_UPCAST(AssignedDevice, dev, pci_dev); + uint16_t entries_nr = 0; + int i, r = 0; + MSIXTableEntry *entry = adev->msix_table; + MSIMessage msg; + + /* Get the usable entry number for allocating */ + for (i = 0; i < adev->msix_max; i++, entry++) { + if (assigned_dev_msix_masked(entry)) { + continue; + } + entries_nr++; + } + + DEBUG("MSI-X entries: %d\n", entries_nr); + + /* It's valid to enable MSI-X with all entries masked */ + if (!entries_nr) { + return 0; + } + + r = kvm_device_msix_init_vectors(kvm_state, adev->dev_id, entries_nr); + if (r != 0) { + error_report("fail to set MSI-X entry number for MSIX! %s", + strerror(-r)); + return r; + } + + free_msi_virqs(adev); + + adev->msi_virq_nr = adev->msix_max; + adev->msi_virq = g_malloc(adev->msix_max * sizeof(*adev->msi_virq)); + + entry = adev->msix_table; + for (i = 0; i < adev->msix_max; i++, entry++) { + adev->msi_virq[i] = -1; + + if (assigned_dev_msix_masked(entry)) { + continue; + } + + msg.address = entry->addr_lo | ((uint64_t)entry->addr_hi << 32); + msg.data = entry->data; + r = kvm_irqchip_add_msi_route(kvm_state, msg); + if (r < 0) { + return r; + } + adev->msi_virq[i] = r; + + DEBUG("MSI-X vector %d, gsi %d, addr %08x_%08x, data %08x\n", i, + r, entry->addr_hi, entry->addr_lo, entry->data); + + r = kvm_device_msix_set_vector(kvm_state, adev->dev_id, i, + adev->msi_virq[i]); + if (r) { + error_report("fail to set MSI-X entry! %s", strerror(-r)); + break; + } + } + + return r; +} + +static void assigned_dev_update_msix(PCIDevice *pci_dev) +{ + AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + uint16_t ctrl_word = pci_get_word(pci_dev->config + pci_dev->msix_cap + + PCI_MSIX_FLAGS); + int r; + + /* Some guests gratuitously disable MSIX even if they're not using it, + * try to catch this by only deassigning irqs if the guest is using + * MSIX or intends to start. */ + if ((assigned_dev->assigned_irq_type == ASSIGNED_IRQ_MSIX) || + (ctrl_word & PCI_MSIX_FLAGS_ENABLE)) { + r = kvm_device_msix_deassign(kvm_state, assigned_dev->dev_id); + /* -ENXIO means no assigned irq */ + if (r && r != -ENXIO) { + perror("assigned_dev_update_msix: deassign irq"); + } + + free_msi_virqs(assigned_dev); + + assigned_dev->assigned_irq_type = ASSIGNED_IRQ_NONE; + pci_device_set_intx_routing_notifier(pci_dev, NULL); + } + + if (ctrl_word & PCI_MSIX_FLAGS_ENABLE) { + if (assigned_dev_update_msix_mmio(pci_dev) < 0) { + perror("assigned_dev_update_msix_mmio"); + return; + } + + if (assigned_dev->msi_virq_nr > 0) { + if (kvm_device_msix_assign(kvm_state, assigned_dev->dev_id) < 0) { + perror("assigned_dev_enable_msix: assign irq"); + return; + } + } + assigned_dev->intx_route.mode = PCI_INTX_DISABLED; + assigned_dev->intx_route.irq = -1; + assigned_dev->assigned_irq_type = ASSIGNED_IRQ_MSIX; + } else { + assign_intx(assigned_dev); + } +} + +static uint32_t assigned_dev_pci_read_config(PCIDevice *pci_dev, + uint32_t address, int len) +{ + AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + uint32_t virt_val = pci_default_read_config(pci_dev, address, len); + uint32_t real_val, emulate_mask, full_emulation_mask; + + emulate_mask = 0; + memcpy(&emulate_mask, assigned_dev->emulate_config_read + address, len); + emulate_mask = le32_to_cpu(emulate_mask); + + full_emulation_mask = 0xffffffff >> (32 - len * 8); + + if (emulate_mask != full_emulation_mask) { + real_val = assigned_dev_pci_read(pci_dev, address, len); + return (virt_val & emulate_mask) | (real_val & ~emulate_mask); + } else { + return virt_val; + } +} + +static void assigned_dev_pci_write_config(PCIDevice *pci_dev, uint32_t address, + uint32_t val, int len) +{ + AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + uint16_t old_cmd = pci_get_word(pci_dev->config + PCI_COMMAND); + uint32_t emulate_mask, full_emulation_mask; + int ret; + + pci_default_write_config(pci_dev, address, val, len); + + if (kvm_has_intx_set_mask() && + range_covers_byte(address, len, PCI_COMMAND + 1)) { + bool intx_masked = (pci_get_word(pci_dev->config + PCI_COMMAND) & + PCI_COMMAND_INTX_DISABLE); + + if (intx_masked != !!(old_cmd & PCI_COMMAND_INTX_DISABLE)) { + ret = kvm_device_intx_set_mask(kvm_state, assigned_dev->dev_id, + intx_masked); + if (ret) { + perror("assigned_dev_pci_write_config: set intx mask"); + } + } + } + if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) { + if (range_covers_byte(address, len, + pci_dev->msi_cap + PCI_MSI_FLAGS)) { + assigned_dev_update_msi(pci_dev); + } + } + if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) { + if (range_covers_byte(address, len, + pci_dev->msix_cap + PCI_MSIX_FLAGS + 1)) { + assigned_dev_update_msix(pci_dev); + } + } + + emulate_mask = 0; + memcpy(&emulate_mask, assigned_dev->emulate_config_write + address, len); + emulate_mask = le32_to_cpu(emulate_mask); + + full_emulation_mask = 0xffffffff >> (32 - len * 8); + + if (emulate_mask != full_emulation_mask) { + if (emulate_mask) { + val &= ~emulate_mask; + val |= assigned_dev_pci_read(pci_dev, address, len) & emulate_mask; + } + assigned_dev_pci_write(pci_dev, address, val, len); + } +} + +static void assigned_dev_setup_cap_read(AssignedDevice *dev, uint32_t offset, + uint32_t len) +{ + assigned_dev_direct_config_read(dev, offset, len); + assigned_dev_emulate_config_read(dev, offset + PCI_CAP_LIST_NEXT, 1); +} + +static int assigned_device_pci_cap_init(PCIDevice *pci_dev) +{ + AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + PCIRegion *pci_region = dev->real_device.regions; + int ret, pos; + + /* Clear initial capabilities pointer and status copied from hw */ + pci_set_byte(pci_dev->config + PCI_CAPABILITY_LIST, 0); + pci_set_word(pci_dev->config + PCI_STATUS, + pci_get_word(pci_dev->config + PCI_STATUS) & + ~PCI_STATUS_CAP_LIST); + + /* Expose MSI capability + * MSI capability is the 1st capability in capability config */ + pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSI, 0); + if (pos != 0 && kvm_check_extension(kvm_state, KVM_CAP_ASSIGN_DEV_IRQ)) { + if (!check_irqchip_in_kernel()) { + return -ENOTSUP; + } + dev->cap.available |= ASSIGNED_DEVICE_CAP_MSI; + /* Only 32-bit/no-mask currently supported */ + ret = pci_add_capability(pci_dev, PCI_CAP_ID_MSI, pos, 10); + if (ret < 0) { + return ret; + } + pci_dev->msi_cap = pos; + + pci_set_word(pci_dev->config + pos + PCI_MSI_FLAGS, + pci_get_word(pci_dev->config + pos + PCI_MSI_FLAGS) & + PCI_MSI_FLAGS_QMASK); + pci_set_long(pci_dev->config + pos + PCI_MSI_ADDRESS_LO, 0); + pci_set_word(pci_dev->config + pos + PCI_MSI_DATA_32, 0); + + /* Set writable fields */ + pci_set_word(pci_dev->wmask + pos + PCI_MSI_FLAGS, + PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); + pci_set_long(pci_dev->wmask + pos + PCI_MSI_ADDRESS_LO, 0xfffffffc); + pci_set_word(pci_dev->wmask + pos + PCI_MSI_DATA_32, 0xffff); + } + /* Expose MSI-X capability */ + pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSIX, 0); + if (pos != 0 && kvm_device_msix_supported(kvm_state)) { + int bar_nr; + uint32_t msix_table_entry; + + if (!check_irqchip_in_kernel()) { + return -ENOTSUP; + } + dev->cap.available |= ASSIGNED_DEVICE_CAP_MSIX; + ret = pci_add_capability(pci_dev, PCI_CAP_ID_MSIX, pos, 12); + if (ret < 0) { + return ret; + } + pci_dev->msix_cap = pos; + + pci_set_word(pci_dev->config + pos + PCI_MSIX_FLAGS, + pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS) & + PCI_MSIX_FLAGS_QSIZE); + + /* Only enable and function mask bits are writable */ + pci_set_word(pci_dev->wmask + pos + PCI_MSIX_FLAGS, + PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL); + + msix_table_entry = pci_get_long(pci_dev->config + pos + PCI_MSIX_TABLE); + bar_nr = msix_table_entry & PCI_MSIX_FLAGS_BIRMASK; + msix_table_entry &= ~PCI_MSIX_FLAGS_BIRMASK; + dev->msix_table_addr = pci_region[bar_nr].base_addr + msix_table_entry; + dev->msix_max = pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS); + dev->msix_max &= PCI_MSIX_FLAGS_QSIZE; + dev->msix_max += 1; + } + + /* Minimal PM support, nothing writable, device appears to NAK changes */ + pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_PM, 0); + if (pos) { + uint16_t pmc; + + ret = pci_add_capability(pci_dev, PCI_CAP_ID_PM, pos, PCI_PM_SIZEOF); + if (ret < 0) { + return ret; + } + + assigned_dev_setup_cap_read(dev, pos, PCI_PM_SIZEOF); + + pmc = pci_get_word(pci_dev->config + pos + PCI_CAP_FLAGS); + pmc &= (PCI_PM_CAP_VER_MASK | PCI_PM_CAP_DSI); + pci_set_word(pci_dev->config + pos + PCI_CAP_FLAGS, pmc); + + /* assign_device will bring the device up to D0, so we don't need + * to worry about doing that ourselves here. */ + pci_set_word(pci_dev->config + pos + PCI_PM_CTRL, + PCI_PM_CTRL_NO_SOFT_RESET); + + pci_set_byte(pci_dev->config + pos + PCI_PM_PPB_EXTENSIONS, 0); + pci_set_byte(pci_dev->config + pos + PCI_PM_DATA_REGISTER, 0); + } + + pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_EXP, 0); + if (pos) { + uint8_t version, size = 0; + uint16_t type, devctl, lnksta; + uint32_t devcap, lnkcap; + + version = pci_get_byte(pci_dev->config + pos + PCI_EXP_FLAGS); + version &= PCI_EXP_FLAGS_VERS; + if (version == 1) { + size = 0x14; + } else if (version == 2) { + /* + * Check for non-std size, accept reduced size to 0x34, + * which is what bcm5761 implemented, violating the + * PCIe v3.0 spec that regs should exist and be read as 0, + * not optionally provided and shorten the struct size. + */ + size = MIN(0x3c, PCI_CONFIG_SPACE_SIZE - pos); + if (size < 0x34) { + error_report("%s: Invalid size PCIe cap-id 0x%x", + __func__, PCI_CAP_ID_EXP); + return -EINVAL; + } else if (size != 0x3c) { + error_report("WARNING, %s: PCIe cap-id 0x%x has " + "non-standard size 0x%x; std size should be 0x3c", + __func__, PCI_CAP_ID_EXP, size); + } + } else if (version == 0) { + uint16_t vid, did; + vid = pci_get_word(pci_dev->config + PCI_VENDOR_ID); + did = pci_get_word(pci_dev->config + PCI_DEVICE_ID); + if (vid == PCI_VENDOR_ID_INTEL && did == 0x10ed) { + /* + * quirk for Intel 82599 VF with invalid PCIe capability + * version, should really be version 2 (same as PF) + */ + size = 0x3c; + } + } + + if (size == 0) { + error_report("%s: Unsupported PCI express capability version %d", + __func__, version); + return -EINVAL; + } + + ret = pci_add_capability(pci_dev, PCI_CAP_ID_EXP, pos, size); + if (ret < 0) { + return ret; + } + + assigned_dev_setup_cap_read(dev, pos, size); + + type = pci_get_word(pci_dev->config + pos + PCI_EXP_FLAGS); + type = (type & PCI_EXP_FLAGS_TYPE) >> 4; + if (type != PCI_EXP_TYPE_ENDPOINT && + type != PCI_EXP_TYPE_LEG_END && type != PCI_EXP_TYPE_RC_END) { + error_report("Device assignment only supports endpoint assignment," + " device type %d", type); + return -EINVAL; + } + + /* capabilities, pass existing read-only copy + * PCI_EXP_FLAGS_IRQ: updated by hardware, should be direct read */ + + /* device capabilities: hide FLR */ + devcap = pci_get_long(pci_dev->config + pos + PCI_EXP_DEVCAP); + devcap &= ~PCI_EXP_DEVCAP_FLR; + pci_set_long(pci_dev->config + pos + PCI_EXP_DEVCAP, devcap); + + /* device control: clear all error reporting enable bits, leaving + * only a few host values. Note, these are + * all writable, but not passed to hw. + */ + devctl = pci_get_word(pci_dev->config + pos + PCI_EXP_DEVCTL); + devctl = (devctl & (PCI_EXP_DEVCTL_READRQ | PCI_EXP_DEVCTL_PAYLOAD)) | + PCI_EXP_DEVCTL_RELAX_EN | PCI_EXP_DEVCTL_NOSNOOP_EN; + pci_set_word(pci_dev->config + pos + PCI_EXP_DEVCTL, devctl); + devctl = PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_AUX_PME; + pci_set_word(pci_dev->wmask + pos + PCI_EXP_DEVCTL, ~devctl); + + /* Clear device status */ + pci_set_word(pci_dev->config + pos + PCI_EXP_DEVSTA, 0); + + /* Link capabilities, expose links and latencues, clear reporting */ + lnkcap = pci_get_long(pci_dev->config + pos + PCI_EXP_LNKCAP); + lnkcap &= (PCI_EXP_LNKCAP_SLS | PCI_EXP_LNKCAP_MLW | + PCI_EXP_LNKCAP_ASPMS | PCI_EXP_LNKCAP_L0SEL | + PCI_EXP_LNKCAP_L1EL); + pci_set_long(pci_dev->config + pos + PCI_EXP_LNKCAP, lnkcap); + + /* Link control, pass existing read-only copy. Should be writable? */ + + /* Link status, only expose current speed and width */ + lnksta = pci_get_word(pci_dev->config + pos + PCI_EXP_LNKSTA); + lnksta &= (PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW); + pci_set_word(pci_dev->config + pos + PCI_EXP_LNKSTA, lnksta); + + if (version >= 2) { + /* Slot capabilities, control, status - not needed for endpoints */ + pci_set_long(pci_dev->config + pos + PCI_EXP_SLTCAP, 0); + pci_set_word(pci_dev->config + pos + PCI_EXP_SLTCTL, 0); + pci_set_word(pci_dev->config + pos + PCI_EXP_SLTSTA, 0); + + /* Root control, capabilities, status - not needed for endpoints */ + pci_set_word(pci_dev->config + pos + PCI_EXP_RTCTL, 0); + pci_set_word(pci_dev->config + pos + PCI_EXP_RTCAP, 0); + pci_set_long(pci_dev->config + pos + PCI_EXP_RTSTA, 0); + + /* Device capabilities/control 2, pass existing read-only copy */ + /* Link control 2, pass existing read-only copy */ + } + } + + pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_PCIX, 0); + if (pos) { + uint16_t cmd; + uint32_t status; + + /* Only expose the minimum, 8 byte capability */ + ret = pci_add_capability(pci_dev, PCI_CAP_ID_PCIX, pos, 8); + if (ret < 0) { + return ret; + } + + assigned_dev_setup_cap_read(dev, pos, 8); + + /* Command register, clear upper bits, including extended modes */ + cmd = pci_get_word(pci_dev->config + pos + PCI_X_CMD); + cmd &= (PCI_X_CMD_DPERR_E | PCI_X_CMD_ERO | PCI_X_CMD_MAX_READ | + PCI_X_CMD_MAX_SPLIT); + pci_set_word(pci_dev->config + pos + PCI_X_CMD, cmd); + + /* Status register, update with emulated PCI bus location, clear + * error bits, leave the rest. */ + status = pci_get_long(pci_dev->config + pos + PCI_X_STATUS); + status &= ~(PCI_X_STATUS_BUS | PCI_X_STATUS_DEVFN); + status |= (pci_bus_num(pci_dev->bus) << 8) | pci_dev->devfn; + status &= ~(PCI_X_STATUS_SPL_DISC | PCI_X_STATUS_UNX_SPL | + PCI_X_STATUS_SPL_ERR); + pci_set_long(pci_dev->config + pos + PCI_X_STATUS, status); + } + + pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_VPD, 0); + if (pos) { + /* Direct R/W passthrough */ + ret = pci_add_capability(pci_dev, PCI_CAP_ID_VPD, pos, 8); + if (ret < 0) { + return ret; + } + + assigned_dev_setup_cap_read(dev, pos, 8); + + /* direct write for cap content */ + assigned_dev_direct_config_write(dev, pos + 2, 6); + } + + /* Devices can have multiple vendor capabilities, get them all */ + for (pos = 0; (pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_VNDR, pos)); + pos += PCI_CAP_LIST_NEXT) { + uint8_t len = pci_get_byte(pci_dev->config + pos + PCI_CAP_FLAGS); + /* Direct R/W passthrough */ + ret = pci_add_capability(pci_dev, PCI_CAP_ID_VNDR, pos, len); + if (ret < 0) { + return ret; + } + + assigned_dev_setup_cap_read(dev, pos, len); + + /* direct write for cap content */ + assigned_dev_direct_config_write(dev, pos + 2, len - 2); + } + + /* If real and virtual capability list status bits differ, virtualize the + * access. */ + if ((pci_get_word(pci_dev->config + PCI_STATUS) & PCI_STATUS_CAP_LIST) != + (assigned_dev_pci_read_byte(pci_dev, PCI_STATUS) & + PCI_STATUS_CAP_LIST)) { + dev->emulate_config_read[PCI_STATUS] |= PCI_STATUS_CAP_LIST; + } + + return 0; +} + +static uint64_t +assigned_dev_msix_mmio_read(void *opaque, hwaddr addr, + unsigned size) +{ + AssignedDevice *adev = opaque; + uint64_t val; + + memcpy(&val, (void *)((uint8_t *)adev->msix_table + addr), size); + + return val; +} + +static void assigned_dev_msix_mmio_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + AssignedDevice *adev = opaque; + PCIDevice *pdev = &adev->dev; + uint16_t ctrl; + MSIXTableEntry orig; + int i = addr >> 4; + + if (i >= adev->msix_max) { + return; /* Drop write */ + } + + ctrl = pci_get_word(pdev->config + pdev->msix_cap + PCI_MSIX_FLAGS); + + DEBUG("write to MSI-X table offset 0x%lx, val 0x%lx\n", addr, val); + + if (ctrl & PCI_MSIX_FLAGS_ENABLE) { + orig = adev->msix_table[i]; + } + + memcpy((uint8_t *)adev->msix_table + addr, &val, size); + + if (ctrl & PCI_MSIX_FLAGS_ENABLE) { + MSIXTableEntry *entry = &adev->msix_table[i]; + + if (!assigned_dev_msix_masked(&orig) && + assigned_dev_msix_masked(entry)) { + /* + * Vector masked, disable it + * + * XXX It's not clear if we can or should actually attempt + * to mask or disable the interrupt. KVM doesn't have + * support for pending bits and kvm_assign_set_msix_entry + * doesn't modify the device hardware mask. Interrupts + * while masked are simply not injected to the guest, so + * are lost. Can we get away with always injecting an + * interrupt on unmask? + */ + } else if (assigned_dev_msix_masked(&orig) && + !assigned_dev_msix_masked(entry)) { + /* Vector unmasked */ + if (i >= adev->msi_virq_nr || adev->msi_virq[i] < 0) { + /* Previously unassigned vector, start from scratch */ + assigned_dev_update_msix(pdev); + return; + } else { + /* Update an existing, previously masked vector */ + MSIMessage msg; + int ret; + + msg.address = entry->addr_lo | + ((uint64_t)entry->addr_hi << 32); + msg.data = entry->data; + + ret = kvm_irqchip_update_msi_route(kvm_state, + adev->msi_virq[i], msg); + if (ret) { + error_report("Error updating irq routing entry (%d)", ret); + } + } + } + } +} + +static const MemoryRegionOps assigned_dev_msix_mmio_ops = { + .read = assigned_dev_msix_mmio_read, + .write = assigned_dev_msix_mmio_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 8, + }, +}; + +static void assigned_dev_msix_reset(AssignedDevice *dev) +{ + MSIXTableEntry *entry; + int i; + + if (!dev->msix_table) { + return; + } + + memset(dev->msix_table, 0, MSIX_PAGE_SIZE); + + for (i = 0, entry = dev->msix_table; i < dev->msix_max; i++, entry++) { + entry->ctrl = cpu_to_le32(0x1); /* Masked */ + } +} + +static int assigned_dev_register_msix_mmio(AssignedDevice *dev) +{ + dev->msix_table = mmap(NULL, MSIX_PAGE_SIZE, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, 0, 0); + if (dev->msix_table == MAP_FAILED) { + error_report("fail allocate msix_table! %s", strerror(errno)); + return -EFAULT; + } + + assigned_dev_msix_reset(dev); + + memory_region_init_io(&dev->mmio, &assigned_dev_msix_mmio_ops, dev, + "assigned-dev-msix", MSIX_PAGE_SIZE); + return 0; +} + +static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev) +{ + if (!dev->msix_table) { + return; + } + + memory_region_destroy(&dev->mmio); + + if (munmap(dev->msix_table, MSIX_PAGE_SIZE) == -1) { + error_report("error unmapping msix_table! %s", strerror(errno)); + } + dev->msix_table = NULL; +} + +static const VMStateDescription vmstate_assigned_device = { + .name = "pci-assign", + .unmigratable = 1, +}; + +static void reset_assigned_device(DeviceState *dev) +{ + PCIDevice *pci_dev = DO_UPCAST(PCIDevice, qdev, dev); + AssignedDevice *adev = DO_UPCAST(AssignedDevice, dev, pci_dev); + char reset_file[64]; + const char reset[] = "1"; + int fd, ret; + + /* + * If a guest is reset without being shutdown, MSI/MSI-X can still + * be running. We want to return the device to a known state on + * reset, so disable those here. We especially do not want MSI-X + * enabled since it lives in MMIO space, which is about to get + * disabled. + */ + if (adev->assigned_irq_type == ASSIGNED_IRQ_MSIX) { + uint16_t ctrl = pci_get_word(pci_dev->config + + pci_dev->msix_cap + PCI_MSIX_FLAGS); + + pci_set_word(pci_dev->config + pci_dev->msix_cap + PCI_MSIX_FLAGS, + ctrl & ~PCI_MSIX_FLAGS_ENABLE); + assigned_dev_update_msix(pci_dev); + } else if (adev->assigned_irq_type == ASSIGNED_IRQ_MSI) { + uint8_t ctrl = pci_get_byte(pci_dev->config + + pci_dev->msi_cap + PCI_MSI_FLAGS); + + pci_set_byte(pci_dev->config + pci_dev->msi_cap + PCI_MSI_FLAGS, + ctrl & ~PCI_MSI_FLAGS_ENABLE); + assigned_dev_update_msi(pci_dev); + } + + snprintf(reset_file, sizeof(reset_file), + "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/reset", + adev->host.domain, adev->host.bus, adev->host.slot, + adev->host.function); + + /* + * Issue a device reset via pci-sysfs. Note that we use write(2) here + * and ignore the return value because some kernels have a bug that + * returns 0 rather than bytes written on success, sending us into an + * infinite retry loop using other write mechanisms. + */ + fd = open(reset_file, O_WRONLY); + if (fd != -1) { + ret = write(fd, reset, strlen(reset)); + (void)ret; + close(fd); + } + + /* + * When a 0 is written to the bus master register, the device is logically + * disconnected from the PCI bus. This avoids further DMA transfers. + */ + assigned_dev_pci_write_config(pci_dev, PCI_COMMAND, 0, 1); +} + +static int assigned_initfn(struct PCIDevice *pci_dev) +{ + AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + uint8_t e_intx; + int r; + + if (!kvm_enabled()) { + error_report("pci-assign: error: requires KVM support"); + return -1; + } + + if (!dev->host.domain && !dev->host.bus && !dev->host.slot && + !dev->host.function) { + error_report("pci-assign: error: no host device specified"); + return -1; + } + + /* + * Set up basic config space access control. Will be further refined during + * device initialization. + */ + assigned_dev_emulate_config_read(dev, 0, PCI_CONFIG_SPACE_SIZE); + assigned_dev_direct_config_read(dev, PCI_STATUS, 2); + assigned_dev_direct_config_read(dev, PCI_REVISION_ID, 1); + assigned_dev_direct_config_read(dev, PCI_CLASS_PROG, 3); + assigned_dev_direct_config_read(dev, PCI_CACHE_LINE_SIZE, 1); + assigned_dev_direct_config_read(dev, PCI_LATENCY_TIMER, 1); + assigned_dev_direct_config_read(dev, PCI_BIST, 1); + assigned_dev_direct_config_read(dev, PCI_CARDBUS_CIS, 4); + assigned_dev_direct_config_read(dev, PCI_SUBSYSTEM_VENDOR_ID, 2); + assigned_dev_direct_config_read(dev, PCI_SUBSYSTEM_ID, 2); + assigned_dev_direct_config_read(dev, PCI_CAPABILITY_LIST + 1, 7); + assigned_dev_direct_config_read(dev, PCI_MIN_GNT, 1); + assigned_dev_direct_config_read(dev, PCI_MAX_LAT, 1); + memcpy(dev->emulate_config_write, dev->emulate_config_read, + sizeof(dev->emulate_config_read)); + + if (get_real_device(dev, dev->host.domain, dev->host.bus, + dev->host.slot, dev->host.function)) { + error_report("pci-assign: Error: Couldn't get real device (%s)!", + dev->dev.qdev.id); + goto out; + } + + if (assigned_device_pci_cap_init(pci_dev) < 0) { + goto out; + } + + /* intercept MSI-X entry page in the MMIO */ + if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) { + if (assigned_dev_register_msix_mmio(dev)) { + goto out; + } + } + + /* handle real device's MMIO/PIO BARs */ + if (assigned_dev_register_regions(dev->real_device.regions, + dev->real_device.region_number, + dev)) { + goto out; + } + + /* handle interrupt routing */ + e_intx = dev->dev.config[PCI_INTERRUPT_PIN] - 1; + dev->intpin = e_intx; + dev->intx_route.mode = PCI_INTX_DISABLED; + dev->intx_route.irq = -1; + + /* assign device to guest */ + r = assign_device(dev); + if (r < 0) { + goto out; + } + + /* assign legacy INTx to the device */ + r = assign_intx(dev); + if (r < 0) { + goto assigned_out; + } + + assigned_dev_load_option_rom(dev); + + add_boot_device_path(dev->bootindex, &pci_dev->qdev, NULL); + + return 0; + +assigned_out: + deassign_device(dev); +out: + free_assigned_device(dev); + return -1; +} + +static void assigned_exitfn(struct PCIDevice *pci_dev) +{ + AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + + deassign_device(dev); + free_assigned_device(dev); +} + +static Property assigned_dev_properties[] = { + DEFINE_PROP_PCI_HOST_DEVADDR("host", AssignedDevice, host), + DEFINE_PROP_BIT("prefer_msi", AssignedDevice, features, + ASSIGNED_DEVICE_PREFER_MSI_BIT, false), + DEFINE_PROP_BIT("share_intx", AssignedDevice, features, + ASSIGNED_DEVICE_SHARE_INTX_BIT, true), + DEFINE_PROP_INT32("bootindex", AssignedDevice, bootindex, -1), + DEFINE_PROP_STRING("configfd", AssignedDevice, configfd_name), + DEFINE_PROP_END_OF_LIST(), +}; + +static void assign_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = assigned_initfn; + k->exit = assigned_exitfn; + k->config_read = assigned_dev_pci_read_config; + k->config_write = assigned_dev_pci_write_config; + dc->props = assigned_dev_properties; + dc->vmsd = &vmstate_assigned_device; + dc->reset = reset_assigned_device; + dc->desc = "KVM-based PCI passthrough"; +} + +static const TypeInfo assign_info = { + .name = "kvm-pci-assign", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(AssignedDevice), + .class_init = assign_class_init, +}; + +static void assign_register_types(void) +{ + type_register_static(&assign_info); +} + +type_init(assign_register_types) + +/* + * Scan the assigned devices for the devices that have an option ROM, and then + * load the corresponding ROM data to RAM. If an error occurs while loading an + * option ROM, we just ignore that option ROM and continue with the next one. + */ +static void assigned_dev_load_option_rom(AssignedDevice *dev) +{ + char name[32], rom_file[64]; + FILE *fp; + uint8_t val; + struct stat st; + void *ptr; + + /* If loading ROM from file, pci handles it */ + if (dev->dev.romfile || !dev->dev.rom_bar) { + return; + } + + snprintf(rom_file, sizeof(rom_file), + "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/rom", + dev->host.domain, dev->host.bus, dev->host.slot, + dev->host.function); + + if (stat(rom_file, &st)) { + return; + } + + if (access(rom_file, F_OK)) { + error_report("pci-assign: Insufficient privileges for %s", rom_file); + return; + } + + /* Write "1" to the ROM file to enable it */ + fp = fopen(rom_file, "r+"); + if (fp == NULL) { + return; + } + val = 1; + if (fwrite(&val, 1, 1, fp) != 1) { + goto close_rom; + } + fseek(fp, 0, SEEK_SET); + + snprintf(name, sizeof(name), "%s.rom", + object_get_typename(OBJECT(dev))); + memory_region_init_ram(&dev->dev.rom, name, st.st_size); + vmstate_register_ram(&dev->dev.rom, &dev->dev.qdev); + ptr = memory_region_get_ram_ptr(&dev->dev.rom); + memset(ptr, 0xff, st.st_size); + + if (!fread(ptr, 1, st.st_size, fp)) { + error_report("pci-assign: Cannot read from host %s\n" + "\tDevice option ROM contents are probably invalid " + "(check dmesg).\n\tSkip option ROM probe with rombar=0, " + "or load from file with romfile=", rom_file); + memory_region_destroy(&dev->dev.rom); + goto close_rom; + } + + pci_register_bar(&dev->dev, PCI_ROM_SLOT, 0, &dev->dev.rom); + dev->dev.has_rom = true; +close_rom: + /* Write "0" to disable ROM */ + fseek(fp, 0, SEEK_SET); + val = 0; + if (!fwrite(&val, 1, 1, fp)) { + DEBUG("%s\n", "Failed to disable pci-sysfs rom file"); + } + fclose(fp); +} diff --git a/hw/kvmvapic.c b/hw/kvmvapic.c index 5d83625f4a..81f4bcfdf6 100644 --- a/hw/kvmvapic.c +++ b/hw/kvmvapic.c @@ -8,9 +8,9 @@ * (at your option) any later version. See the COPYING file in the * top-level directory. */ -#include "sysemu.h" -#include "cpus.h" -#include "kvm.h" +#include "sysemu/sysemu.h" +#include "sysemu/cpus.h" +#include "sysemu/kvm.h" #include "apic_internal.h" #define APIC_DEFAULT_ADDRESS 0xfee00000 @@ -144,7 +144,7 @@ static void update_guest_rom_state(VAPICROMState *s) static int find_real_tpr_addr(VAPICROMState *s, CPUX86State *env) { - target_phys_addr_t paddr; + hwaddr paddr; target_ulong addr; if (s->state == VAPIC_ACTIVE) { @@ -269,7 +269,7 @@ instruction_ok: static int update_rom_mapping(VAPICROMState *s, CPUX86State *env, target_ulong ip) { - target_phys_addr_t paddr; + hwaddr paddr; uint32_t rom_state_vaddr; uint32_t pos, patch, offset; @@ -350,14 +350,14 @@ static int get_kpcr_number(CPUX86State *env) static int vapic_enable(VAPICROMState *s, CPUX86State *env) { int cpu_number = get_kpcr_number(env); - target_phys_addr_t vapic_paddr; + hwaddr vapic_paddr; static const uint8_t enabled = 1; if (cpu_number < 0) { return -1; } vapic_paddr = s->vapic_paddr + - (((target_phys_addr_t)cpu_number) << VAPIC_CPU_SHIFT); + (((hwaddr)cpu_number) << VAPIC_CPU_SHIFT); cpu_physical_memory_rw(vapic_paddr + offsetof(VAPICState, enabled), (void *)&enabled, sizeof(enabled), 1); apic_enable_vapic(env->apic_state, vapic_paddr); @@ -384,10 +384,12 @@ static void patch_call(VAPICROMState *s, CPUX86State *env, target_ulong ip, static void patch_instruction(VAPICROMState *s, CPUX86State *env, target_ulong ip) { - target_phys_addr_t paddr; VAPICHandlers *handlers; uint8_t opcode[2]; uint32_t imm32; + target_ulong current_pc = 0; + target_ulong current_cs_base = 0; + int current_flags = 0; if (smp_cpus == 1) { handlers = &s->rom_state.up; @@ -395,6 +397,12 @@ static void patch_instruction(VAPICROMState *s, CPUX86State *env, target_ulong i handlers = &s->rom_state.mp; } + if (!kvm_enabled()) { + cpu_restore_state(env, env->mem_io_pc); + cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, + ¤t_flags); + } + pause_all_vcpus(); cpu_memory_rw_debug(env, ip, opcode, sizeof(opcode), 0); @@ -430,9 +438,11 @@ static void patch_instruction(VAPICROMState *s, CPUX86State *env, target_ulong i resume_all_vcpus(); - paddr = cpu_get_phys_page_debug(env, ip); - paddr += ip & ~TARGET_PAGE_MASK; - tb_invalidate_phys_page_range(paddr, paddr + 1, 1); + if (!kvm_enabled()) { + env->current_tb = NULL; + tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); + cpu_resume_from_signal(env, NULL); + } } void vapic_report_tpr_access(DeviceState *dev, void *cpu, target_ulong ip, @@ -475,11 +485,13 @@ static void vapic_enable_tpr_reporting(bool enable) VAPICEnableTPRReporting info = { .enable = enable, }; + X86CPU *cpu; CPUX86State *env; for (env = first_cpu; env != NULL; env = env->next_cpu) { + cpu = x86_env_get_cpu(env); info.apic = env->apic_state; - run_on_cpu(env, vapic_do_enable_tpr_reporting, &info); + run_on_cpu(CPU(cpu), vapic_do_enable_tpr_reporting, &info); } } @@ -500,7 +512,7 @@ static void vapic_reset(DeviceState *dev) */ static int patch_hypercalls(VAPICROMState *s) { - target_phys_addr_t rom_paddr = s->rom_state_paddr & ROM_BLOCK_MASK; + hwaddr rom_paddr = s->rom_state_paddr & ROM_BLOCK_MASK; static const uint8_t vmcall_pattern[] = { /* vmcall */ 0xb8, 0x1, 0, 0, 0, 0xf, 0x1, 0xc1 }; @@ -557,7 +569,7 @@ static int patch_hypercalls(VAPICROMState *s) */ static void vapic_map_rom_writable(VAPICROMState *s) { - target_phys_addr_t rom_paddr = s->rom_state_paddr & ROM_BLOCK_MASK; + hwaddr rom_paddr = s->rom_state_paddr & ROM_BLOCK_MASK; MemoryRegionSection section; MemoryRegion *as; size_t rom_size; @@ -603,11 +615,11 @@ static int vapic_prepare(VAPICROMState *s) return 0; } -static void vapic_write(void *opaque, target_phys_addr_t addr, uint64_t data, +static void vapic_write(void *opaque, hwaddr addr, uint64_t data, unsigned int size) { CPUX86State *env = cpu_single_env; - target_phys_addr_t rom_paddr; + hwaddr rom_paddr; VAPICROMState *s = opaque; cpu_synchronize_state(env); @@ -717,7 +729,7 @@ static int vapic_post_load(void *opaque, int version_id) } if (s->state == VAPIC_ACTIVE) { if (smp_cpus == 1) { - run_on_cpu(first_cpu, do_vapic_enable, s); + run_on_cpu(ENV_GET_CPU(first_cpu), do_vapic_enable, s); } else { zero = g_malloc0(s->rom_state.vapic_size); cpu_physical_memory_rw(s->vapic_paddr, zero, @@ -5,7 +5,7 @@ * Written by Hans at OK-Labs * Updated by Peter Chubb. * - * This code is licenced under the GPL, version 2 or later. + * This code is licensed under the GPL, version 2 or later. * See the file `COPYING' in the top level directory. * * It (partially) emulates a Kyoto Microcomputer @@ -14,14 +14,14 @@ */ #include "sysbus.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #include "hw.h" #include "arm-misc.h" #include "devices.h" -#include "net.h" -#include "sysemu.h" +#include "net/net.h" +#include "sysemu/sysemu.h" #include "boards.h" -#include "pc.h" /* for the FPGA UART that emulates a 16550 */ +#include "serial.h" #include "imx.h" /* Memory map for Kzm Emulation Baseboard: @@ -70,11 +70,13 @@ static struct arm_boot_info kzm_binfo = { .board_id = 1722, }; -static void kzm_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void kzm_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/lan9118.c b/hw/lan9118.c index ff0a50be19..5adf91199b 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -11,9 +11,9 @@ */ #include "sysbus.h" -#include "net.h" +#include "net/net.h" #include "devices.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "ptimer.h" /* For crc32 */ #include <zlib.h> @@ -500,7 +500,7 @@ static int lan9118_filter(lan9118_state *s, const uint8_t *addr) } } else { /* Hash matching */ - hash = (crc32(~0, addr, 6) >> 26); + hash = compute_mcast_idx(addr); if (hash & 0x20) { return (s->mac_hashh >> (hash & 0x1f)) & 1; } else { @@ -1000,7 +1000,7 @@ static void lan9118_tick(void *opaque) lan9118_update(s); } -static void lan9118_writel(void *opaque, target_phys_addr_t offset, +static void lan9118_writel(void *opaque, hwaddr offset, uint64_t val, unsigned size) { lan9118_state *s = (lan9118_state *)opaque; @@ -1134,7 +1134,7 @@ static void lan9118_writel(void *opaque, target_phys_addr_t offset, lan9118_update(s); } -static void lan9118_writew(void *opaque, target_phys_addr_t offset, +static void lan9118_writew(void *opaque, hwaddr offset, uint32_t val) { lan9118_state *s = (lan9118_state *)opaque; @@ -1161,7 +1161,7 @@ static void lan9118_writew(void *opaque, target_phys_addr_t offset, } } -static void lan9118_16bit_mode_write(void *opaque, target_phys_addr_t offset, +static void lan9118_16bit_mode_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { switch (size) { @@ -1176,7 +1176,7 @@ static void lan9118_16bit_mode_write(void *opaque, target_phys_addr_t offset, hw_error("lan9118_write: Bad size 0x%x\n", size); } -static uint64_t lan9118_readl(void *opaque, target_phys_addr_t offset, +static uint64_t lan9118_readl(void *opaque, hwaddr offset, unsigned size) { lan9118_state *s = (lan9118_state *)opaque; @@ -1250,7 +1250,7 @@ static uint64_t lan9118_readl(void *opaque, target_phys_addr_t offset, return 0; } -static uint32_t lan9118_readw(void *opaque, target_phys_addr_t offset) +static uint32_t lan9118_readw(void *opaque, hwaddr offset) { lan9118_state *s = (lan9118_state *)opaque; uint32_t val; @@ -1278,7 +1278,7 @@ static uint32_t lan9118_readw(void *opaque, target_phys_addr_t offset) return val; } -static uint64_t lan9118_16bit_mode_read(void *opaque, target_phys_addr_t offset, +static uint64_t lan9118_16bit_mode_read(void *opaque, hwaddr offset, unsigned size) { switch (size) { diff --git a/hw/lance.c b/hw/lance.c index 9b98bb849a..b7265c0fed 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -36,9 +36,9 @@ */ #include "sysbus.h" -#include "net.h" -#include "qemu-timer.h" -#include "qemu_socket.h" +#include "net/net.h" +#include "qemu/timer.h" +#include "qemu/sockets.h" #include "sun4m.h" #include "pcnet.h" #include "trace.h" @@ -55,7 +55,7 @@ static void parent_lance_reset(void *opaque, int irq, int level) pcnet_h_reset(&d->state); } -static void lance_mem_write(void *opaque, target_phys_addr_t addr, +static void lance_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { SysBusPCNetState *d = opaque; @@ -64,7 +64,7 @@ static void lance_mem_write(void *opaque, target_phys_addr_t addr, pcnet_ioport_writew(&d->state, addr, val & 0xffff); } -static uint64_t lance_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t lance_mem_read(void *opaque, hwaddr addr, unsigned size) { SysBusPCNetState *d = opaque; diff --git a/hw/leon3.c b/hw/leon3.c index 878d3aa557..79b3a41def 100644 --- a/hw/leon3.c +++ b/hw/leon3.c @@ -22,15 +22,15 @@ * THE SOFTWARE. */ #include "hw.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "ptimer.h" -#include "qemu-char.h" -#include "sysemu.h" +#include "char/char.h" +#include "sysemu/sysemu.h" #include "boards.h" #include "loader.h" #include "elf.h" #include "trace.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #include "grlib.h" @@ -94,13 +94,11 @@ static void leon3_set_pil_in(void *opaque, uint32_t pil_in) } } -static void leon3_generic_hw_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void leon3_generic_hw_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; SPARCCPU *cpu; CPUSPARCState *env; MemoryRegion *address_space_mem = get_system_memory(); @@ -210,11 +208,10 @@ static void leon3_generic_hw_init(ram_addr_t ram_size, } } -QEMUMachine leon3_generic_machine = { +static QEMUMachine leon3_generic_machine = { .name = "leon3_generic", .desc = "Leon-3 generic", .init = leon3_generic_hw_init, - .use_scsi = 0, }; static void leon3_machine_init(void) @@ -1,3 +1,6 @@ +#ifndef HW_LM32_H +#define HW_LM32_H 1 + #include "qemu-common.h" @@ -23,3 +26,5 @@ static inline DeviceState *lm32_juart_init(void) return dev; } + +#endif diff --git a/hw/lm32_boards.c b/hw/lm32_boards.c index b76d8008be..42e8b6b52a 100644 --- a/hw/lm32_boards.c +++ b/hw/lm32_boards.c @@ -19,25 +19,24 @@ #include "sysbus.h" #include "hw.h" -#include "net.h" #include "flash.h" #include "devices.h" #include "boards.h" #include "loader.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "elf.h" #include "lm32_hwsetup.h" #include "lm32.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" typedef struct { LM32CPU *cpu; - target_phys_addr_t bootstrap_pc; - target_phys_addr_t flash_base; - target_phys_addr_t hwsetup_base; - target_phys_addr_t initrd_base; + hwaddr bootstrap_pc; + hwaddr flash_base; + hwaddr hwsetup_base; + hwaddr initrd_base; size_t initrd_size; - target_phys_addr_t cmdline_base; + hwaddr cmdline_base; } ResetInfo; static void cpu_irq_handler(void *opaque, int irq, int level) @@ -69,12 +68,10 @@ static void main_cpu_reset(void *opaque) env->deba = reset_info->flash_base; } -static void lm32_evr_init(ram_addr_t ram_size_not_used, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void lm32_evr_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; LM32CPU *cpu; CPULM32State *env; DriveInfo *dinfo; @@ -85,14 +82,14 @@ static void lm32_evr_init(ram_addr_t ram_size_not_used, int i; /* memory map */ - target_phys_addr_t flash_base = 0x04000000; + hwaddr flash_base = 0x04000000; size_t flash_sector_size = 256 * 1024; size_t flash_size = 32 * 1024 * 1024; - target_phys_addr_t ram_base = 0x08000000; + hwaddr ram_base = 0x08000000; size_t ram_size = 64 * 1024 * 1024; - target_phys_addr_t timer0_base = 0x80002000; - target_phys_addr_t uart0_base = 0x80006000; - target_phys_addr_t timer1_base = 0x8000a000; + hwaddr timer0_base = 0x80002000; + hwaddr uart0_base = 0x80006000; + hwaddr timer1_base = 0x8000a000; int uart0_irq = 0; int timer0_irq = 1; int timer1_irq = 3; @@ -159,12 +156,12 @@ static void lm32_evr_init(ram_addr_t ram_size_not_used, qemu_register_reset(main_cpu_reset, reset_info); } -static void lm32_uclinux_init(ram_addr_t ram_size_not_used, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void lm32_uclinux_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; LM32CPU *cpu; CPULM32State *env; DriveInfo *dinfo; @@ -176,22 +173,22 @@ static void lm32_uclinux_init(ram_addr_t ram_size_not_used, int i; /* memory map */ - target_phys_addr_t flash_base = 0x04000000; + hwaddr flash_base = 0x04000000; size_t flash_sector_size = 256 * 1024; size_t flash_size = 32 * 1024 * 1024; - target_phys_addr_t ram_base = 0x08000000; + hwaddr ram_base = 0x08000000; size_t ram_size = 64 * 1024 * 1024; - target_phys_addr_t uart0_base = 0x80000000; - target_phys_addr_t timer0_base = 0x80002000; - target_phys_addr_t timer1_base = 0x80010000; - target_phys_addr_t timer2_base = 0x80012000; + hwaddr uart0_base = 0x80000000; + hwaddr timer0_base = 0x80002000; + hwaddr timer1_base = 0x80010000; + hwaddr timer2_base = 0x80012000; int uart0_irq = 0; int timer0_irq = 1; int timer1_irq = 20; int timer2_irq = 21; - target_phys_addr_t hwsetup_base = 0x0bffe000; - target_phys_addr_t cmdline_base = 0x0bfff000; - target_phys_addr_t initrd_base = 0x08400000; + hwaddr hwsetup_base = 0x0bffe000; + hwaddr cmdline_base = 0x0bfff000; + hwaddr initrd_base = 0x08400000; size_t initrd_max = 0x01000000; reset_info = g_malloc0(sizeof(ResetInfo)); diff --git a/hw/lm32_hwsetup.h b/hw/lm32_hwsetup.h index 8fc285efc2..853e9abc7b 100644 --- a/hw/lm32_hwsetup.h +++ b/hw/lm32_hwsetup.h @@ -71,7 +71,7 @@ static inline void hwsetup_free(HWSetup *hw) } static inline void hwsetup_create_rom(HWSetup *hw, - target_phys_addr_t base) + hwaddr base) { rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE, base); } @@ -96,7 +96,7 @@ static inline void hwsetup_add_tag(HWSetup *hw, enum hwsetup_tag t) static inline void hwsetup_add_str(HWSetup *hw, const char *str) { - strncpy(hw->ptr, str, 31); /* make sure last byte is zero */ + pstrcpy(hw->ptr, 32, str); hw->ptr += 32; } diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c index f07ed3977f..7c2d202d6a 100644 --- a/hw/lm32_juart.c +++ b/hw/lm32_juart.c @@ -20,7 +20,7 @@ #include "hw.h" #include "sysbus.h" #include "trace.h" -#include "qemu-char.h" +#include "char/char.h" #include "lm32_juart.h" diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c index 32f65db7f1..42d5602cf0 100644 --- a/hw/lm32_pic.c +++ b/hw/lm32_pic.c @@ -21,7 +21,7 @@ #include "hw.h" #include "pc.h" -#include "monitor.h" +#include "monitor/monitor.h" #include "sysbus.h" #include "trace.h" #include "lm32_pic.h" diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c index bbe03c41d5..e3a9db9748 100644 --- a/hw/lm32_sys.c +++ b/hw/lm32_sys.c @@ -31,10 +31,10 @@ #include "hw.h" #include "sysbus.h" #include "trace.h" -#include "qemu-log.h" -#include "qemu-error.h" -#include "sysemu.h" -#include "qemu-log.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "sysemu/sysemu.h" +#include "qemu/log.h" enum { R_CTRL = 0, @@ -61,7 +61,7 @@ static void copy_testname(LM32SysState *s) s->testname[MAX_TESTNAME_LEN - 1] = '\0'; } -static void sys_write(void *opaque, target_phys_addr_t addr, +static void sys_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { LM32SysState *s = opaque; @@ -91,7 +91,7 @@ static void sys_write(void *opaque, target_phys_addr_t addr, } } -static bool sys_ops_accepts(void *opaque, target_phys_addr_t addr, +static bool sys_ops_accepts(void *opaque, hwaddr addr, unsigned size, bool is_write) { return is_write && size == 4; diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c index e9450a0ce1..bd4c346386 100644 --- a/hw/lm32_timer.c +++ b/hw/lm32_timer.c @@ -24,9 +24,9 @@ #include "hw.h" #include "sysbus.h" #include "trace.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "ptimer.h" -#include "qemu-error.h" +#include "qemu/error-report.h" #define DEFAULT_FREQUENCY (50*1000000) @@ -72,7 +72,7 @@ static void timer_update_irq(LM32TimerState *s) qemu_set_irq(s->irq, state); } -static uint64_t timer_read(void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size) { LM32TimerState *s = opaque; uint32_t r = 0; @@ -97,7 +97,7 @@ static uint64_t timer_read(void *opaque, target_phys_addr_t addr, unsigned size) return r; } -static void timer_write(void *opaque, target_phys_addr_t addr, +static void timer_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { LM32TimerState *s = opaque; diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c index 57066e28c6..89605b8e77 100644 --- a/hw/lm32_uart.c +++ b/hw/lm32_uart.c @@ -25,8 +25,8 @@ #include "hw.h" #include "sysbus.h" #include "trace.h" -#include "qemu-char.h" -#include "qemu-error.h" +#include "char/char.h" +#include "qemu/error-report.h" enum { R_RXTX = 0, @@ -125,7 +125,7 @@ static void uart_update_irq(LM32UartState *s) qemu_set_irq(s->irq, irq); } -static uint64_t uart_read(void *opaque, target_phys_addr_t addr, +static uint64_t uart_read(void *opaque, hwaddr addr, unsigned size) { LM32UartState *s = opaque; @@ -160,7 +160,7 @@ static uint64_t uart_read(void *opaque, target_phys_addr_t addr, return r; } -static void uart_write(void *opaque, target_phys_addr_t addr, +static void uart_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { LM32UartState *s = opaque; diff --git a/hw/lm4549.c b/hw/lm4549.c index 80b3ec4a5d..b3c2d5f25d 100644 --- a/hw/lm4549.c +++ b/hw/lm4549.c @@ -150,7 +150,7 @@ static void lm4549_audio_out_callback(void *opaque, int free) } } -uint32_t lm4549_read(lm4549_state *s, target_phys_addr_t offset) +uint32_t lm4549_read(lm4549_state *s, hwaddr offset) { uint16_t *regfile = s->regfile; uint32_t value = 0; @@ -165,7 +165,7 @@ uint32_t lm4549_read(lm4549_state *s, target_phys_addr_t offset) } void lm4549_write(lm4549_state *s, - target_phys_addr_t offset, uint32_t value) + hwaddr offset, uint32_t value) { uint16_t *regfile = s->regfile; @@ -224,7 +224,7 @@ uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right) This model supports 16-bit playback. */ - if (s->buffer_level >= LM4549_BUFFER_SIZE) { + if (s->buffer_level > LM4549_BUFFER_SIZE - 2) { DPRINTF("write_sample Buffer full\n"); return 0; } diff --git a/hw/lm4549.h b/hw/lm4549.h index 5948780e00..812a7a4440 100644 --- a/hw/lm4549.h +++ b/hw/lm4549.h @@ -36,8 +36,8 @@ extern const VMStateDescription vmstate_lm4549_state; void lm4549_init(lm4549_state *s, lm4549_callback data_req, void *opaque); -uint32_t lm4549_read(lm4549_state *s, target_phys_addr_t offset); -void lm4549_write(lm4549_state *s, target_phys_addr_t offset, uint32_t value); +uint32_t lm4549_read(lm4549_state *s, hwaddr offset); +void lm4549_write(lm4549_state *s, hwaddr offset, uint32_t value); uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right); #endif /* #ifndef HW_LM4549_H */ diff --git a/hw/lm832x.c b/hw/lm832x.c index 8e09f9bcc9..3649e3d249 100644 --- a/hw/lm832x.c +++ b/hw/lm832x.c @@ -20,8 +20,8 @@ #include "hw.h" #include "i2c.h" -#include "qemu-timer.h" -#include "console.h" +#include "qemu/timer.h" +#include "ui/console.h" typedef struct { I2CSlave i2c; diff --git a/hw/loader.c b/hw/loader.c index 33acc2fdab..3f59fcd14a 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -43,14 +43,14 @@ */ #include "hw.h" -#include "disas.h" -#include "monitor.h" -#include "sysemu.h" +#include "disas/disas.h" +#include "monitor/monitor.h" +#include "sysemu/sysemu.h" #include "uboot_image.h" #include "loader.h" #include "fw_cfg.h" -#include "memory.h" -#include "exec-memory.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" #include <zlib.h> @@ -88,7 +88,7 @@ int load_image(const char *filename, uint8_t *addr) /* read()-like version */ ssize_t read_targphys(const char *name, - int fd, target_phys_addr_t dst_addr, size_t nbytes) + int fd, hwaddr dst_addr, size_t nbytes) { uint8_t *buf; ssize_t did; @@ -103,7 +103,7 @@ ssize_t read_targphys(const char *name, /* return the size or -1 if error */ int load_image_targphys(const char *filename, - target_phys_addr_t addr, uint64_t max_sz) + hwaddr addr, uint64_t max_sz) { int size; @@ -117,7 +117,7 @@ int load_image_targphys(const char *filename, return size; } -void pstrcpy_targphys(const char *name, target_phys_addr_t dest, int buf_size, +void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size, const char *source) { const char *nulp; @@ -179,8 +179,8 @@ static void bswap_ahdr(struct exec *e) : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x, target_page_size), target_page_size))) -int load_aout(const char *filename, target_phys_addr_t addr, int max_sz, - int bswap_needed, target_phys_addr_t target_page_size) +int load_aout(const char *filename, hwaddr addr, int max_sz, + int bswap_needed, hwaddr target_page_size) { int fd; ssize_t size, ret; @@ -434,8 +434,8 @@ static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, } /* Load a U-Boot image. */ -int load_uimage(const char *filename, target_phys_addr_t *ep, - target_phys_addr_t *loadaddr, int *is_linux) +int load_uimage(const char *filename, hwaddr *ep, + hwaddr *loadaddr, int *is_linux) { int fd; int size; @@ -539,7 +539,7 @@ struct Rom { char *fw_dir; char *fw_file; - target_phys_addr_t addr; + hwaddr addr; QTAILQ_ENTRY(Rom) next; }; @@ -565,7 +565,7 @@ static void rom_insert(Rom *rom) } int rom_add_file(const char *file, const char *fw_dir, - target_phys_addr_t addr, int32_t bootindex) + hwaddr addr, int32_t bootindex) { Rom *rom; int rc, fd = -1; @@ -633,7 +633,7 @@ err: } int rom_add_blob(const char *name, const void *blob, size_t len, - target_phys_addr_t addr) + hwaddr addr) { Rom *rom; @@ -679,7 +679,7 @@ static void rom_reset(void *unused) int rom_load_all(void) { - target_phys_addr_t addr = 0; + hwaddr addr = 0; MemoryRegionSection section; Rom *rom; @@ -709,7 +709,7 @@ void rom_set_fw(void *f) fw_cfg = f; } -static Rom *find_rom(target_phys_addr_t addr) +static Rom *find_rom(hwaddr addr) { Rom *rom; @@ -733,9 +733,9 @@ static Rom *find_rom(target_phys_addr_t addr) * a ROM between addr and addr + size is copied. Note that this can involve * multiple ROMs, which need not start at addr and need not end at addr + size. */ -int rom_copy(uint8_t *dest, target_phys_addr_t addr, size_t size) +int rom_copy(uint8_t *dest, hwaddr addr, size_t size) { - target_phys_addr_t end = addr + size; + hwaddr end = addr + size; uint8_t *s, *d = dest; size_t l = 0; Rom *rom; @@ -768,7 +768,7 @@ int rom_copy(uint8_t *dest, target_phys_addr_t addr, size_t size) return (d + l) - dest; } -void *rom_ptr(target_phys_addr_t addr) +void *rom_ptr(hwaddr addr) { Rom *rom; diff --git a/hw/loader.h b/hw/loader.h index 6da291e31f..26480ad8dd 100644 --- a/hw/loader.h +++ b/hw/loader.h @@ -4,32 +4,32 @@ /* loader.c */ int get_image_size(const char *filename); int load_image(const char *filename, uint8_t *addr); /* deprecated */ -int load_image_targphys(const char *filename, target_phys_addr_t, +int load_image_targphys(const char *filename, hwaddr, uint64_t max_sz); int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb); -int load_aout(const char *filename, target_phys_addr_t addr, int max_sz, - int bswap_needed, target_phys_addr_t target_page_size); -int load_uimage(const char *filename, target_phys_addr_t *ep, - target_phys_addr_t *loadaddr, int *is_linux); +int load_aout(const char *filename, hwaddr addr, int max_sz, + int bswap_needed, hwaddr target_page_size); +int load_uimage(const char *filename, hwaddr *ep, + hwaddr *loadaddr, int *is_linux); ssize_t read_targphys(const char *name, - int fd, target_phys_addr_t dst_addr, size_t nbytes); + int fd, hwaddr dst_addr, size_t nbytes); void pstrcpy_targphys(const char *name, - target_phys_addr_t dest, int buf_size, + hwaddr dest, int buf_size, const char *source); int rom_add_file(const char *file, const char *fw_dir, - target_phys_addr_t addr, int32_t bootindex); + hwaddr addr, int32_t bootindex); int rom_add_blob(const char *name, const void *blob, size_t len, - target_phys_addr_t addr); + hwaddr addr); int rom_load_all(void); void rom_set_fw(void *f); -int rom_copy(uint8_t *dest, target_phys_addr_t addr, size_t size); -void *rom_ptr(target_phys_addr_t addr); +int rom_copy(uint8_t *dest, hwaddr addr, size_t size); +void *rom_ptr(hwaddr addr); void do_info_roms(Monitor *mon); #define rom_add_file_fixed(_f, _a, _i) \ diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c new file mode 100644 index 0000000000..16843d76bc --- /dev/null +++ b/hw/lpc_ich9.c @@ -0,0 +1,538 @@ +/* + * QEMU ICH9 Emulation + * + * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2009, 2010, 2011 + * Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * Copyright (C) 2012 Jason Baron <jbaron@redhat.com> + * + * This is based on piix_pci.c, but heavily modified. + * + * 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. + */ +#include "qemu-common.h" +#include "hw.h" +#include "qemu/range.h" +#include "isa.h" +#include "sysbus.h" +#include "pc.h" +#include "apm.h" +#include "ioapic.h" +#include "pci/pci.h" +#include "pci/pcie_host.h" +#include "pci/pci_bridge.h" +#include "ich9.h" +#include "acpi.h" +#include "acpi_ich9.h" +#include "pam.h" +#include "pci/pci_bus.h" +#include "exec/address-spaces.h" +#include "sysemu/sysemu.h" + +static int ich9_lpc_sci_irq(ICH9LPCState *lpc); + +/*****************************************************************************/ +/* ICH9 LPC PCI to ISA bridge */ + +static void ich9_lpc_reset(DeviceState *qdev); + +/* chipset configuration register + * to access chipset configuration registers, pci_[sg]et_{byte, word, long} + * are used. + * Although it's not pci configuration space, it's little endian as Intel. + */ + +static void ich9_cc_update_ir(uint8_t irr[PCI_NUM_PINS], uint16_t ir) +{ + int intx; + for (intx = 0; intx < PCI_NUM_PINS; intx++) { + irr[intx] = (ir >> (intx * ICH9_CC_DIR_SHIFT)) & ICH9_CC_DIR_MASK; + } +} + +static void ich9_cc_update(ICH9LPCState *lpc) +{ + int slot; + int pci_intx; + + const int reg_offsets[] = { + ICH9_CC_D25IR, + ICH9_CC_D26IR, + ICH9_CC_D27IR, + ICH9_CC_D28IR, + ICH9_CC_D29IR, + ICH9_CC_D30IR, + ICH9_CC_D31IR, + }; + const int *offset; + + /* D{25 - 31}IR, but D30IR is read only to 0. */ + for (slot = 25, offset = reg_offsets; slot < 32; slot++, offset++) { + if (slot == 30) { + continue; + } + ich9_cc_update_ir(lpc->irr[slot], + pci_get_word(lpc->chip_config + *offset)); + } + + /* + * D30: DMI2PCI bridge + * It is arbitrarily decided how INTx lines of PCI devicesbehind the bridge + * are connected to pirq lines. Our choice is PIRQ[E-H]. + * INT[A-D] are connected to PIRQ[E-H] + */ + for (pci_intx = 0; pci_intx < PCI_NUM_PINS; pci_intx++) { + lpc->irr[30][pci_intx] = pci_intx + 4; + } +} + +static void ich9_cc_init(ICH9LPCState *lpc) +{ + int slot; + int intx; + + /* the default irq routing is arbitrary as long as it matches with + * acpi irq routing table. + * The one that is incompatible with piix_pci(= bochs) one is + * intentionally chosen to let the users know that the different + * board is used. + * + * int[A-D] -> pirq[E-F] + * avoid pirq A-D because they are used for pci express port + */ + for (slot = 0; slot < PCI_SLOT_MAX; slot++) { + for (intx = 0; intx < PCI_NUM_PINS; intx++) { + lpc->irr[slot][intx] = (slot + intx) % 4 + 4; + } + } + ich9_cc_update(lpc); +} + +static void ich9_cc_reset(ICH9LPCState *lpc) +{ + uint8_t *c = lpc->chip_config; + + memset(lpc->chip_config, 0, sizeof(lpc->chip_config)); + + pci_set_long(c + ICH9_CC_D31IR, ICH9_CC_DIR_DEFAULT); + pci_set_long(c + ICH9_CC_D30IR, ICH9_CC_D30IR_DEFAULT); + pci_set_long(c + ICH9_CC_D29IR, ICH9_CC_DIR_DEFAULT); + pci_set_long(c + ICH9_CC_D28IR, ICH9_CC_DIR_DEFAULT); + pci_set_long(c + ICH9_CC_D27IR, ICH9_CC_DIR_DEFAULT); + pci_set_long(c + ICH9_CC_D26IR, ICH9_CC_DIR_DEFAULT); + pci_set_long(c + ICH9_CC_D25IR, ICH9_CC_DIR_DEFAULT); + + ich9_cc_update(lpc); +} + +static void ich9_cc_addr_len(uint64_t *addr, unsigned *len) +{ + *addr &= ICH9_CC_ADDR_MASK; + if (*addr + *len >= ICH9_CC_SIZE) { + *len = ICH9_CC_SIZE - *addr; + } +} + +/* val: little endian */ +static void ich9_cc_write(void *opaque, hwaddr addr, + uint64_t val, unsigned len) +{ + ICH9LPCState *lpc = (ICH9LPCState *)opaque; + + ich9_cc_addr_len(&addr, &len); + memcpy(lpc->chip_config + addr, &val, len); + ich9_cc_update(lpc); +} + +/* return value: little endian */ +static uint64_t ich9_cc_read(void *opaque, hwaddr addr, + unsigned len) +{ + ICH9LPCState *lpc = (ICH9LPCState *)opaque; + + uint32_t val = 0; + ich9_cc_addr_len(&addr, &len); + memcpy(&val, lpc->chip_config + addr, len); + return val; +} + +/* IRQ routing */ +/* */ +static void ich9_lpc_rout(uint8_t pirq_rout, int *pic_irq, int *pic_dis) +{ + *pic_irq = pirq_rout & ICH9_LPC_PIRQ_ROUT_MASK; + *pic_dis = pirq_rout & ICH9_LPC_PIRQ_ROUT_IRQEN; +} + +static void ich9_lpc_pic_irq(ICH9LPCState *lpc, int pirq_num, + int *pic_irq, int *pic_dis) +{ + switch (pirq_num) { + case 0 ... 3: /* A-D */ + ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQA_ROUT + pirq_num], + pic_irq, pic_dis); + return; + case 4 ... 7: /* E-H */ + ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQE_ROUT + (pirq_num - 4)], + pic_irq, pic_dis); + return; + default: + break; + } + abort(); +} + +/* pic_irq: i8254 irq 0-15 */ +static void ich9_lpc_update_pic(ICH9LPCState *lpc, int pic_irq) +{ + int i, pic_level; + + /* The pic level is the logical OR of all the PCI irqs mapped to it */ + pic_level = 0; + for (i = 0; i < ICH9_LPC_NB_PIRQS; i++) { + int tmp_irq; + int tmp_dis; + ich9_lpc_pic_irq(lpc, i, &tmp_irq, &tmp_dis); + if (!tmp_dis && pic_irq == tmp_irq) { + pic_level |= pci_bus_get_irq_level(lpc->d.bus, i); + } + } + if (pic_irq == ich9_lpc_sci_irq(lpc)) { + pic_level |= lpc->sci_level; + } + + qemu_set_irq(lpc->pic[pic_irq], pic_level); +} + +/* pirq: pirq[A-H] 0-7*/ +static void ich9_lpc_update_by_pirq(ICH9LPCState *lpc, int pirq) +{ + int pic_irq; + int pic_dis; + + ich9_lpc_pic_irq(lpc, pirq, &pic_irq, &pic_dis); + assert(pic_irq < ICH9_LPC_PIC_NUM_PINS); + if (pic_dis) { + return; + } + + ich9_lpc_update_pic(lpc, pic_irq); +} + +/* APIC mode: GSIx: PIRQ[A-H] -> GSI 16, ... no pirq shares same APIC pins. */ +static int ich9_pirq_to_gsi(int pirq) +{ + return pirq + ICH9_LPC_PIC_NUM_PINS; +} + +static int ich9_gsi_to_pirq(int gsi) +{ + return gsi - ICH9_LPC_PIC_NUM_PINS; +} + +static void ich9_lpc_update_apic(ICH9LPCState *lpc, int gsi) +{ + int level = 0; + + if (gsi >= ICH9_LPC_PIC_NUM_PINS) { + level |= pci_bus_get_irq_level(lpc->d.bus, ich9_gsi_to_pirq(gsi)); + } + if (gsi == ich9_lpc_sci_irq(lpc)) { + level |= lpc->sci_level; + } + + qemu_set_irq(lpc->ioapic[gsi], level); +} + +void ich9_lpc_set_irq(void *opaque, int pirq, int level) +{ + ICH9LPCState *lpc = opaque; + + assert(0 <= pirq); + assert(pirq < ICH9_LPC_NB_PIRQS); + + ich9_lpc_update_apic(lpc, ich9_pirq_to_gsi(pirq)); + ich9_lpc_update_by_pirq(lpc, pirq); +} + +/* return the pirq number (PIRQ[A-H]:0-7) corresponding to + * a given device irq pin. + */ +int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx) +{ + BusState *bus = qdev_get_parent_bus(&pci_dev->qdev); + PCIBus *pci_bus = PCI_BUS(bus); + PCIDevice *lpc_pdev = + pci_bus->devices[PCI_DEVFN(ICH9_LPC_DEV, ICH9_LPC_FUNC)]; + ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pdev); + + return lpc->irr[PCI_SLOT(pci_dev->devfn)][intx]; +} + +static int ich9_lpc_sci_irq(ICH9LPCState *lpc) +{ + switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] & + ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK) { + case ICH9_LPC_ACPI_CTRL_9: + return 9; + case ICH9_LPC_ACPI_CTRL_10: + return 10; + case ICH9_LPC_ACPI_CTRL_11: + return 11; + case ICH9_LPC_ACPI_CTRL_20: + return 20; + case ICH9_LPC_ACPI_CTRL_21: + return 21; + default: + /* reserved */ + break; + } + return -1; +} + +static void ich9_set_sci(void *opaque, int irq_num, int level) +{ + ICH9LPCState *lpc = opaque; + int irq; + + assert(irq_num == 0); + level = !!level; + if (level == lpc->sci_level) { + return; + } + lpc->sci_level = level; + + irq = ich9_lpc_sci_irq(lpc); + if (irq < 0) { + return; + } + + ich9_lpc_update_apic(lpc, irq); + if (irq < ICH9_LPC_PIC_NUM_PINS) { + ich9_lpc_update_pic(lpc, irq); + } +} + +void ich9_lpc_pm_init(PCIDevice *lpc_pci, qemu_irq cmos_s3) +{ + ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci); + qemu_irq *sci_irq; + + sci_irq = qemu_allocate_irqs(ich9_set_sci, lpc, 1); + ich9_pm_init(lpc_pci, &lpc->pm, sci_irq[0], cmos_s3); + + ich9_lpc_reset(&lpc->d.qdev); +} + +/* APM */ + +static void ich9_apm_ctrl_changed(uint32_t val, void *arg) +{ + ICH9LPCState *lpc = arg; + + /* ACPI specs 3.0, 4.7.2.5 */ + acpi_pm1_cnt_update(&lpc->pm.acpi_regs, + val == ICH9_APM_ACPI_ENABLE, + val == ICH9_APM_ACPI_DISABLE); + + /* SMI_EN = PMBASE + 30. SMI control and enable register */ + if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) { + cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI); + } +} + +/* config:PMBASE */ +static void +ich9_lpc_pmbase_update(ICH9LPCState *lpc) +{ + uint32_t pm_io_base = pci_get_long(lpc->d.config + ICH9_LPC_PMBASE); + pm_io_base &= ICH9_LPC_PMBASE_BASE_ADDRESS_MASK; + + ich9_pm_iospace_update(&lpc->pm, pm_io_base); +} + +/* config:RBCA */ +static void ich9_lpc_rcba_update(ICH9LPCState *lpc, uint32_t rbca_old) +{ + uint32_t rbca = pci_get_long(lpc->d.config + ICH9_LPC_RCBA); + + if (rbca_old & ICH9_LPC_RCBA_EN) { + memory_region_del_subregion(get_system_memory(), &lpc->rbca_mem); + } + if (rbca & ICH9_LPC_RCBA_EN) { + memory_region_add_subregion_overlap(get_system_memory(), + rbca & ICH9_LPC_RCBA_BA_MASK, + &lpc->rbca_mem, 1); + } +} + +static int ich9_lpc_post_load(void *opaque, int version_id) +{ + ICH9LPCState *lpc = opaque; + + ich9_lpc_pmbase_update(lpc); + ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RBCA_EN */); + return 0; +} + +static void ich9_lpc_config_write(PCIDevice *d, + uint32_t addr, uint32_t val, int len) +{ + ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); + uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA); + + pci_default_write_config(d, addr, val, len); + if (ranges_overlap(addr, len, ICH9_LPC_PMBASE, 4)) { + ich9_lpc_pmbase_update(lpc); + } + if (ranges_overlap(addr, len, ICH9_LPC_RCBA, 4)) { + ich9_lpc_rcba_update(lpc, rbca_old); + } +} + +static void ich9_lpc_reset(DeviceState *qdev) +{ + PCIDevice *d = PCI_DEVICE(qdev); + ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); + uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA); + int i; + + for (i = 0; i < 4; i++) { + pci_set_byte(d->config + ICH9_LPC_PIRQA_ROUT + i, + ICH9_LPC_PIRQ_ROUT_DEFAULT); + } + for (i = 0; i < 4; i++) { + pci_set_byte(d->config + ICH9_LPC_PIRQE_ROUT + i, + ICH9_LPC_PIRQ_ROUT_DEFAULT); + } + pci_set_byte(d->config + ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_DEFAULT); + + pci_set_long(d->config + ICH9_LPC_PMBASE, ICH9_LPC_PMBASE_DEFAULT); + pci_set_long(d->config + ICH9_LPC_RCBA, ICH9_LPC_RCBA_DEFAULT); + + ich9_cc_reset(lpc); + + ich9_lpc_pmbase_update(lpc); + ich9_lpc_rcba_update(lpc, rbca_old); + + lpc->sci_level = 0; +} + +static const MemoryRegionOps rbca_mmio_ops = { + .read = ich9_cc_read, + .write = ich9_cc_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void ich9_lpc_machine_ready(Notifier *n, void *opaque) +{ + ICH9LPCState *s = container_of(n, ICH9LPCState, machine_ready); + uint8_t *pci_conf; + + pci_conf = s->d.config; + if (isa_is_ioport_assigned(0x3f8)) { + /* com1 */ + pci_conf[0x82] |= 0x01; + } + if (isa_is_ioport_assigned(0x2f8)) { + /* com2 */ + pci_conf[0x82] |= 0x02; + } + if (isa_is_ioport_assigned(0x378)) { + /* lpt */ + pci_conf[0x82] |= 0x04; + } + if (isa_is_ioport_assigned(0x3f0)) { + /* floppy */ + pci_conf[0x82] |= 0x08; + } +} + +static int ich9_lpc_initfn(PCIDevice *d) +{ + ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); + ISABus *isa_bus; + + isa_bus = isa_bus_new(&d->qdev, get_system_io()); + + pci_set_long(d->wmask + ICH9_LPC_PMBASE, + ICH9_LPC_PMBASE_BASE_ADDRESS_MASK); + + memory_region_init_io(&lpc->rbca_mem, &rbca_mmio_ops, lpc, + "lpc-rbca-mmio", ICH9_CC_SIZE); + + lpc->isa_bus = isa_bus; + + ich9_cc_init(lpc); + apm_init(d, &lpc->apm, ich9_apm_ctrl_changed, lpc); + + lpc->machine_ready.notify = ich9_lpc_machine_ready; + qemu_add_machine_init_done_notifier(&lpc->machine_ready); + + return 0; +} + +static const VMStateDescription vmstate_ich9_lpc = { + .name = "ICH9LPC", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = ich9_lpc_post_load, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(d, ICH9LPCState), + VMSTATE_STRUCT(apm, ICH9LPCState, 0, vmstate_apm, APMState), + VMSTATE_STRUCT(pm, ICH9LPCState, 0, vmstate_ich9_pm, ICH9LPCPMRegs), + VMSTATE_UINT8_ARRAY(chip_config, ICH9LPCState, ICH9_CC_SIZE), + VMSTATE_UINT32(sci_level, ICH9LPCState), + VMSTATE_END_OF_LIST() + } +}; + +static void ich9_lpc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + dc->reset = ich9_lpc_reset; + k->init = ich9_lpc_initfn; + dc->vmsd = &vmstate_ich9_lpc; + dc->no_user = 1; + k->config_write = ich9_lpc_config_write; + dc->desc = "ICH9 LPC bridge"; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_ICH9_8; + k->revision = ICH9_A2_LPC_REVISION; + k->class_id = PCI_CLASS_BRIDGE_ISA; + +} + +static const TypeInfo ich9_lpc_info = { + .name = TYPE_ICH9_LPC_DEVICE, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(struct ICH9LPCState), + .class_init = ich9_lpc_class_init, +}; + +static void ich9_lpc_register(void) +{ + type_register_static(&ich9_lpc_info); +} + +type_init(ich9_lpc_register); diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 34afe96742..0aafb00b58 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -13,9 +13,9 @@ #include <assert.h> #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "scsi.h" -#include "dma.h" +#include "sysemu/dma.h" //#define DEBUG_LSI //#define DEBUG_LSI_REG @@ -1878,7 +1878,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) #undef CASE_SET_REG32 } -static void lsi_mmio_write(void *opaque, target_phys_addr_t addr, +static void lsi_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { LSIState *s = opaque; @@ -1886,7 +1886,7 @@ static void lsi_mmio_write(void *opaque, target_phys_addr_t addr, lsi_reg_writeb(s, addr & 0xff, val); } -static uint64_t lsi_mmio_read(void *opaque, target_phys_addr_t addr, +static uint64_t lsi_mmio_read(void *opaque, hwaddr addr, unsigned size) { LSIState *s = opaque; @@ -1904,7 +1904,7 @@ static const MemoryRegionOps lsi_mmio_ops = { }, }; -static void lsi_ram_write(void *opaque, target_phys_addr_t addr, +static void lsi_ram_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { LSIState *s = opaque; @@ -1920,7 +1920,7 @@ static void lsi_ram_write(void *opaque, target_phys_addr_t addr, s->script_ram[addr >> 2] = newval; } -static uint64_t lsi_ram_read(void *opaque, target_phys_addr_t addr, +static uint64_t lsi_ram_read(void *opaque, hwaddr addr, unsigned size) { LSIState *s = opaque; @@ -1939,14 +1939,14 @@ static const MemoryRegionOps lsi_ram_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint64_t lsi_io_read(void *opaque, target_phys_addr_t addr, +static uint64_t lsi_io_read(void *opaque, hwaddr addr, unsigned size) { LSIState *s = opaque; return lsi_reg_readb(s, addr & 0xff); } -static void lsi_io_write(void *opaque, target_phys_addr_t addr, +static void lsi_io_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { LSIState *s = opaque; diff --git a/hw/m25p80.c b/hw/m25p80.c new file mode 100644 index 0000000000..d39265632b --- /dev/null +++ b/hw/m25p80.c @@ -0,0 +1,651 @@ +/* + * ST M25P80 emulator. Emulate all SPI flash devices based on the m25p80 command + * set. Known devices table current as of Jun/2012 and taken from linux. + * See drivers/mtd/devices/m25p80.c. + * + * Copyright (C) 2011 Edgar E. Iglesias <edgar.iglesias@gmail.com> + * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com> + * Copyright (C) 2012 PetaLogix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) a later version of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw.h" +#include "sysemu/blockdev.h" +#include "ssi.h" +#include "devices.h" + +#ifdef M25P80_ERR_DEBUG +#define DB_PRINT(...) do { \ + fprintf(stderr, ": %s: ", __func__); \ + fprintf(stderr, ## __VA_ARGS__); \ + } while (0); +#else + #define DB_PRINT(...) +#endif + +/* Fields for FlashPartInfo->flags */ + +/* erase capabilities */ +#define ER_4K 1 +#define ER_32K 2 +/* set to allow the page program command to write 0s back to 1. Useful for + * modelling EEPROM with SPI flash command set + */ +#define WR_1 0x100 + +typedef struct FlashPartInfo { + const char *part_name; + /* jedec code. (jedec >> 16) & 0xff is the 1st byte, >> 8 the 2nd etc */ + uint32_t jedec; + /* extended jedec code */ + uint16_t ext_jedec; + /* there is confusion between manufacturers as to what a sector is. In this + * device model, a "sector" is the size that is erased by the ERASE_SECTOR + * command (opcode 0xd8). + */ + uint32_t sector_size; + uint32_t n_sectors; + uint32_t page_size; + uint8_t flags; +} FlashPartInfo; + +/* adapted from linux */ + +#define INFO(_part_name, _jedec, _ext_jedec, _sector_size, _n_sectors, _flags)\ + .part_name = (_part_name),\ + .jedec = (_jedec),\ + .ext_jedec = (_ext_jedec),\ + .sector_size = (_sector_size),\ + .n_sectors = (_n_sectors),\ + .page_size = 256,\ + .flags = (_flags),\ + +#define JEDEC_NUMONYX 0x20 +#define JEDEC_WINBOND 0xEF +#define JEDEC_SPANSION 0x01 + +static const FlashPartInfo known_devices[] = { + /* Atmel -- some are (confusingly) marketed as "DataFlash" */ + { INFO("at25fs010", 0x1f6601, 0, 32 << 10, 4, ER_4K) }, + { INFO("at25fs040", 0x1f6604, 0, 64 << 10, 8, ER_4K) }, + + { INFO("at25df041a", 0x1f4401, 0, 64 << 10, 8, ER_4K) }, + { INFO("at25df321a", 0x1f4701, 0, 64 << 10, 64, ER_4K) }, + { INFO("at25df641", 0x1f4800, 0, 64 << 10, 128, ER_4K) }, + + { INFO("at26f004", 0x1f0400, 0, 64 << 10, 8, ER_4K) }, + { INFO("at26df081a", 0x1f4501, 0, 64 << 10, 16, ER_4K) }, + { INFO("at26df161a", 0x1f4601, 0, 64 << 10, 32, ER_4K) }, + { INFO("at26df321", 0x1f4700, 0, 64 << 10, 64, ER_4K) }, + + /* EON -- en25xxx */ + { INFO("en25f32", 0x1c3116, 0, 64 << 10, 64, ER_4K) }, + { INFO("en25p32", 0x1c2016, 0, 64 << 10, 64, 0) }, + { INFO("en25q32b", 0x1c3016, 0, 64 << 10, 64, 0) }, + { INFO("en25p64", 0x1c2017, 0, 64 << 10, 128, 0) }, + + /* Intel/Numonyx -- xxxs33b */ + { INFO("160s33b", 0x898911, 0, 64 << 10, 32, 0) }, + { INFO("320s33b", 0x898912, 0, 64 << 10, 64, 0) }, + { INFO("640s33b", 0x898913, 0, 64 << 10, 128, 0) }, + + /* Macronix */ + { INFO("mx25l4005a", 0xc22013, 0, 64 << 10, 8, ER_4K) }, + { INFO("mx25l8005", 0xc22014, 0, 64 << 10, 16, 0) }, + { INFO("mx25l1606e", 0xc22015, 0, 64 << 10, 32, ER_4K) }, + { INFO("mx25l3205d", 0xc22016, 0, 64 << 10, 64, 0) }, + { INFO("mx25l6405d", 0xc22017, 0, 64 << 10, 128, 0) }, + { INFO("mx25l12805d", 0xc22018, 0, 64 << 10, 256, 0) }, + { INFO("mx25l12855e", 0xc22618, 0, 64 << 10, 256, 0) }, + { INFO("mx25l25635e", 0xc22019, 0, 64 << 10, 512, 0) }, + { INFO("mx25l25655e", 0xc22619, 0, 64 << 10, 512, 0) }, + + /* Spansion -- single (large) sector size only, at least + * for the chips listed here (without boot sectors). + */ + { INFO("s25sl004a", 0x010212, 0, 64 << 10, 8, 0) }, + { INFO("s25sl008a", 0x010213, 0, 64 << 10, 16, 0) }, + { INFO("s25sl016a", 0x010214, 0, 64 << 10, 32, 0) }, + { INFO("s25sl032a", 0x010215, 0, 64 << 10, 64, 0) }, + { INFO("s25sl032p", 0x010215, 0x4d00, 64 << 10, 64, ER_4K) }, + { INFO("s25sl064a", 0x010216, 0, 64 << 10, 128, 0) }, + { INFO("s25fl256s0", 0x010219, 0x4d00, 256 << 10, 128, 0) }, + { INFO("s25fl256s1", 0x010219, 0x4d01, 64 << 10, 512, 0) }, + { INFO("s25fl512s", 0x010220, 0x4d00, 256 << 10, 256, 0) }, + { INFO("s70fl01gs", 0x010221, 0x4d00, 256 << 10, 256, 0) }, + { INFO("s25sl12800", 0x012018, 0x0300, 256 << 10, 64, 0) }, + { INFO("s25sl12801", 0x012018, 0x0301, 64 << 10, 256, 0) }, + { INFO("s25fl129p0", 0x012018, 0x4d00, 256 << 10, 64, 0) }, + { INFO("s25fl129p1", 0x012018, 0x4d01, 64 << 10, 256, 0) }, + { INFO("s25fl016k", 0xef4015, 0, 64 << 10, 32, ER_4K | ER_32K) }, + { INFO("s25fl064k", 0xef4017, 0, 64 << 10, 128, ER_4K | ER_32K) }, + + /* SST -- large erase sizes are "overlays", "sectors" are 4<< 10 */ + { INFO("sst25vf040b", 0xbf258d, 0, 64 << 10, 8, ER_4K) }, + { INFO("sst25vf080b", 0xbf258e, 0, 64 << 10, 16, ER_4K) }, + { INFO("sst25vf016b", 0xbf2541, 0, 64 << 10, 32, ER_4K) }, + { INFO("sst25vf032b", 0xbf254a, 0, 64 << 10, 64, ER_4K) }, + { INFO("sst25wf512", 0xbf2501, 0, 64 << 10, 1, ER_4K) }, + { INFO("sst25wf010", 0xbf2502, 0, 64 << 10, 2, ER_4K) }, + { INFO("sst25wf020", 0xbf2503, 0, 64 << 10, 4, ER_4K) }, + { INFO("sst25wf040", 0xbf2504, 0, 64 << 10, 8, ER_4K) }, + + /* ST Microelectronics -- newer production may have feature updates */ + { INFO("m25p05", 0x202010, 0, 32 << 10, 2, 0) }, + { INFO("m25p10", 0x202011, 0, 32 << 10, 4, 0) }, + { INFO("m25p20", 0x202012, 0, 64 << 10, 4, 0) }, + { INFO("m25p40", 0x202013, 0, 64 << 10, 8, 0) }, + { INFO("m25p80", 0x202014, 0, 64 << 10, 16, 0) }, + { INFO("m25p16", 0x202015, 0, 64 << 10, 32, 0) }, + { INFO("m25p32", 0x202016, 0, 64 << 10, 64, 0) }, + { INFO("m25p64", 0x202017, 0, 64 << 10, 128, 0) }, + { INFO("m25p128", 0x202018, 0, 256 << 10, 64, 0) }, + + { INFO("m45pe10", 0x204011, 0, 64 << 10, 2, 0) }, + { INFO("m45pe80", 0x204014, 0, 64 << 10, 16, 0) }, + { INFO("m45pe16", 0x204015, 0, 64 << 10, 32, 0) }, + + { INFO("m25pe80", 0x208014, 0, 64 << 10, 16, 0) }, + { INFO("m25pe16", 0x208015, 0, 64 << 10, 32, ER_4K) }, + + { INFO("m25px32", 0x207116, 0, 64 << 10, 64, ER_4K) }, + { INFO("m25px32-s0", 0x207316, 0, 64 << 10, 64, ER_4K) }, + { INFO("m25px32-s1", 0x206316, 0, 64 << 10, 64, ER_4K) }, + { INFO("m25px64", 0x207117, 0, 64 << 10, 128, 0) }, + + /* Winbond -- w25x "blocks" are 64k, "sectors" are 4KiB */ + { INFO("w25x10", 0xef3011, 0, 64 << 10, 2, ER_4K) }, + { INFO("w25x20", 0xef3012, 0, 64 << 10, 4, ER_4K) }, + { INFO("w25x40", 0xef3013, 0, 64 << 10, 8, ER_4K) }, + { INFO("w25x80", 0xef3014, 0, 64 << 10, 16, ER_4K) }, + { INFO("w25x16", 0xef3015, 0, 64 << 10, 32, ER_4K) }, + { INFO("w25x32", 0xef3016, 0, 64 << 10, 64, ER_4K) }, + { INFO("w25q32", 0xef4016, 0, 64 << 10, 64, ER_4K) }, + { INFO("w25x64", 0xef3017, 0, 64 << 10, 128, ER_4K) }, + { INFO("w25q64", 0xef4017, 0, 64 << 10, 128, ER_4K) }, + + /* Numonyx -- n25q128 */ + { INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) }, + + { }, +}; + +typedef enum { + NOP = 0, + WRDI = 0x4, + RDSR = 0x5, + WREN = 0x6, + JEDEC_READ = 0x9f, + BULK_ERASE = 0xc7, + + READ = 0x3, + FAST_READ = 0xb, + DOR = 0x3b, + QOR = 0x6b, + DIOR = 0xbb, + QIOR = 0xeb, + + PP = 0x2, + DPP = 0xa2, + QPP = 0x32, + + ERASE_4K = 0x20, + ERASE_32K = 0x52, + ERASE_SECTOR = 0xd8, +} FlashCMD; + +typedef enum { + STATE_IDLE, + STATE_PAGE_PROGRAM, + STATE_READ, + STATE_COLLECTING_DATA, + STATE_READING_DATA, +} CMDState; + +typedef struct Flash { + SSISlave ssidev; + uint32_t r; + + BlockDriverState *bdrv; + + uint8_t *storage; + uint32_t size; + int page_size; + + uint8_t state; + uint8_t data[16]; + uint32_t len; + uint32_t pos; + uint8_t needed_bytes; + uint8_t cmd_in_progress; + uint64_t cur_addr; + bool write_enable; + + int64_t dirty_page; + + char *part_name; + const FlashPartInfo *pi; + +} Flash; + +static void bdrv_sync_complete(void *opaque, int ret) +{ + /* do nothing. Masters do not directly interact with the backing store, + * only the working copy so no mutexing required. + */ +} + +static void flash_sync_page(Flash *s, int page) +{ + if (s->bdrv) { + int bdrv_sector, nb_sectors; + QEMUIOVector iov; + + bdrv_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE; + nb_sectors = DIV_ROUND_UP(s->pi->page_size, BDRV_SECTOR_SIZE); + qemu_iovec_init(&iov, 1); + qemu_iovec_add(&iov, s->storage + bdrv_sector * BDRV_SECTOR_SIZE, + nb_sectors * BDRV_SECTOR_SIZE); + bdrv_aio_writev(s->bdrv, bdrv_sector, &iov, nb_sectors, + bdrv_sync_complete, NULL); + } +} + +static inline void flash_sync_area(Flash *s, int64_t off, int64_t len) +{ + int64_t start, end, nb_sectors; + QEMUIOVector iov; + + if (!s->bdrv) { + return; + } + + assert(!(len % BDRV_SECTOR_SIZE)); + start = off / BDRV_SECTOR_SIZE; + end = (off + len) / BDRV_SECTOR_SIZE; + nb_sectors = end - start; + qemu_iovec_init(&iov, 1); + qemu_iovec_add(&iov, s->storage + (start * BDRV_SECTOR_SIZE), + nb_sectors * BDRV_SECTOR_SIZE); + bdrv_aio_writev(s->bdrv, start, &iov, nb_sectors, bdrv_sync_complete, NULL); +} + +static void flash_erase(Flash *s, int offset, FlashCMD cmd) +{ + uint32_t len; + uint8_t capa_to_assert = 0; + + switch (cmd) { + case ERASE_4K: + len = 4 << 10; + capa_to_assert = ER_4K; + break; + case ERASE_32K: + len = 32 << 10; + capa_to_assert = ER_32K; + break; + case ERASE_SECTOR: + len = s->pi->sector_size; + break; + case BULK_ERASE: + len = s->size; + break; + default: + abort(); + } + + DB_PRINT("offset = %#x, len = %d\n", offset, len); + if ((s->pi->flags & capa_to_assert) != capa_to_assert) { + hw_error("m25p80: %dk erase size not supported by device\n", len); + } + + if (!s->write_enable) { + DB_PRINT("erase with write protect!\n"); + return; + } + memset(s->storage + offset, 0xff, len); + flash_sync_area(s, offset, len); +} + +static inline void flash_sync_dirty(Flash *s, int64_t newpage) +{ + if (s->dirty_page >= 0 && s->dirty_page != newpage) { + flash_sync_page(s, s->dirty_page); + s->dirty_page = newpage; + } +} + +static inline +void flash_write8(Flash *s, uint64_t addr, uint8_t data) +{ + int64_t page = addr / s->pi->page_size; + uint8_t prev = s->storage[s->cur_addr]; + + if (!s->write_enable) { + DB_PRINT("write with write protect!\n"); + } + + if ((prev ^ data) & data) { + DB_PRINT("programming zero to one! addr=%lx %x -> %x\n", + addr, prev, data); + } + + if (s->pi->flags & WR_1) { + s->storage[s->cur_addr] = data; + } else { + s->storage[s->cur_addr] &= data; + } + + flash_sync_dirty(s, page); + s->dirty_page = page; +} + +static void complete_collecting_data(Flash *s) +{ + s->cur_addr = s->data[0] << 16; + s->cur_addr |= s->data[1] << 8; + s->cur_addr |= s->data[2]; + + switch (s->cmd_in_progress) { + case DPP: + case QPP: + case PP: + s->state = STATE_PAGE_PROGRAM; + break; + case READ: + case FAST_READ: + case DOR: + case QOR: + case DIOR: + case QIOR: + s->state = STATE_READ; + break; + case ERASE_4K: + case ERASE_32K: + case ERASE_SECTOR: + flash_erase(s, s->cur_addr, s->cmd_in_progress); + break; + default: + break; + } +} + +static void decode_new_cmd(Flash *s, uint32_t value) +{ + s->cmd_in_progress = value; + DB_PRINT("decoded new command:%x\n", value); + + switch (value) { + + case ERASE_4K: + case ERASE_32K: + case ERASE_SECTOR: + case READ: + case DPP: + case QPP: + case PP: + s->needed_bytes = 3; + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; + break; + + case FAST_READ: + case DOR: + case QOR: + s->needed_bytes = 4; + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; + break; + + case DIOR: + switch ((s->pi->jedec >> 16) & 0xFF) { + case JEDEC_WINBOND: + case JEDEC_SPANSION: + s->needed_bytes = 4; + break; + case JEDEC_NUMONYX: + default: + s->needed_bytes = 5; + } + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; + break; + + case QIOR: + switch ((s->pi->jedec >> 16) & 0xFF) { + case JEDEC_WINBOND: + case JEDEC_SPANSION: + s->needed_bytes = 6; + break; + case JEDEC_NUMONYX: + default: + s->needed_bytes = 8; + } + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; + break; + + case WRDI: + s->write_enable = false; + break; + case WREN: + s->write_enable = true; + break; + + case RDSR: + s->data[0] = (!!s->write_enable) << 1; + s->pos = 0; + s->len = 1; + s->state = STATE_READING_DATA; + break; + + case JEDEC_READ: + DB_PRINT("populated jedec code\n"); + s->data[0] = (s->pi->jedec >> 16) & 0xff; + s->data[1] = (s->pi->jedec >> 8) & 0xff; + s->data[2] = s->pi->jedec & 0xff; + if (s->pi->ext_jedec) { + s->data[3] = (s->pi->ext_jedec >> 8) & 0xff; + s->data[4] = s->pi->ext_jedec & 0xff; + s->len = 5; + } else { + s->len = 3; + } + s->pos = 0; + s->state = STATE_READING_DATA; + break; + + case BULK_ERASE: + if (s->write_enable) { + DB_PRINT("chip erase\n"); + flash_erase(s, 0, BULK_ERASE); + } else { + DB_PRINT("chip erase with write protect!\n"); + } + break; + case NOP: + break; + default: + DB_PRINT("Unknown cmd %x\n", value); + break; + } +} + +static int m25p80_cs(SSISlave *ss, bool select) +{ + Flash *s = FROM_SSI_SLAVE(Flash, ss); + + if (select) { + s->len = 0; + s->pos = 0; + s->state = STATE_IDLE; + flash_sync_dirty(s, -1); + } + + DB_PRINT("%sselect\n", select ? "de" : ""); + + return 0; +} + +static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx) +{ + Flash *s = FROM_SSI_SLAVE(Flash, ss); + uint32_t r = 0; + + switch (s->state) { + + case STATE_PAGE_PROGRAM: + DB_PRINT("page program cur_addr=%lx data=%x\n", s->cur_addr, + (uint8_t)tx); + flash_write8(s, s->cur_addr, (uint8_t)tx); + s->cur_addr++; + break; + + case STATE_READ: + r = s->storage[s->cur_addr]; + DB_PRINT("READ 0x%lx=%x\n", s->cur_addr, r); + s->cur_addr = (s->cur_addr + 1) % s->size; + break; + + case STATE_COLLECTING_DATA: + s->data[s->len] = (uint8_t)tx; + s->len++; + + if (s->len == s->needed_bytes) { + complete_collecting_data(s); + } + break; + + case STATE_READING_DATA: + r = s->data[s->pos]; + s->pos++; + if (s->pos == s->len) { + s->pos = 0; + s->state = STATE_IDLE; + } + break; + + default: + case STATE_IDLE: + decode_new_cmd(s, (uint8_t)tx); + break; + } + + return r; +} + +static int m25p80_init(SSISlave *ss) +{ + DriveInfo *dinfo; + Flash *s = FROM_SSI_SLAVE(Flash, ss); + const FlashPartInfo *i; + + if (!s->part_name) { /* default to actual m25p80 if no partname given */ + s->part_name = (char *)"m25p80"; + } + + i = known_devices; + for (i = known_devices;; i++) { + assert(i); + if (!i->part_name) { + fprintf(stderr, "Unknown SPI flash part: \"%s\"\n", s->part_name); + return 1; + } else if (!strcmp(i->part_name, s->part_name)) { + s->pi = i; + break; + } + } + + s->size = s->pi->sector_size * s->pi->n_sectors; + s->dirty_page = -1; + s->storage = qemu_blockalign(s->bdrv, s->size); + + dinfo = drive_get_next(IF_MTD); + + if (dinfo && dinfo->bdrv) { + DB_PRINT("Binding to IF_MTD drive\n"); + s->bdrv = dinfo->bdrv; + /* FIXME: Move to late init */ + if (bdrv_read(s->bdrv, 0, s->storage, DIV_ROUND_UP(s->size, + BDRV_SECTOR_SIZE))) { + fprintf(stderr, "Failed to initialize SPI flash!\n"); + return 1; + } + } else { + memset(s->storage, 0xFF, s->size); + } + + return 0; +} + +static void m25p80_pre_save(void *opaque) +{ + flash_sync_dirty((Flash *)opaque, -1); +} + +static const VMStateDescription vmstate_m25p80 = { + .name = "xilinx_spi", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_save = m25p80_pre_save, + .fields = (VMStateField[]) { + VMSTATE_UINT8(state, Flash), + VMSTATE_UINT8_ARRAY(data, Flash, 16), + VMSTATE_UINT32(len, Flash), + VMSTATE_UINT32(pos, Flash), + VMSTATE_UINT8(needed_bytes, Flash), + VMSTATE_UINT8(cmd_in_progress, Flash), + VMSTATE_UINT64(cur_addr, Flash), + VMSTATE_BOOL(write_enable, Flash), + VMSTATE_END_OF_LIST() + } +}; + +static Property m25p80_properties[] = { + DEFINE_PROP_STRING("partname", Flash, part_name), + DEFINE_PROP_END_OF_LIST(), +}; + +static void m25p80_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = m25p80_init; + k->transfer = m25p80_transfer8; + k->set_cs = m25p80_cs; + k->cs_polarity = SSI_CS_LOW; + dc->props = m25p80_properties; + dc->vmsd = &vmstate_m25p80; +} + +static const TypeInfo m25p80_info = { + .name = "m25p80", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(Flash), + .class_init = m25p80_class_init, +}; + +static void m25p80_register_types(void) +{ + type_register_static(&m25p80_info); +} + +type_init(m25p80_register_types) diff --git a/hw/m48t59.c b/hw/m48t59.c index dd6cb37ba6..393c5c049a 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -23,10 +23,11 @@ */ #include "hw.h" #include "nvram.h" -#include "qemu-timer.h" -#include "sysemu.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" #include "sysbus.h" #include "isa.h" +#include "exec/address-spaces.h" //#define DEBUG_NVRAM @@ -80,6 +81,7 @@ typedef struct M48t59ISAState { typedef struct M48t59SysBusState { SysBusDevice busdev; M48t59State state; + MemoryRegion io; } M48t59SysBusState; /* Fake timer functions */ @@ -466,13 +468,6 @@ uint32_t m48t59_read (void *opaque, uint32_t addr) return retval; } -void m48t59_set_addr (void *opaque, uint32_t addr) -{ - M48t59State *NVRAM = opaque; - - NVRAM->addr = addr; -} - void m48t59_toggle_lock (void *opaque, int lock) { M48t59State *NVRAM = opaque; @@ -481,7 +476,8 @@ void m48t59_toggle_lock (void *opaque, int lock) } /* IO access to NVRAM */ -static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val) +static void NVRAM_writeb(void *opaque, hwaddr addr, uint64_t val, + unsigned size) { M48t59State *NVRAM = opaque; @@ -504,7 +500,7 @@ static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t NVRAM_readb (void *opaque, uint32_t addr) +static uint64_t NVRAM_readb(void *opaque, hwaddr addr, unsigned size) { M48t59State *NVRAM = opaque; uint32_t retval; @@ -522,14 +518,14 @@ static uint32_t NVRAM_readb (void *opaque, uint32_t addr) return retval; } -static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +static void nvram_writeb (void *opaque, hwaddr addr, uint32_t value) { M48t59State *NVRAM = opaque; m48t59_write(NVRAM, addr, value & 0xff); } -static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +static void nvram_writew (void *opaque, hwaddr addr, uint32_t value) { M48t59State *NVRAM = opaque; @@ -537,7 +533,7 @@ static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) m48t59_write(NVRAM, addr + 1, value & 0xff); } -static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +static void nvram_writel (void *opaque, hwaddr addr, uint32_t value) { M48t59State *NVRAM = opaque; @@ -547,7 +543,7 @@ static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) m48t59_write(NVRAM, addr + 3, value & 0xff); } -static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) +static uint32_t nvram_readb (void *opaque, hwaddr addr) { M48t59State *NVRAM = opaque; uint32_t retval; @@ -556,7 +552,7 @@ static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) return retval; } -static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) +static uint32_t nvram_readw (void *opaque, hwaddr addr) { M48t59State *NVRAM = opaque; uint32_t retval; @@ -566,7 +562,7 @@ static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) return retval; } -static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr) +static uint32_t nvram_readl (void *opaque, hwaddr addr) { M48t59State *NVRAM = opaque; uint32_t retval; @@ -626,17 +622,18 @@ static void m48t59_reset_sysbus(DeviceState *d) m48t59_reset_common(NVRAM); } -static const MemoryRegionPortio m48t59_portio[] = { - {0, 4, 1, .read = NVRAM_readb, .write = NVRAM_writeb }, - PORTIO_END_OF_LIST(), -}; - static const MemoryRegionOps m48t59_io_ops = { - .old_portio = m48t59_portio, + .read = NVRAM_readb, + .write = NVRAM_writeb, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; /* Initialisation routine */ -M48t59State *m48t59_init(qemu_irq IRQ, target_phys_addr_t mem_base, +M48t59State *m48t59_init(qemu_irq IRQ, hwaddr mem_base, uint32_t io_base, uint16_t size, int model) { DeviceState *dev; @@ -653,9 +650,9 @@ M48t59State *m48t59_init(qemu_irq IRQ, target_phys_addr_t mem_base, d = FROM_SYSBUS(M48t59SysBusState, s); state = &d->state; sysbus_connect_irq(s, 0, IRQ); + memory_region_init_io(&d->io, &m48t59_io_ops, state, "m48t59", 4); if (io_base != 0) { - register_ioport_read(io_base, 0x04, 1, NVRAM_readb, state); - register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, state); + memory_region_add_subregion(get_system_io(), io_base, &d->io); } if (mem_base != 0) { sysbus_mmio_map(s, 0, mem_base); diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index 1791ec12e1..b894ab21aa 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -39,6 +39,7 @@ #include "hw.h" #include "isa.h" #include "mac_dbdma.h" +#include "qemu/main-loop.h" /* debug DBDMA */ //#define DEBUG_DBDMA @@ -699,7 +700,7 @@ dbdma_control_write(DBDMA_channel *ch) ch->flush(&ch->io); } -static void dbdma_write(void *opaque, target_phys_addr_t addr, +static void dbdma_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { int channel = addr >> DBDMA_CHANNEL_SHIFT; @@ -749,7 +750,7 @@ static void dbdma_write(void *opaque, target_phys_addr_t addr, } } -static uint64_t dbdma_read(void *opaque, target_phys_addr_t addr, +static uint64_t dbdma_read(void *opaque, hwaddr addr, unsigned size) { uint32_t value; diff --git a/hw/mac_dbdma.h b/hw/mac_dbdma.h index 6d1abe6aae..691263eede 100644 --- a/hw/mac_dbdma.h +++ b/hw/mac_dbdma.h @@ -19,8 +19,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#ifndef HW_MAC_DBDMA_H +#define HW_MAC_DBDMA_H 1 -#include "memory.h" +#include "exec/memory.h" typedef struct DBDMA_io DBDMA_io; @@ -30,7 +32,7 @@ typedef void (*DBDMA_end)(DBDMA_io *io); struct DBDMA_io { void *opaque; void *channel; - target_phys_addr_t addr; + hwaddr addr; int len; int is_last; int is_dma_out; @@ -42,3 +44,5 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, DBDMA_rw rw, DBDMA_flush flush, void *opaque); void* DBDMA_init (MemoryRegion **dbdma_mem); + +#endif diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c index ed0a2b7ef2..71093c2b10 100644 --- a/hw/mac_nvram.c +++ b/hw/mac_nvram.c @@ -24,7 +24,7 @@ */ #include "hw.h" #include "firmware_abi.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "ppc_mac.h" /* debug NVR */ @@ -71,7 +71,7 @@ void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val) } /* macio style NVRAM device */ -static void macio_nvram_writeb(void *opaque, target_phys_addr_t addr, +static void macio_nvram_writeb(void *opaque, hwaddr addr, uint64_t value, unsigned size) { MacIONVRAMState *s = opaque; @@ -81,7 +81,7 @@ static void macio_nvram_writeb(void *opaque, target_phys_addr_t addr, NVR_DPRINTF("writeb addr %04x val %x\n", (int)addr, value); } -static uint64_t macio_nvram_readb(void *opaque, target_phys_addr_t addr, +static uint64_t macio_nvram_readb(void *opaque, hwaddr addr, unsigned size) { MacIONVRAMState *s = opaque; @@ -116,7 +116,7 @@ static void macio_nvram_reset(void *opaque) { } -MacIONVRAMState *macio_nvram_init (target_phys_addr_t size, +MacIONVRAMState *macio_nvram_init (hwaddr size, unsigned int it_shift) { MacIONVRAMState *s; @@ -135,7 +135,7 @@ MacIONVRAMState *macio_nvram_init (target_phys_addr_t size, } void macio_nvram_setup_bar(MacIONVRAMState *s, MemoryRegion *bar, - target_phys_addr_t mem_base) + hwaddr mem_base) { memory_region_add_subregion(bar, mem_base, &s->mem); } diff --git a/hw/macio.c b/hw/macio.c index eb15b890b1..362afdc7ec 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -24,7 +24,7 @@ */ #include "hw.h" #include "ppc_mac.h" -#include "pci.h" +#include "pci/pci.h" #include "escc.h" typedef struct MacIOState diff --git a/hw/mainstone.c b/hw/mainstone.c index 97687b6eeb..a5ddbeff9d 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -14,13 +14,13 @@ #include "hw.h" #include "pxa.h" #include "arm-misc.h" -#include "net.h" +#include "net/net.h" #include "devices.h" #include "boards.h" #include "flash.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "sysbus.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" /* Device addresses */ #define MST_FPGA_PHYS 0x08000000 @@ -95,19 +95,18 @@ static struct arm_boot_info mainstone_binfo = { }; static void mainstone_common_init(MemoryRegion *address_space_mem, - ram_addr_t ram_size, - const char *kernel_filename, - const char *kernel_cmdline, const char *initrd_filename, - const char *cpu_model, enum mainstone_model_e model, int arm_id) + QEMUMachineInitArgs *args, + enum mainstone_model_e model, int arm_id) { uint32_t sector_len = 256 * 1024; - target_phys_addr_t mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 }; + hwaddr mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 }; PXA2xxState *mpu; DeviceState *mst_irq; DriveInfo *dinfo; int i; int be; MemoryRegion *rom = g_new(MemoryRegion, 1); + const char *cpu_model = args->cpu_model; if (!cpu_model) cpu_model = "pxa270-c5"; @@ -164,20 +163,16 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, smc91c111_init(&nd_table[0], MST_ETH_PHYS, qdev_get_gpio_in(mst_irq, ETHERNET_IRQ)); - mainstone_binfo.kernel_filename = kernel_filename; - mainstone_binfo.kernel_cmdline = kernel_cmdline; - mainstone_binfo.initrd_filename = initrd_filename; + mainstone_binfo.kernel_filename = args->kernel_filename; + mainstone_binfo.kernel_cmdline = args->kernel_cmdline; + mainstone_binfo.initrd_filename = args->initrd_filename; mainstone_binfo.board_id = arm_id; arm_load_kernel(mpu->cpu, &mainstone_binfo); } -static void mainstone_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void mainstone_init(QEMUMachineInitArgs *args) { - mainstone_common_init(get_system_memory(), ram_size, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, mainstone, 0x196); + mainstone_common_init(get_system_memory(), args, mainstone, 0x196); } static QEMUMachine mainstone2_machine = { diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c index f6f1937442..de16cfa090 100644 --- a/hw/marvell_88w8618_audio.c +++ b/hw/marvell_88w8618_audio.c @@ -138,7 +138,7 @@ static void mv88w8618_audio_clock_update(mv88w8618_audio_state *s) wm8750_set_bclk_in(s->wm, rate); } -static uint64_t mv88w8618_audio_read(void *opaque, target_phys_addr_t offset, +static uint64_t mv88w8618_audio_read(void *opaque, hwaddr offset, unsigned size) { mv88w8618_audio_state *s = opaque; @@ -164,7 +164,7 @@ static uint64_t mv88w8618_audio_read(void *opaque, target_phys_addr_t offset, } } -static void mv88w8618_audio_write(void *opaque, target_phys_addr_t offset, +static void mv88w8618_audio_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { mv88w8618_audio_state *s = opaque; diff --git a/hw/max111x.c b/hw/max111x.c index 706d89f4fd..67640f109a 100644 --- a/hw/max111x.c +++ b/hw/max111x.c @@ -99,10 +99,11 @@ static uint32_t max111x_transfer(SSISlave *dev, uint32_t value) static const VMStateDescription vmstate_max111x = { .name = "max111x", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, .fields = (VMStateField[]) { + VMSTATE_SSI_SLAVE(ssidev, MAX111xState), VMSTATE_UINT8(tb1, MAX111xState), VMSTATE_UINT8(rb2, MAX111xState), VMSTATE_UINT8(rb3, MAX111xState), diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 3777f858a1..2ddd7de09e 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -22,9 +22,10 @@ * THE SOFTWARE. */ #include "hw.h" -#include "qemu-timer.h" -#include "sysemu.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" #include "mc146818rtc.h" +#include "qapi/visitor.h" #ifdef TARGET_I386 #include "apic.h" @@ -45,36 +46,65 @@ # define DPRINTF_C(format, ...) do { } while (0) #endif +#define NSEC_PER_SEC 1000000000LL +#define SEC_PER_MIN 60 +#define MIN_PER_HOUR 60 +#define SEC_PER_HOUR 3600 +#define HOUR_PER_DAY 24 +#define SEC_PER_DAY 86400 + #define RTC_REINJECT_ON_ACK_COUNT 20 +#define RTC_CLOCK_RATE 32768 +#define UIP_HOLD_LENGTH (8 * NSEC_PER_SEC / 32768) typedef struct RTCState { ISADevice dev; MemoryRegion io; uint8_t cmos_data[128]; uint8_t cmos_index; - struct tm current_tm; int32_t base_year; + uint64_t base_rtc; + uint64_t last_update; + int64_t offset; qemu_irq irq; qemu_irq sqw_irq; int it_shift; /* periodic timer */ QEMUTimer *periodic_timer; int64_t next_periodic_time; - /* second update */ - int64_t next_second_time; + /* update-ended timer */ + QEMUTimer *update_timer; + uint64_t next_alarm_time; uint16_t irq_reinject_on_ack_count; uint32_t irq_coalesced; uint32_t period; QEMUTimer *coalesced_timer; - QEMUTimer *second_timer; - QEMUTimer *second_timer2; Notifier clock_reset_notifier; LostTickPolicy lost_tick_policy; Notifier suspend_notifier; } RTCState; static void rtc_set_time(RTCState *s); -static void rtc_copy_date(RTCState *s); +static void rtc_update_time(RTCState *s); +static void rtc_set_cmos(RTCState *s, const struct tm *tm); +static inline int rtc_from_bcd(RTCState *s, int a); +static uint64_t get_next_alarm(RTCState *s); + +static inline bool rtc_running(RTCState *s) +{ + return (!(s->cmos_data[RTC_REG_B] & REG_B_SET) && + (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20); +} + +static uint64_t get_guest_rtc_ns(RTCState *s) +{ + uint64_t guest_rtc; + uint64_t guest_clock = qemu_get_clock_ns(rtc_clock); + + guest_rtc = s->base_rtc * NSEC_PER_SEC + + guest_clock - s->last_update + s->offset; + return guest_rtc; +} #ifdef TARGET_I386 static void rtc_coalesced_timer_update(RTCState *s) @@ -85,7 +115,7 @@ static void rtc_coalesced_timer_update(RTCState *s) /* divide each RTC interval to 2 - 8 smaller intervals */ int c = MIN(s->irq_coalesced, 7) + 1; int64_t next_clock = qemu_get_clock_ns(rtc_clock) + - muldiv64(s->period / c, get_ticks_per_sec(), 32768); + muldiv64(s->period / c, get_ticks_per_sec(), RTC_CLOCK_RATE); qemu_mod_timer(s->coalesced_timer, next_clock); } } @@ -110,7 +140,8 @@ static void rtc_coalesced_timer(void *opaque) } #endif -static void rtc_timer_update(RTCState *s, int64_t current_time) +/* handle periodic timer */ +static void periodic_timer_update(RTCState *s, int64_t current_time) { int period_code, period; int64_t cur_clock, next_irq_clock; @@ -131,10 +162,10 @@ static void rtc_timer_update(RTCState *s, int64_t current_time) s->period = period; #endif /* compute 32 khz clock */ - cur_clock = muldiv64(current_time, 32768, get_ticks_per_sec()); + cur_clock = muldiv64(current_time, RTC_CLOCK_RATE, get_ticks_per_sec()); next_irq_clock = (cur_clock & ~(period - 1)) + period; s->next_periodic_time = - muldiv64(next_irq_clock, get_ticks_per_sec(), 32768) + 1; + muldiv64(next_irq_clock, get_ticks_per_sec(), RTC_CLOCK_RATE) + 1; qemu_mod_timer(s->periodic_timer, s->next_periodic_time); } else { #ifdef TARGET_I386 @@ -148,7 +179,7 @@ static void rtc_periodic_timer(void *opaque) { RTCState *s = opaque; - rtc_timer_update(s, s->next_periodic_time); + periodic_timer_update(s, s->next_periodic_time); s->cmos_data[RTC_REG_C] |= REG_C_PF; if (s->cmos_data[RTC_REG_B] & REG_B_PIE) { s->cmos_data[RTC_REG_C] |= REG_C_IRQF; @@ -175,7 +206,186 @@ static void rtc_periodic_timer(void *opaque) } } -static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) +/* handle update-ended timer */ +static void check_update_timer(RTCState *s) +{ + uint64_t next_update_time; + uint64_t guest_nsec; + int next_alarm_sec; + + /* From the data sheet: "Holding the dividers in reset prevents + * interrupts from operating, while setting the SET bit allows" + * them to occur. However, it will prevent an alarm interrupt + * from occurring, because the time of day is not updated. + */ + if ((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) { + qemu_del_timer(s->update_timer); + return; + } + if ((s->cmos_data[RTC_REG_C] & REG_C_UF) && + (s->cmos_data[RTC_REG_B] & REG_B_SET)) { + qemu_del_timer(s->update_timer); + return; + } + if ((s->cmos_data[RTC_REG_C] & REG_C_UF) && + (s->cmos_data[RTC_REG_C] & REG_C_AF)) { + qemu_del_timer(s->update_timer); + return; + } + + guest_nsec = get_guest_rtc_ns(s) % NSEC_PER_SEC; + /* if UF is clear, reprogram to next second */ + next_update_time = qemu_get_clock_ns(rtc_clock) + + NSEC_PER_SEC - guest_nsec; + + /* Compute time of next alarm. One second is already accounted + * for in next_update_time. + */ + next_alarm_sec = get_next_alarm(s); + s->next_alarm_time = next_update_time + (next_alarm_sec - 1) * NSEC_PER_SEC; + + if (s->cmos_data[RTC_REG_C] & REG_C_UF) { + /* UF is set, but AF is clear. Program the timer to target + * the alarm time. */ + next_update_time = s->next_alarm_time; + } + if (next_update_time != qemu_timer_expire_time_ns(s->update_timer)) { + qemu_mod_timer(s->update_timer, next_update_time); + } +} + +static inline uint8_t convert_hour(RTCState *s, uint8_t hour) +{ + if (!(s->cmos_data[RTC_REG_B] & REG_B_24H)) { + hour %= 12; + if (s->cmos_data[RTC_HOURS] & 0x80) { + hour += 12; + } + } + return hour; +} + +static uint64_t get_next_alarm(RTCState *s) +{ + int32_t alarm_sec, alarm_min, alarm_hour, cur_hour, cur_min, cur_sec; + int32_t hour, min, sec; + + rtc_update_time(s); + + alarm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]); + alarm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]); + alarm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]); + alarm_hour = alarm_hour == -1 ? -1 : convert_hour(s, alarm_hour); + + cur_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]); + cur_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]); + cur_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS]); + cur_hour = convert_hour(s, cur_hour); + + if (alarm_hour == -1) { + alarm_hour = cur_hour; + if (alarm_min == -1) { + alarm_min = cur_min; + if (alarm_sec == -1) { + alarm_sec = cur_sec + 1; + } else if (cur_sec > alarm_sec) { + alarm_min++; + } + } else if (cur_min == alarm_min) { + if (alarm_sec == -1) { + alarm_sec = cur_sec + 1; + } else { + if (cur_sec > alarm_sec) { + alarm_hour++; + } + } + if (alarm_sec == SEC_PER_MIN) { + /* wrap to next hour, minutes is not in don't care mode */ + alarm_sec = 0; + alarm_hour++; + } + } else if (cur_min > alarm_min) { + alarm_hour++; + } + } else if (cur_hour == alarm_hour) { + if (alarm_min == -1) { + alarm_min = cur_min; + if (alarm_sec == -1) { + alarm_sec = cur_sec + 1; + } else if (cur_sec > alarm_sec) { + alarm_min++; + } + + if (alarm_sec == SEC_PER_MIN) { + alarm_sec = 0; + alarm_min++; + } + /* wrap to next day, hour is not in don't care mode */ + alarm_min %= MIN_PER_HOUR; + } else if (cur_min == alarm_min) { + if (alarm_sec == -1) { + alarm_sec = cur_sec + 1; + } + /* wrap to next day, hours+minutes not in don't care mode */ + alarm_sec %= SEC_PER_MIN; + } + } + + /* values that are still don't care fire at the next min/sec */ + if (alarm_min == -1) { + alarm_min = 0; + } + if (alarm_sec == -1) { + alarm_sec = 0; + } + + /* keep values in range */ + if (alarm_sec == SEC_PER_MIN) { + alarm_sec = 0; + alarm_min++; + } + if (alarm_min == MIN_PER_HOUR) { + alarm_min = 0; + alarm_hour++; + } + alarm_hour %= HOUR_PER_DAY; + + hour = alarm_hour - cur_hour; + min = hour * MIN_PER_HOUR + alarm_min - cur_min; + sec = min * SEC_PER_MIN + alarm_sec - cur_sec; + return sec <= 0 ? sec + SEC_PER_DAY : sec; +} + +static void rtc_update_timer(void *opaque) +{ + RTCState *s = opaque; + int32_t irqs = REG_C_UF; + int32_t new_irqs; + + assert((s->cmos_data[RTC_REG_A] & 0x60) != 0x60); + + /* UIP might have been latched, update time and clear it. */ + rtc_update_time(s); + s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; + + if (qemu_get_clock_ns(rtc_clock) >= s->next_alarm_time) { + irqs |= REG_C_AF; + if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC); + } + } + + new_irqs = irqs & ~s->cmos_data[RTC_REG_C]; + s->cmos_data[RTC_REG_C] |= irqs; + if ((new_irqs & s->cmos_data[RTC_REG_B]) != 0) { + s->cmos_data[RTC_REG_C] |= REG_C_IRQF; + qemu_irq_raise(s->irq); + } + check_update_timer(s); +} + +static void cmos_ioport_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) { RTCState *s = opaque; @@ -189,7 +399,12 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) case RTC_MINUTES_ALARM: case RTC_HOURS_ALARM: s->cmos_data[s->cmos_index] = data; + check_update_timer(s); break; + case RTC_IBM_PS2_CENTURY_BYTE: + s->cmos_index = RTC_CENTURY; + /* fall through */ + case RTC_CENTURY: case RTC_SECONDS: case RTC_MINUTES: case RTC_HOURS: @@ -199,37 +414,66 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) case RTC_YEAR: s->cmos_data[s->cmos_index] = data; /* if in set mode, do not update the time */ - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + if (rtc_running(s)) { rtc_set_time(s); + check_update_timer(s); } break; case RTC_REG_A: + if ((data & 0x60) == 0x60) { + if (rtc_running(s)) { + rtc_update_time(s); + } + /* What happens to UIP when divider reset is enabled is + * unclear from the datasheet. Shouldn't matter much + * though. + */ + s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; + } else if (((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) && + (data & 0x70) <= 0x20) { + /* when the divider reset is removed, the first update cycle + * begins one-half second later*/ + if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { + s->offset = 500000000; + rtc_set_time(s); + } + s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; + } /* UIP bit is read only */ s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) | (s->cmos_data[RTC_REG_A] & REG_A_UIP); - rtc_timer_update(s, qemu_get_clock_ns(rtc_clock)); + periodic_timer_update(s, qemu_get_clock_ns(rtc_clock)); + check_update_timer(s); break; case RTC_REG_B: if (data & REG_B_SET) { + /* update cmos to when the rtc was stopping */ + if (rtc_running(s)) { + rtc_update_time(s); + } /* set mode: reset UIP mode */ s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; data &= ~REG_B_UIE; } else { /* if disabling set mode, update the time */ - if (s->cmos_data[RTC_REG_B] & REG_B_SET) { + if ((s->cmos_data[RTC_REG_B] & REG_B_SET) && + (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20) { + s->offset = get_guest_rtc_ns(s) % NSEC_PER_SEC; rtc_set_time(s); } } - if (((s->cmos_data[RTC_REG_B] ^ data) & (REG_B_DM | REG_B_24H)) && - !(data & REG_B_SET)) { - /* If the time format has changed and not in set mode, - update the registers immediately. */ - s->cmos_data[RTC_REG_B] = data; - rtc_copy_date(s); + /* if an interrupt flag is already set when the interrupt + * becomes enabled, raise an interrupt immediately. */ + if (data & s->cmos_data[RTC_REG_C] & REG_C_MASK) { + s->cmos_data[RTC_REG_C] |= REG_C_IRQF; + qemu_irq_raise(s->irq); } else { - s->cmos_data[RTC_REG_B] = data; + s->cmos_data[RTC_REG_C] &= ~REG_C_IRQF; + qemu_irq_lower(s->irq); } - rtc_timer_update(s, qemu_get_clock_ns(rtc_clock)); + s->cmos_data[RTC_REG_B] = data; + periodic_timer_update(s, qemu_get_clock_ns(rtc_clock)); + check_update_timer(s); break; case RTC_REG_C: case RTC_REG_D: @@ -253,6 +497,9 @@ static inline int rtc_to_bcd(RTCState *s, int a) static inline int rtc_from_bcd(RTCState *s, int a) { + if ((a & 0xc0) == 0xc0) { + return -1; + } if (s->cmos_data[RTC_REG_B] & REG_B_DM) { return a; } else { @@ -260,10 +507,8 @@ static inline int rtc_from_bcd(RTCState *s, int a) } } -static void rtc_set_time(RTCState *s) +static void rtc_get_time(RTCState *s, struct tm *tm) { - struct tm *tm = &s->current_tm; - tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]); tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]); tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f); @@ -276,14 +521,24 @@ static void rtc_set_time(RTCState *s) tm->tm_wday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1; tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]); tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1; - tm->tm_year = rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900; + tm->tm_year = + rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year + + rtc_from_bcd(s, s->cmos_data[RTC_CENTURY]) * 100 - 1900; +} + +static void rtc_set_time(RTCState *s) +{ + struct tm tm; + + rtc_get_time(s, &tm); + s->base_rtc = mktimegm(&tm); + s->last_update = qemu_get_clock_ns(rtc_clock); - rtc_change_mon_event(tm); + rtc_change_mon_event(&tm); } -static void rtc_copy_date(RTCState *s) +static void rtc_set_cmos(RTCState *s, const struct tm *tm) { - const struct tm *tm = &s->current_tm; int year; s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec); @@ -301,131 +556,53 @@ static void rtc_copy_date(RTCState *s) s->cmos_data[RTC_DAY_OF_WEEK] = rtc_to_bcd(s, tm->tm_wday + 1); s->cmos_data[RTC_DAY_OF_MONTH] = rtc_to_bcd(s, tm->tm_mday); s->cmos_data[RTC_MONTH] = rtc_to_bcd(s, tm->tm_mon + 1); - year = (tm->tm_year - s->base_year) % 100; - if (year < 0) - year += 100; - s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year); + year = tm->tm_year + 1900 - s->base_year; + s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year % 100); + s->cmos_data[RTC_CENTURY] = rtc_to_bcd(s, year / 100); } -/* month is between 0 and 11. */ -static int get_days_in_month(int month, int year) +static void rtc_update_time(RTCState *s) { - static const int days_tab[12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; - int d; - if ((unsigned )month >= 12) - return 31; - d = days_tab[month]; - if (month == 1) { - if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) - d++; - } - return d; -} + struct tm ret; + time_t guest_sec; + int64_t guest_nsec; -/* update 'tm' to the next second */ -static void rtc_next_second(struct tm *tm) -{ - int days_in_month; - - tm->tm_sec++; - if ((unsigned)tm->tm_sec >= 60) { - tm->tm_sec = 0; - tm->tm_min++; - if ((unsigned)tm->tm_min >= 60) { - tm->tm_min = 0; - tm->tm_hour++; - if ((unsigned)tm->tm_hour >= 24) { - tm->tm_hour = 0; - /* next day */ - tm->tm_wday++; - if ((unsigned)tm->tm_wday >= 7) - tm->tm_wday = 0; - days_in_month = get_days_in_month(tm->tm_mon, - tm->tm_year + 1900); - tm->tm_mday++; - if (tm->tm_mday < 1) { - tm->tm_mday = 1; - } else if (tm->tm_mday > days_in_month) { - tm->tm_mday = 1; - tm->tm_mon++; - if (tm->tm_mon >= 12) { - tm->tm_mon = 0; - tm->tm_year++; - } - } - } - } - } -} - - -static void rtc_update_second(void *opaque) -{ - RTCState *s = opaque; - int64_t delay; - - /* if the oscillator is not in normal operation, we do not update */ - if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) { - s->next_second_time += get_ticks_per_sec(); - qemu_mod_timer(s->second_timer, s->next_second_time); - } else { - rtc_next_second(&s->current_tm); + guest_nsec = get_guest_rtc_ns(s); + guest_sec = guest_nsec / NSEC_PER_SEC; + gmtime_r(&guest_sec, &ret); - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { - /* update in progress bit */ - s->cmos_data[RTC_REG_A] |= REG_A_UIP; - } - /* should be 244 us = 8 / 32768 seconds, but currently the - timers do not have the necessary resolution. */ - delay = (get_ticks_per_sec() * 1) / 100; - if (delay < 1) - delay = 1; - qemu_mod_timer(s->second_timer2, - s->next_second_time + delay); + /* Is SET flag of Register B disabled? */ + if ((s->cmos_data[RTC_REG_B] & REG_B_SET) == 0) { + rtc_set_cmos(s, &ret); } } -static void rtc_update_second2(void *opaque) +static int update_in_progress(RTCState *s) { - RTCState *s = opaque; + int64_t guest_nsec; - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { - rtc_copy_date(s); + if (!rtc_running(s)) { + return 0; } - - /* check alarm */ - if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 || - rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]) == s->current_tm.tm_sec) && - ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 || - rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]) == s->current_tm.tm_min) && - ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 || - rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]) == s->current_tm.tm_hour)) { - - s->cmos_data[RTC_REG_C] |= REG_C_AF; - if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC); - qemu_irq_raise(s->irq); - s->cmos_data[RTC_REG_C] |= REG_C_IRQF; + if (qemu_timer_pending(s->update_timer)) { + int64_t next_update_time = qemu_timer_expire_time_ns(s->update_timer); + /* Latch UIP until the timer expires. */ + if (qemu_get_clock_ns(rtc_clock) >= (next_update_time - UIP_HOLD_LENGTH)) { + s->cmos_data[RTC_REG_A] |= REG_A_UIP; + return 1; } } - /* update ended interrupt */ - s->cmos_data[RTC_REG_C] |= REG_C_UF; - if (s->cmos_data[RTC_REG_B] & REG_B_UIE) { - s->cmos_data[RTC_REG_C] |= REG_C_IRQF; - qemu_irq_raise(s->irq); + guest_nsec = get_guest_rtc_ns(s); + /* UIP bit will be set at last 244us of every second. */ + if ((guest_nsec % NSEC_PER_SEC) >= (NSEC_PER_SEC - UIP_HOLD_LENGTH)) { + return 1; } - - /* clear update in progress bit */ - s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; - - s->next_second_time += get_ticks_per_sec(); - qemu_mod_timer(s->second_timer, s->next_second_time); + return 0; } -static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) +static uint64_t cmos_ioport_read(void *opaque, hwaddr addr, + unsigned size) { RTCState *s = opaque; int ret; @@ -433,6 +610,10 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) return 0xff; } else { switch(s->cmos_index) { + case RTC_IBM_PS2_CENTURY_BYTE: + s->cmos_index = RTC_CENTURY; + /* fall through */ + case RTC_CENTURY: case RTC_SECONDS: case RTC_MINUTES: case RTC_HOURS: @@ -440,15 +621,28 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) case RTC_DAY_OF_MONTH: case RTC_MONTH: case RTC_YEAR: + /* if not in set mode, calibrate cmos before + * reading*/ + if (rtc_running(s)) { + rtc_update_time(s); + } ret = s->cmos_data[s->cmos_index]; break; case RTC_REG_A: + if (update_in_progress(s)) { + s->cmos_data[s->cmos_index] |= REG_A_UIP; + } else { + s->cmos_data[s->cmos_index] &= ~REG_A_UIP; + } ret = s->cmos_data[s->cmos_index]; break; case RTC_REG_C: ret = s->cmos_data[s->cmos_index]; qemu_irq_lower(s->irq); s->cmos_data[RTC_REG_C] = 0x00; + if (ret & (REG_C_UF | REG_C_AF)) { + check_update_timer(s); + } #ifdef TARGET_I386 if(s->irq_coalesced && (s->cmos_data[RTC_REG_B] & REG_B_PIE) && @@ -483,37 +677,32 @@ void rtc_set_memory(ISADevice *dev, int addr, int val) s->cmos_data[addr] = val; } -void rtc_set_date(ISADevice *dev, const struct tm *tm) -{ - RTCState *s = DO_UPCAST(RTCState, dev, dev); - s->current_tm = *tm; - rtc_copy_date(s); -} - -/* PC cmos mappings */ -#define REG_IBM_CENTURY_BYTE 0x32 -#define REG_IBM_PS2_CENTURY_BYTE 0x37 - static void rtc_set_date_from_host(ISADevice *dev) { RTCState *s = DO_UPCAST(RTCState, dev, dev); struct tm tm; - int val; - /* set the CMOS date */ qemu_get_timedate(&tm, 0); - rtc_set_date(dev, &tm); - val = rtc_to_bcd(s, (tm.tm_year / 100) + 19); - rtc_set_memory(dev, REG_IBM_CENTURY_BYTE, val); - rtc_set_memory(dev, REG_IBM_PS2_CENTURY_BYTE, val); + s->base_rtc = mktimegm(&tm); + s->last_update = qemu_get_clock_ns(rtc_clock); + s->offset = 0; + + /* set the CMOS date */ + rtc_set_cmos(s, &tm); } static int rtc_post_load(void *opaque, int version_id) { -#ifdef TARGET_I386 RTCState *s = opaque; + if (version_id <= 2) { + rtc_set_time(s); + s->offset = 0; + check_update_timer(s); + } + +#ifdef TARGET_I386 if (version_id >= 2) { if (s->lost_tick_policy == LOST_TICK_SLEW) { rtc_coalesced_timer_update(s); @@ -525,27 +714,24 @@ static int rtc_post_load(void *opaque, int version_id) static const VMStateDescription vmstate_rtc = { .name = "mc146818rtc", - .version_id = 2, + .version_id = 3, .minimum_version_id = 1, .minimum_version_id_old = 1, .post_load = rtc_post_load, .fields = (VMStateField []) { VMSTATE_BUFFER(cmos_data, RTCState), VMSTATE_UINT8(cmos_index, RTCState), - VMSTATE_INT32(current_tm.tm_sec, RTCState), - VMSTATE_INT32(current_tm.tm_min, RTCState), - VMSTATE_INT32(current_tm.tm_hour, RTCState), - VMSTATE_INT32(current_tm.tm_wday, RTCState), - VMSTATE_INT32(current_tm.tm_mday, RTCState), - VMSTATE_INT32(current_tm.tm_mon, RTCState), - VMSTATE_INT32(current_tm.tm_year, RTCState), + VMSTATE_UNUSED(7*4), VMSTATE_TIMER(periodic_timer, RTCState), VMSTATE_INT64(next_periodic_time, RTCState), - VMSTATE_INT64(next_second_time, RTCState), - VMSTATE_TIMER(second_timer, RTCState), - VMSTATE_TIMER(second_timer2, RTCState), + VMSTATE_UNUSED(3*8), VMSTATE_UINT32_V(irq_coalesced, RTCState, 2), VMSTATE_UINT32_V(period, RTCState, 2), + VMSTATE_UINT64_V(base_rtc, RTCState, 3), + VMSTATE_UINT64_V(last_update, RTCState, 3), + VMSTATE_INT64_V(offset, RTCState, 3), + VMSTATE_TIMER_V(update_timer, RTCState, 3), + VMSTATE_UINT64_V(next_alarm_time, RTCState, 3), VMSTATE_END_OF_LIST() } }; @@ -556,9 +742,8 @@ static void rtc_notify_clock_reset(Notifier *notifier, void *data) int64_t now = *(int64_t *)data; rtc_set_date_from_host(&s->dev); - s->next_second_time = now + (get_ticks_per_sec() * 99) / 100; - qemu_mod_timer(s->second_timer2, s->next_second_time); - rtc_timer_update(s, now); + periodic_timer_update(s, now); + check_update_timer(s); #ifdef TARGET_I386 if (s->lost_tick_policy == LOST_TICK_SLEW) { rtc_coalesced_timer_update(s); @@ -580,6 +765,7 @@ static void rtc_reset(void *opaque) s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE); s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF); + check_update_timer(s); qemu_irq_lower(s->irq); @@ -590,13 +776,14 @@ static void rtc_reset(void *opaque) #endif } -static const MemoryRegionPortio cmos_portio[] = { - {0, 2, 1, .read = cmos_ioport_read, .write = cmos_ioport_write }, - PORTIO_END_OF_LIST(), -}; - static const MemoryRegionOps cmos_ops = { - .old_portio = cmos_portio + .read = cmos_ioport_read, + .write = cmos_ioport_write, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static void rtc_get_date(Object *obj, Visitor *v, void *opaque, @@ -604,14 +791,17 @@ static void rtc_get_date(Object *obj, Visitor *v, void *opaque, { ISADevice *isa = ISA_DEVICE(obj); RTCState *s = DO_UPCAST(RTCState, dev, isa); + struct tm current_tm; + rtc_update_time(s); + rtc_get_time(s, ¤t_tm); visit_start_struct(v, NULL, "struct tm", name, 0, errp); - visit_type_int32(v, &s->current_tm.tm_year, "tm_year", errp); - visit_type_int32(v, &s->current_tm.tm_mon, "tm_mon", errp); - visit_type_int32(v, &s->current_tm.tm_mday, "tm_mday", errp); - visit_type_int32(v, &s->current_tm.tm_hour, "tm_hour", errp); - visit_type_int32(v, &s->current_tm.tm_min, "tm_min", errp); - visit_type_int32(v, &s->current_tm.tm_sec, "tm_sec", errp); + visit_type_int32(v, ¤t_tm.tm_year, "tm_year", errp); + visit_type_int32(v, ¤t_tm.tm_mon, "tm_mon", errp); + visit_type_int32(v, ¤t_tm.tm_mday, "tm_mday", errp); + visit_type_int32(v, ¤t_tm.tm_hour, "tm_hour", errp); + visit_type_int32(v, ¤t_tm.tm_min, "tm_min", errp); + visit_type_int32(v, ¤t_tm.tm_sec, "tm_sec", errp); visit_end_struct(v, errp); } @@ -625,6 +815,18 @@ static int rtc_initfn(ISADevice *dev) s->cmos_data[RTC_REG_C] = 0x00; s->cmos_data[RTC_REG_D] = 0x80; + /* This is for historical reasons. The default base year qdev property + * was set to 2000 for most machine types before the century byte was + * implemented. + * + * This if statement means that the century byte will be always 0 + * (at least until 2079...) for base_year = 1980, but will be set + * correctly for base_year = 2000. + */ + if (s->base_year == 2000) { + s->base_year = 0; + } + rtc_set_date_from_host(dev); #ifdef TARGET_I386 @@ -641,8 +843,8 @@ static int rtc_initfn(ISADevice *dev) #endif s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s); - s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s); - s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s); + s->update_timer = qemu_new_timer_ns(rtc_clock, rtc_update_timer, s); + check_update_timer(s); s->clock_reset_notifier.notify = rtc_notify_clock_reset; qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier); @@ -650,14 +852,10 @@ static int rtc_initfn(ISADevice *dev) s->suspend_notifier.notify = rtc_notify_suspend; qemu_register_suspend_notifier(&s->suspend_notifier); - s->next_second_time = - qemu_get_clock_ns(rtc_clock) + (get_ticks_per_sec() * 99) / 100; - qemu_mod_timer(s->second_timer2, s->next_second_time); - memory_region_init_io(&s->io, &cmos_ops, s, "rtc", 2); isa_register_ioport(dev, &s->io, base); - qdev_set_legacy_instance_id(&dev->qdev, base, 2); + qdev_set_legacy_instance_id(&dev->qdev, base, 3); qemu_register_reset(rtc_reset, s); object_property_add(OBJECT(s), "date", "struct tm", diff --git a/hw/mc146818rtc_regs.h b/hw/mc146818rtc_regs.h index 3ab37709f0..ccdee42b3c 100644 --- a/hw/mc146818rtc_regs.h +++ b/hw/mc146818rtc_regs.h @@ -44,6 +44,10 @@ #define RTC_REG_C 12 #define RTC_REG_D 13 +/* PC cmos mappings */ +#define RTC_CENTURY 0x32 +#define RTC_IBM_PS2_CENTURY_BYTE 0x37 + #define REG_A_UIP 0x80 #define REG_B_SET 0x80 @@ -58,5 +62,6 @@ #define REG_C_IRQF 0x80 #define REG_C_PF 0x40 #define REG_C_AF 0x20 +#define REG_C_MASK 0x70 #endif @@ -5,23 +5,23 @@ struct MemoryRegion; /* mcf_uart.c */ -uint64_t mcf_uart_read(void *opaque, target_phys_addr_t addr, +uint64_t mcf_uart_read(void *opaque, hwaddr addr, unsigned size); -void mcf_uart_write(void *opaque, target_phys_addr_t addr, +void mcf_uart_write(void *opaque, hwaddr addr, uint64_t val, unsigned size); void *mcf_uart_init(qemu_irq irq, CharDriverState *chr); void mcf_uart_mm_init(struct MemoryRegion *sysmem, - target_phys_addr_t base, + hwaddr base, qemu_irq irq, CharDriverState *chr); /* mcf_intc.c */ qemu_irq *mcf_intc_init(struct MemoryRegion *sysmem, - target_phys_addr_t base, + hwaddr base, CPUM68KState *env); /* mcf_fec.c */ void mcf_fec_init(struct MemoryRegion *sysmem, NICInfo *nd, - target_phys_addr_t base, qemu_irq *irq); + hwaddr base, qemu_irq *irq); /* mcf5206.c */ qemu_irq *mcf5206_init(struct MemoryRegion *sysmem, diff --git a/hw/mcf5206.c b/hw/mcf5206.c index 539b391338..d8c0059ed6 100644 --- a/hw/mcf5206.c +++ b/hw/mcf5206.c @@ -7,10 +7,10 @@ */ #include "hw.h" #include "mcf.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "ptimer.h" -#include "sysemu.h" -#include "exec-memory.h" +#include "sysemu/sysemu.h" +#include "exec/address-spaces.h" /* General purpose timer module. */ typedef struct { @@ -359,7 +359,7 @@ static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset, /* Internal peripherals use a variety of register widths. This lookup table allows a single routine to handle all of them. */ -static const int m5206_mbar_width[] = +static const uint8_t m5206_mbar_width[] = { /* 000-040 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, /* 040-080 */ 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2, @@ -371,14 +371,14 @@ static const int m5206_mbar_width[] = /* 1c0-200 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; -static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset); -static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset); +static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset); +static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset); -static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset) +static uint32_t m5206_mbar_readb(void *opaque, hwaddr offset) { m5206_mbar_state *s = (m5206_mbar_state *)opaque; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR read offset 0x%x", (int)offset); } if (m5206_mbar_width[offset >> 2] > 1) { @@ -392,12 +392,12 @@ static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset) return m5206_mbar_read(s, offset, 1); } -static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset) +static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset) { m5206_mbar_state *s = (m5206_mbar_state *)opaque; int width; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR read offset 0x%x", (int)offset); } width = m5206_mbar_width[offset >> 2]; @@ -416,12 +416,12 @@ static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset) return m5206_mbar_read(s, offset, 2); } -static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset) +static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset) { m5206_mbar_state *s = (m5206_mbar_state *)opaque; int width; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR read offset 0x%x", (int)offset); } width = m5206_mbar_width[offset >> 2]; @@ -434,18 +434,18 @@ static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset) return m5206_mbar_read(s, offset, 4); } -static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset, +static void m5206_mbar_writew(void *opaque, hwaddr offset, uint32_t value); -static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset, +static void m5206_mbar_writel(void *opaque, hwaddr offset, uint32_t value); -static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset, +static void m5206_mbar_writeb(void *opaque, hwaddr offset, uint32_t value) { m5206_mbar_state *s = (m5206_mbar_state *)opaque; int width; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR write offset 0x%x", (int)offset); } width = m5206_mbar_width[offset >> 2]; @@ -463,13 +463,13 @@ static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset, m5206_mbar_write(s, offset, value, 1); } -static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset, +static void m5206_mbar_writew(void *opaque, hwaddr offset, uint32_t value) { m5206_mbar_state *s = (m5206_mbar_state *)opaque; int width; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR write offset 0x%x", (int)offset); } width = m5206_mbar_width[offset >> 2]; @@ -491,13 +491,13 @@ static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset, m5206_mbar_write(s, offset, value, 2); } -static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset, +static void m5206_mbar_writel(void *opaque, hwaddr offset, uint32_t value) { m5206_mbar_state *s = (m5206_mbar_state *)opaque; int width; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR write offset 0x%x", (int)offset); } width = m5206_mbar_width[offset >> 2]; diff --git a/hw/mcf5208.c b/hw/mcf5208.c index ee25b1b387..c1816cc9d1 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -7,14 +7,14 @@ */ #include "hw.h" #include "mcf.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "ptimer.h" -#include "sysemu.h" -#include "net.h" +#include "sysemu/sysemu.h" +#include "net/net.h" #include "boards.h" #include "loader.h" #include "elf.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #define SYS_FREQ 66000000 @@ -45,7 +45,7 @@ static void m5208_timer_update(m5208_timer_state *s) qemu_irq_lower(s->irq); } -static void m5208_timer_write(void *opaque, target_phys_addr_t offset, +static void m5208_timer_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { m5208_timer_state *s = (m5208_timer_state *)opaque; @@ -107,7 +107,7 @@ static void m5208_timer_trigger(void *opaque) m5208_timer_update(s); } -static uint64_t m5208_timer_read(void *opaque, target_phys_addr_t addr, +static uint64_t m5208_timer_read(void *opaque, hwaddr addr, unsigned size) { m5208_timer_state *s = (m5208_timer_state *)opaque; @@ -130,7 +130,7 @@ static const MemoryRegionOps m5208_timer_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint64_t m5208_sys_read(void *opaque, target_phys_addr_t addr, +static uint64_t m5208_sys_read(void *opaque, hwaddr addr, unsigned size) { switch (addr) { @@ -152,7 +152,7 @@ static uint64_t m5208_sys_read(void *opaque, target_phys_addr_t addr, } } -static void m5208_sys_write(void *opaque, target_phys_addr_t addr, +static void m5208_sys_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { hw_error("m5208_sys_write: Bad offset 0x%x\n", (int)addr); @@ -187,15 +187,15 @@ static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic) } } -static void mcf5208evb_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void mcf5208evb_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; CPUM68KState *env; int kernel_size; uint64_t elf_entry; - target_phys_addr_t entry; + hwaddr entry; qemu_irq *pic; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 2fec5bc73e..2423f64bf6 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -6,11 +6,11 @@ * This code is licensed under the GPL */ #include "hw.h" -#include "net.h" +#include "net/net.h" #include "mcf.h" /* For crc32 */ #include <zlib.h> -#include "exec-memory.h" +#include "exec/address-spaces.h" //#define DEBUG_FEC 1 @@ -216,7 +216,7 @@ static void mcf_fec_reset(mcf_fec_state *s) s->rfsr = 0x500; } -static uint64_t mcf_fec_read(void *opaque, target_phys_addr_t addr, +static uint64_t mcf_fec_read(void *opaque, hwaddr addr, unsigned size) { mcf_fec_state *s = (mcf_fec_state *)opaque; @@ -254,7 +254,7 @@ static uint64_t mcf_fec_read(void *opaque, target_phys_addr_t addr, } } -static void mcf_fec_write(void *opaque, target_phys_addr_t addr, +static void mcf_fec_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { mcf_fec_state *s = (mcf_fec_state *)opaque; @@ -458,7 +458,7 @@ static NetClientInfo net_mcf_fec_info = { }; void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd, - target_phys_addr_t base, qemu_irq *irq) + hwaddr base, qemu_irq *irq) { mcf_fec_state *s; diff --git a/hw/mcf_intc.c b/hw/mcf_intc.c index cc1a5f3763..3bed3a2e4c 100644 --- a/hw/mcf_intc.c +++ b/hw/mcf_intc.c @@ -7,7 +7,7 @@ */ #include "hw.h" #include "mcf.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" typedef struct { MemoryRegion iomem; @@ -43,7 +43,7 @@ static void mcf_intc_update(mcf_intc_state *s) m68k_set_irq_level(s->env, best_level, s->active_vector); } -static uint64_t mcf_intc_read(void *opaque, target_phys_addr_t addr, +static uint64_t mcf_intc_read(void *opaque, hwaddr addr, unsigned size) { int offset; @@ -76,7 +76,7 @@ static uint64_t mcf_intc_read(void *opaque, target_phys_addr_t addr, } } -static void mcf_intc_write(void *opaque, target_phys_addr_t addr, +static void mcf_intc_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { int offset; @@ -138,7 +138,7 @@ static const MemoryRegionOps mcf_intc_ops = { }; qemu_irq *mcf_intc_init(MemoryRegion *sysmem, - target_phys_addr_t base, + hwaddr base, CPUM68KState *env) { mcf_intc_state *s; diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c index ec6a87f238..c44344317a 100644 --- a/hw/mcf_uart.c +++ b/hw/mcf_uart.c @@ -7,8 +7,8 @@ */ #include "hw.h" #include "mcf.h" -#include "qemu-char.h" -#include "exec-memory.h" +#include "char/char.h" +#include "exec/address-spaces.h" typedef struct { MemoryRegion iomem; @@ -66,7 +66,7 @@ static void mcf_uart_update(mcf_uart_state *s) qemu_set_irq(s->irq, (s->isr & s->imr) != 0); } -uint64_t mcf_uart_read(void *opaque, target_phys_addr_t addr, +uint64_t mcf_uart_read(void *opaque, hwaddr addr, unsigned size) { mcf_uart_state *s = (mcf_uart_state *)opaque; @@ -185,7 +185,7 @@ static void mcf_do_command(mcf_uart_state *s, uint8_t cmd) } } -void mcf_uart_write(void *opaque, target_phys_addr_t addr, +void mcf_uart_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { mcf_uart_state *s = (mcf_uart_state *)opaque; @@ -294,7 +294,7 @@ static const MemoryRegionOps mcf_uart_ops = { }; void mcf_uart_mm_init(MemoryRegion *sysmem, - target_phys_addr_t base, + hwaddr base, qemu_irq irq, CharDriverState *chr) { diff --git a/hw/megasas.c b/hw/megasas.c index c35a15db4f..eb191f5e12 100644 --- a/hw/megasas.c +++ b/hw/megasas.c @@ -19,13 +19,12 @@ */ #include "hw.h" -#include "pci.h" -#include "dma.h" -#include "msix.h" -#include "iov.h" +#include "pci/pci.h" +#include "sysemu/dma.h" +#include "pci/msix.h" +#include "qemu/iov.h" #include "scsi.h" #include "scsi-defs.h" -#include "block_int.h" #include "trace.h" #include "mfi.h" @@ -38,6 +37,7 @@ #define MEGASAS_MAX_SECTORS 0xFFFF /* No real limit */ #define MEGASAS_MAX_ARRAYS 128 +#define MEGASAS_HBA_SERIAL "QEMU123456" #define NAA_LOCALLY_ASSIGNED_ID 0x3ULL #define IEEE_COMPANY_LOCALLY_ASSIGNED 0x525400 @@ -58,8 +58,8 @@ typedef struct MegasasCmd { uint16_t count; uint64_t context; - target_phys_addr_t pa; - target_phys_addr_t pa_size; + hwaddr pa; + hwaddr pa_size; union mfi_frame *frame; SCSIRequest *req; QEMUSGList qsg; @@ -93,6 +93,7 @@ typedef struct MegasasState { int boot_event; uint64_t sas_addr; + char *hba_serial; uint64_t reply_queue_pa; void *reply_queue; @@ -275,7 +276,7 @@ static int megasas_build_sense(MegasasCmd *cmd, uint8_t *sense_ptr, uint8_t sense_len) { uint32_t pa_hi = 0, pa_lo; - target_phys_addr_t pa; + hwaddr pa; if (sense_len > cmd->frame->header.sense_len) { sense_len = cmd->frame->header.sense_len; @@ -402,7 +403,7 @@ static int megasas_next_index(MegasasState *s, int index, int limit) } static MegasasCmd *megasas_lookup_frame(MegasasState *s, - target_phys_addr_t frame) + hwaddr frame) { MegasasCmd *cmd = NULL; int num = 0, index; @@ -422,7 +423,7 @@ static MegasasCmd *megasas_lookup_frame(MegasasState *s, } static MegasasCmd *megasas_next_frame(MegasasState *s, - target_phys_addr_t frame) + hwaddr frame) { MegasasCmd *cmd = NULL; int num = 0, index; @@ -450,11 +451,11 @@ static MegasasCmd *megasas_next_frame(MegasasState *s, } static MegasasCmd *megasas_enqueue_frame(MegasasState *s, - target_phys_addr_t frame, uint64_t context, int count) + hwaddr frame, uint64_t context, int count) { MegasasCmd *cmd = NULL; int frame_size = MFI_FRAME_SIZE * 16; - target_phys_addr_t frame_size_p = frame_size; + hwaddr frame_size_p = frame_size; cmd = megasas_next_frame(s, frame); /* All frames busy */ @@ -559,7 +560,7 @@ static void megasas_abort_command(MegasasCmd *cmd) static int megasas_init_firmware(MegasasState *s, MegasasCmd *cmd) { uint32_t pa_hi, pa_lo; - target_phys_addr_t iq_pa, initq_size; + hwaddr iq_pa, initq_size; struct mfi_init_qinfo *initq; uint32_t flags; int ret = MFI_STAT_OK; @@ -650,7 +651,6 @@ static void megasas_finish_dcmd(MegasasCmd *cmd, uint32_t iov_size) } } cmd->iov_size = 0; - return; } static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) @@ -698,8 +698,7 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) } memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20); - snprintf(info.serial_number, 32, "QEMU%08lx", - (unsigned long)s & 0xFFFFFFFF); + snprintf(info.serial_number, 32, "%s", s->hba_serial); snprintf(info.package_version, 0x60, "%s-QEMU", QEMU_VERSION); memcpy(info.image_component[0].name, "APP", 3); memcpy(info.image_component[0].version, MEGASAS_VERSION "-QEMU", 9); @@ -1080,6 +1079,7 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd) /* Logical device size is in blocks */ bdrv_get_geometry(conf->bs, &ld_size); info.ld_list[num_ld_disks].ld.v.target_id = sdev->id; + info.ld_list[num_ld_disks].ld.v.lun_id = sdev->lun; info.ld_list[num_ld_disks].state = MFI_LD_STATE_OPTIMAL; info.ld_list[num_ld_disks].size = cpu_to_le64(ld_size); num_ld_disks++; @@ -1296,7 +1296,7 @@ static int megasas_dcmd_get_properties(MegasasState *s, MegasasCmd *cmd) static int megasas_cache_flush(MegasasState *s, MegasasCmd *cmd) { - qemu_aio_flush(); + bdrv_drain_all(); return MFI_STAT_OK; } @@ -1771,7 +1771,7 @@ static void megasas_command_cancel(SCSIRequest *req) static int megasas_handle_abort(MegasasState *s, MegasasCmd *cmd) { uint64_t abort_ctx = le64_to_cpu(cmd->frame->abort.abort_context); - target_phys_addr_t abort_addr, addr_hi, addr_lo; + hwaddr abort_addr, addr_hi, addr_lo; MegasasCmd *abort_cmd; addr_hi = le32_to_cpu(cmd->frame->abort.abort_mfi_addr_hi); @@ -1861,7 +1861,7 @@ static void megasas_handle_frame(MegasasState *s, uint64_t frame_addr, } } -static uint64_t megasas_mmio_read(void *opaque, target_phys_addr_t addr, +static uint64_t megasas_mmio_read(void *opaque, hwaddr addr, unsigned size) { MegasasState *s = opaque; @@ -1897,7 +1897,7 @@ static uint64_t megasas_mmio_read(void *opaque, target_phys_addr_t addr, return retval; } -static void megasas_mmio_write(void *opaque, target_phys_addr_t addr, +static void megasas_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { MegasasState *s = opaque; @@ -1977,13 +1977,13 @@ static const MemoryRegionOps megasas_mmio_ops = { } }; -static uint64_t megasas_port_read(void *opaque, target_phys_addr_t addr, +static uint64_t megasas_port_read(void *opaque, hwaddr addr, unsigned size) { return megasas_mmio_read(opaque, addr & 0xff, size); } -static void megasas_port_write(void *opaque, target_phys_addr_t addr, +static void megasas_port_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { megasas_mmio_write(opaque, addr & 0xff, val, size); @@ -1999,7 +1999,7 @@ static const MemoryRegionOps megasas_port_ops = { } }; -static uint64_t megasas_queue_read(void *opaque, target_phys_addr_t addr, +static uint64_t megasas_queue_read(void *opaque, hwaddr addr, unsigned size) { return 0; @@ -2132,6 +2132,9 @@ static int megasas_scsi_init(PCIDevice *dev) s->sas_addr |= (PCI_SLOT(dev->devfn) << 8); s->sas_addr |= PCI_FUNC(dev->devfn); } + if (!s->hba_serial) { + s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL); + } if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) { s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE; } else if (s->fw_sge >= 128 - MFI_PASS_FRAME_SIZE) { @@ -2166,6 +2169,7 @@ static Property megasas_properties[] = { MEGASAS_DEFAULT_SGE), DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds, MEGASAS_DEFAULT_FRAMES), + DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial), DEFINE_PROP_HEX64("sas_address", MegasasState, sas_addr, 0), #ifdef USE_MSIX DEFINE_PROP_BIT("use_msix", MegasasState, flags, @@ -1085,7 +1085,7 @@ struct mfi_pd_list { union mfi_ld_ref { struct { uint8_t target_id; - uint8_t reserved; + uint8_t lun_id; uint16_t seq; } v; uint32_t ref; diff --git a/hw/microblaze/Makefile.objs b/hw/microblaze/Makefile.objs index 274d2c543e..3028e651c8 100644 --- a/hw/microblaze/Makefile.objs +++ b/hw/microblaze/Makefile.objs @@ -1,6 +1,7 @@ obj-y = petalogix_s3adsp1800_mmu.o obj-y += petalogix_ml605_mmu.o obj-y += microblaze_boot.o +obj-y += xilinx_spi.o obj-y += microblaze_pic_cpu.o obj-y += xilinx_ethlite.o diff --git a/hw/microblaze_boot.c b/hw/microblaze_boot.c index 1030e9c8ed..3ec5c0f7dd 100644 --- a/hw/microblaze_boot.c +++ b/hw/microblaze_boot.c @@ -24,10 +24,10 @@ * THE SOFTWARE. */ -#include "qemu-option.h" -#include "qemu-config.h" +#include "qemu/option.h" +#include "qemu/config-file.h" #include "qemu-common.h" -#include "device_tree.h" +#include "sysemu/device_tree.h" #include "loader.h" #include "elf.h" @@ -55,7 +55,7 @@ static void main_cpu_reset(void *opaque) } } -static int microblaze_load_dtb(target_phys_addr_t addr, +static int microblaze_load_dtb(hwaddr addr, uint32_t ramsize, const char *kernel_cmdline, const char *dtb_filename) @@ -100,7 +100,7 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) return addr - 0x30000000LL; } -void microblaze_load_kernel(MicroBlazeCPU *cpu, target_phys_addr_t ddr_base, +void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, uint32_t ramsize, const char *dtb_filename, void (*machine_cpu_reset)(MicroBlazeCPU *)) { @@ -149,7 +149,7 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, target_phys_addr_t ddr_base, /* If it wasn't an ELF image, try an u-boot image. */ if (kernel_size < 0) { - target_phys_addr_t uentry, loadaddr; + hwaddr uentry, loadaddr; kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0); boot_info.bootstrap_pc = uentry; diff --git a/hw/microblaze_boot.h b/hw/microblaze_boot.h index c9a3064d27..c1cf836b99 100644 --- a/hw/microblaze_boot.h +++ b/hw/microblaze_boot.h @@ -3,7 +3,7 @@ #include "hw.h" -void microblaze_load_kernel(MicroBlazeCPU *cpu, target_phys_addr_t ddr_base, +void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, uint32_t ramsize, const char *dtb_filename, void (*machine_cpu_reset)(MicroBlazeCPU *)); diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c index 4414f39734..f46af1c509 100644 --- a/hw/milkymist-ac97.c +++ b/hw/milkymist-ac97.c @@ -25,7 +25,7 @@ #include "sysbus.h" #include "trace.h" #include "audio/audio.h" -#include "qemu-error.h" +#include "qemu/error-report.h" enum { R_AC97_CTRL = 0, @@ -83,7 +83,7 @@ static void update_voices(MilkymistAC97State *s) } } -static uint64_t ac97_read(void *opaque, target_phys_addr_t addr, +static uint64_t ac97_read(void *opaque, hwaddr addr, unsigned size) { MilkymistAC97State *s = opaque; @@ -115,7 +115,7 @@ static uint64_t ac97_read(void *opaque, target_phys_addr_t addr, return r; } -static void ac97_write(void *opaque, target_phys_addr_t addr, uint64_t value, +static void ac97_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { MilkymistAC97State *s = opaque; diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c index 2da0293683..fd54d3129a 100644 --- a/hw/milkymist-hpdmc.c +++ b/hw/milkymist-hpdmc.c @@ -24,7 +24,7 @@ #include "hw.h" #include "sysbus.h" #include "trace.h" -#include "qemu-error.h" +#include "qemu/error-report.h" enum { R_SYSTEM = 0, @@ -48,7 +48,7 @@ struct MilkymistHpdmcState { }; typedef struct MilkymistHpdmcState MilkymistHpdmcState; -static uint64_t hpdmc_read(void *opaque, target_phys_addr_t addr, +static uint64_t hpdmc_read(void *opaque, hwaddr addr, unsigned size) { MilkymistHpdmcState *s = opaque; @@ -74,7 +74,7 @@ static uint64_t hpdmc_read(void *opaque, target_phys_addr_t addr, return r; } -static void hpdmc_write(void *opaque, target_phys_addr_t addr, uint64_t value, +static void hpdmc_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { MilkymistHpdmcState *s = opaque; diff --git a/hw/milkymist-hw.h b/hw/milkymist-hw.h index 9f358a7d69..812ddd2bd1 100644 --- a/hw/milkymist-hw.h +++ b/hw/milkymist-hw.h @@ -3,8 +3,9 @@ #include "qdev.h" #include "qdev-addr.h" +#include "net/net.h" -static inline DeviceState *milkymist_uart_create(target_phys_addr_t base, +static inline DeviceState *milkymist_uart_create(hwaddr base, qemu_irq irq) { DeviceState *dev; @@ -17,7 +18,7 @@ static inline DeviceState *milkymist_uart_create(target_phys_addr_t base, return dev; } -static inline DeviceState *milkymist_hpdmc_create(target_phys_addr_t base) +static inline DeviceState *milkymist_hpdmc_create(hwaddr base) { DeviceState *dev; @@ -28,7 +29,7 @@ static inline DeviceState *milkymist_hpdmc_create(target_phys_addr_t base) return dev; } -static inline DeviceState *milkymist_memcard_create(target_phys_addr_t base) +static inline DeviceState *milkymist_memcard_create(hwaddr base) { DeviceState *dev; @@ -39,7 +40,7 @@ static inline DeviceState *milkymist_memcard_create(target_phys_addr_t base) return dev; } -static inline DeviceState *milkymist_vgafb_create(target_phys_addr_t base, +static inline DeviceState *milkymist_vgafb_create(hwaddr base, uint32_t fb_offset, uint32_t fb_mask) { DeviceState *dev; @@ -53,7 +54,7 @@ static inline DeviceState *milkymist_vgafb_create(target_phys_addr_t base, return dev; } -static inline DeviceState *milkymist_sysctl_create(target_phys_addr_t base, +static inline DeviceState *milkymist_sysctl_create(hwaddr base, qemu_irq gpio_irq, qemu_irq timer0_irq, qemu_irq timer1_irq, uint32_t freq_hz, uint32_t system_id, uint32_t capabilities, uint32_t gpio_strappings) @@ -74,7 +75,7 @@ static inline DeviceState *milkymist_sysctl_create(target_phys_addr_t base, return dev; } -static inline DeviceState *milkymist_pfpu_create(target_phys_addr_t base, +static inline DeviceState *milkymist_pfpu_create(hwaddr base, qemu_irq irq) { DeviceState *dev; @@ -97,7 +98,7 @@ static const int glx_fbconfig_attr[] = { }; #endif -static inline DeviceState *milkymist_tmu2_create(target_phys_addr_t base, +static inline DeviceState *milkymist_tmu2_create(hwaddr base, qemu_irq irq) { #ifdef CONFIG_OPENGL @@ -152,7 +153,7 @@ static inline DeviceState *milkymist_tmu2_create(target_phys_addr_t base, #endif } -static inline DeviceState *milkymist_ac97_create(target_phys_addr_t base, +static inline DeviceState *milkymist_ac97_create(hwaddr base, qemu_irq crrequest_irq, qemu_irq crreply_irq, qemu_irq dmar_irq, qemu_irq dmaw_irq) { @@ -169,7 +170,7 @@ static inline DeviceState *milkymist_ac97_create(target_phys_addr_t base, return dev; } -static inline DeviceState *milkymist_minimac_create(target_phys_addr_t base, +static inline DeviceState *milkymist_minimac_create(hwaddr base, qemu_irq rx_irq, qemu_irq tx_irq) { DeviceState *dev; @@ -185,8 +186,8 @@ static inline DeviceState *milkymist_minimac_create(target_phys_addr_t base, return dev; } -static inline DeviceState *milkymist_minimac2_create(target_phys_addr_t base, - target_phys_addr_t buffers_base, qemu_irq rx_irq, qemu_irq tx_irq) +static inline DeviceState *milkymist_minimac2_create(hwaddr base, + hwaddr buffers_base, qemu_irq rx_irq, qemu_irq tx_irq) { DeviceState *dev; @@ -202,7 +203,7 @@ static inline DeviceState *milkymist_minimac2_create(target_phys_addr_t base, return dev; } -static inline DeviceState *milkymist_softusb_create(target_phys_addr_t base, +static inline DeviceState *milkymist_softusb_create(hwaddr base, qemu_irq irq, uint32_t pmem_base, uint32_t pmem_size, uint32_t dmem_base, uint32_t dmem_size) { diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c index 3515c3cd9a..f80befc53a 100644 --- a/hw/milkymist-memcard.c +++ b/hw/milkymist-memcard.c @@ -23,10 +23,10 @@ #include "hw.h" #include "sysbus.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "trace.h" -#include "qemu-error.h" -#include "blockdev.h" +#include "qemu/error-report.h" +#include "sysemu/blockdev.h" #include "sd.h" enum { @@ -117,7 +117,7 @@ static void memcard_sd_command(MilkymistMemcardState *s) } } -static uint64_t memcard_read(void *opaque, target_phys_addr_t addr, +static uint64_t memcard_read(void *opaque, hwaddr addr, unsigned size) { MilkymistMemcardState *s = opaque; @@ -166,7 +166,7 @@ static uint64_t memcard_read(void *opaque, target_phys_addr_t addr, return r; } -static void memcard_write(void *opaque, target_phys_addr_t addr, uint64_t value, +static void memcard_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { MilkymistMemcardState *s = opaque; diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c index b483a02f21..4e92ac3dcb 100644 --- a/hw/milkymist-minimac2.c +++ b/hw/milkymist-minimac2.c @@ -25,8 +25,8 @@ #include "hw.h" #include "sysbus.h" #include "trace.h" -#include "net.h" -#include "qemu-error.h" +#include "net/net.h" +#include "qemu/error-report.h" #include "qdev-addr.h" #include <zlib.h> @@ -96,7 +96,7 @@ struct MilkymistMinimac2State { NICState *nic; NICConf conf; char *phy_model; - target_phys_addr_t buffers_base; + hwaddr buffers_base; MemoryRegion buffers; MemoryRegion regs_region; @@ -323,7 +323,7 @@ static ssize_t minimac2_rx(NetClientState *nc, const uint8_t *buf, size_t size) } static uint64_t -minimac2_read(void *opaque, target_phys_addr_t addr, unsigned size) +minimac2_read(void *opaque, hwaddr addr, unsigned size) { MilkymistMinimac2State *s = opaque; uint32_t r = 0; @@ -352,7 +352,7 @@ minimac2_read(void *opaque, target_phys_addr_t addr, unsigned size) } static void -minimac2_write(void *opaque, target_phys_addr_t addr, uint64_t value, +minimac2_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { MilkymistMinimac2State *s = opaque; diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c index 0f9ff4a13d..0521829202 100644 --- a/hw/milkymist-pfpu.c +++ b/hw/milkymist-pfpu.c @@ -25,8 +25,8 @@ #include "hw.h" #include "sysbus.h" #include "trace.h" -#include "qemu-log.h" -#include "qemu-error.h" +#include "qemu/log.h" +#include "qemu/error-report.h" #include <math.h> /* #define TRACE_EXEC */ @@ -131,7 +131,7 @@ struct MilkymistPFPUState { }; typedef struct MilkymistPFPUState MilkymistPFPUState; -static inline target_phys_addr_t +static inline hwaddr get_dma_address(uint32_t base, uint32_t x, uint32_t y) { return base + 8 * (128 * y + x); @@ -225,7 +225,7 @@ static int pfpu_decode_insn(MilkymistPFPUState *s) { uint32_t a = cpu_to_be32(s->gp_regs[reg_a]); uint32_t b = cpu_to_be32(s->gp_regs[reg_b]); - target_phys_addr_t dma_ptr = + hwaddr dma_ptr = get_dma_address(s->regs[R_MESHBASE], s->gp_regs[GPR_X], s->gp_regs[GPR_Y]); cpu_physical_memory_write(dma_ptr, (uint8_t *)&a, 4); @@ -380,7 +380,7 @@ static inline int get_microcode_address(MilkymistPFPUState *s, uint32_t addr) return (512 * s->regs[R_CODEPAGE]) + addr - MICROCODE_BEGIN; } -static uint64_t pfpu_read(void *opaque, target_phys_addr_t addr, +static uint64_t pfpu_read(void *opaque, hwaddr addr, unsigned size) { MilkymistPFPUState *s = opaque; @@ -420,7 +420,7 @@ static uint64_t pfpu_read(void *opaque, target_phys_addr_t addr, return r; } -static void pfpu_write(void *opaque, target_phys_addr_t addr, uint64_t value, +static void pfpu_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { MilkymistPFPUState *s = opaque; diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c index ecc2be9225..b7beb4bedb 100644 --- a/hw/milkymist-softusb.c +++ b/hw/milkymist-softusb.c @@ -24,9 +24,9 @@ #include "hw.h" #include "sysbus.h" #include "trace.h" -#include "console.h" +#include "ui/console.h" #include "hid.h" -#include "qemu-error.h" +#include "qemu/error-report.h" enum { R_CTRL = 0, @@ -71,7 +71,7 @@ struct MilkymistSoftUsbState { }; typedef struct MilkymistSoftUsbState MilkymistSoftUsbState; -static uint64_t softusb_read(void *opaque, target_phys_addr_t addr, +static uint64_t softusb_read(void *opaque, hwaddr addr, unsigned size) { MilkymistSoftUsbState *s = opaque; @@ -95,7 +95,7 @@ static uint64_t softusb_read(void *opaque, target_phys_addr_t addr, } static void -softusb_write(void *opaque, target_phys_addr_t addr, uint64_t value, +softusb_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { MilkymistSoftUsbState *s = opaque; diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c index 8878d2bd17..796e795f04 100644 --- a/hw/milkymist-sysctl.c +++ b/hw/milkymist-sysctl.c @@ -23,11 +23,11 @@ #include "hw.h" #include "sysbus.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "trace.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "ptimer.h" -#include "qemu-error.h" +#include "qemu/error-report.h" enum { CTRL_ENABLE = (1<<0), @@ -89,7 +89,7 @@ static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value) } } -static uint64_t sysctl_read(void *opaque, target_phys_addr_t addr, +static uint64_t sysctl_read(void *opaque, hwaddr addr, unsigned size) { MilkymistSysctlState *s = opaque; @@ -134,7 +134,7 @@ static uint64_t sysctl_read(void *opaque, target_phys_addr_t addr, return r; } -static void sysctl_write(void *opaque, target_phys_addr_t addr, uint64_t value, +static void sysctl_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { MilkymistSysctlState *s = opaque; diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c index 210ceede2a..a11772aebe 100644 --- a/hw/milkymist-tmu2.c +++ b/hw/milkymist-tmu2.c @@ -27,7 +27,7 @@ #include "hw.h" #include "sysbus.h" #include "trace.h" -#include "qemu-error.h" +#include "qemu/error-report.h" #include <X11/Xlib.h> #include <GL/gl.h> @@ -182,9 +182,9 @@ static void tmu2_start(MilkymistTMU2State *s) GLXPbuffer pbuffer; GLuint texture; void *fb; - target_phys_addr_t fb_len; + hwaddr fb_len; void *mesh; - target_phys_addr_t mesh_len; + hwaddr mesh_len; float m; trace_milkymist_tmu2_start(); @@ -310,7 +310,7 @@ static void tmu2_start(MilkymistTMU2State *s) qemu_irq_pulse(s->irq); } -static uint64_t tmu2_read(void *opaque, target_phys_addr_t addr, +static uint64_t tmu2_read(void *opaque, hwaddr addr, unsigned size) { MilkymistTMU2State *s = opaque; @@ -372,7 +372,7 @@ static void tmu2_check_registers(MilkymistTMU2State *s) } } -static void tmu2_write(void *opaque, target_phys_addr_t addr, uint64_t value, +static void tmu2_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { MilkymistTMU2State *s = opaque; diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c index 291fe3c57b..19e9dbdc75 100644 --- a/hw/milkymist-uart.c +++ b/hw/milkymist-uart.c @@ -24,8 +24,8 @@ #include "hw.h" #include "sysbus.h" #include "trace.h" -#include "qemu-char.h" -#include "qemu-error.h" +#include "char/char.h" +#include "qemu/error-report.h" enum { R_RXTX = 0, @@ -78,7 +78,7 @@ static void uart_update_irq(MilkymistUartState *s) } } -static uint64_t uart_read(void *opaque, target_phys_addr_t addr, +static uint64_t uart_read(void *opaque, hwaddr addr, unsigned size) { MilkymistUartState *s = opaque; @@ -107,7 +107,7 @@ static uint64_t uart_read(void *opaque, target_phys_addr_t addr, return r; } -static void uart_write(void *opaque, target_phys_addr_t addr, uint64_t value, +static void uart_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { MilkymistUartState *s = opaque; diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c index cd4365d64b..561285154f 100644 --- a/hw/milkymist-vgafb.c +++ b/hw/milkymist-vgafb.c @@ -25,10 +25,10 @@ #include "hw.h" #include "sysbus.h" #include "trace.h" -#include "console.h" +#include "ui/console.h" #include "framebuffer.h" -#include "pixel_ops.h" -#include "qemu-error.h" +#include "ui/pixel_ops.h" +#include "qemu/error-report.h" #define BITS 8 #include "milkymist-vgafb_template.h" @@ -134,7 +134,7 @@ static void vgafb_update_display(void *opaque) &first, &last); if (first >= 0) { - dpy_update(s->ds, 0, first, s->regs[R_HRES], last - first + 1); + dpy_gfx_update(s->ds, 0, first, s->regs[R_HRES], last - first + 1); } s->invalidate = 0; } @@ -155,7 +155,7 @@ static void vgafb_resize(MilkymistVgafbState *s) s->invalidate = 1; } -static uint64_t vgafb_read(void *opaque, target_phys_addr_t addr, +static uint64_t vgafb_read(void *opaque, hwaddr addr, unsigned size) { MilkymistVgafbState *s = opaque; @@ -193,7 +193,7 @@ static uint64_t vgafb_read(void *opaque, target_phys_addr_t addr, return r; } -static void vgafb_write(void *opaque, target_phys_addr_t addr, uint64_t value, +static void vgafb_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { MilkymistVgafbState *s = opaque; diff --git a/hw/milkymist.c b/hw/milkymist.c index 2e7235b4b3..0c23b672f3 100644 --- a/hw/milkymist.c +++ b/hw/milkymist.c @@ -19,17 +19,16 @@ #include "sysbus.h" #include "hw.h" -#include "net.h" #include "flash.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "devices.h" #include "boards.h" #include "loader.h" #include "elf.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "milkymist-hw.h" #include "lm32.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #define BIOS_FILENAME "mmone-bios.bin" #define BIOS_OFFSET 0x00860000 @@ -38,11 +37,11 @@ typedef struct { LM32CPU *cpu; - target_phys_addr_t bootstrap_pc; - target_phys_addr_t flash_base; - target_phys_addr_t initrd_base; + hwaddr bootstrap_pc; + hwaddr flash_base; + hwaddr initrd_base; size_t initrd_size; - target_phys_addr_t cmdline_base; + hwaddr cmdline_base; } ResetInfo; static void cpu_irq_handler(void *opaque, int irq, int level) @@ -73,12 +72,12 @@ static void main_cpu_reset(void *opaque) } static void -milkymist_init(ram_addr_t ram_size_not_used, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +milkymist_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; LM32CPU *cpu; CPULM32State *env; int kernel_size; @@ -91,14 +90,14 @@ milkymist_init(ram_addr_t ram_size_not_used, ResetInfo *reset_info; /* memory map */ - target_phys_addr_t flash_base = 0x00000000; + hwaddr flash_base = 0x00000000; size_t flash_sector_size = 128 * 1024; size_t flash_size = 32 * 1024 * 1024; - target_phys_addr_t sdram_base = 0x40000000; + hwaddr sdram_base = 0x40000000; size_t sdram_size = 128 * 1024 * 1024; - target_phys_addr_t initrd_base = sdram_base + 0x1002000; - target_phys_addr_t cmdline_base = sdram_base + 0x1000000; + hwaddr initrd_base = sdram_base + 0x1002000; + hwaddr cmdline_base = sdram_base + 0x1000000; size_t initrd_max = sdram_size - 0x1002000; reset_info = g_malloc0(sizeof(ResetInfo)); @@ -2,7 +2,7 @@ #define HW_MIPS_H /* Definitions for mips board emulation. */ -#include "memory.h" +#include "exec/memory.h" /* gt64xxx.c */ PCIBus *gt64120_register(qemu_irq *pic); @@ -12,7 +12,7 @@ PCIBus *bonito_init(qemu_irq *pic); /* rc4030.c */ typedef struct rc4030DMAState *rc4030_dma; -void rc4030_dma_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write); +void rc4030_dma_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write); void rc4030_dma_read(void *dma, uint8_t *buf, int len); void rc4030_dma_write(void *dma, uint8_t *buf, int len); @@ -21,9 +21,9 @@ void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus, MemoryRegion *sysmem); /* dp8393x.c */ -void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, +void dp83932_init(NICInfo *nd, hwaddr base, int it_shift, MemoryRegion *address_space, qemu_irq irq, void* mem_opaque, - void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write)); + void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write)); #endif diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index 38e4b86150..4d8ee8c09c 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -20,19 +20,20 @@ #include "hw.h" #include "pc.h" +#include "serial.h" #include "fdc.h" -#include "net.h" +#include "net/net.h" #include "boards.h" #include "smbus.h" -#include "block.h" +#include "block/block.h" #include "flash.h" #include "mips.h" #include "mips_cpudevs.h" -#include "pci.h" -#include "qemu-char.h" -#include "sysemu.h" +#include "pci/pci.h" +#include "char/char.h" +#include "sysemu/sysemu.h" #include "audio/audio.h" -#include "qemu-log.h" +#include "qemu/log.h" #include "loader.h" #include "mips-bios.h" #include "ide.h" @@ -40,8 +41,8 @@ #include "vt82c686.h" #include "mc146818rtc.h" #include "i8254.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" #define DEBUG_FULONG2E_INIT @@ -256,10 +257,13 @@ static void cpu_request_exit(void *opaque, int irq, int level) } } -static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void mips_fulong2e_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; char *filename; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); @@ -392,7 +396,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, network_init(); } -QEMUMachine mips_fulong2e_machine = { +static QEMUMachine mips_fulong2e_machine = { .name = "fulong2e", .desc = "Fulong 2e mini pc", .init = mips_fulong2e_init, diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index db927f14d0..63df2a734b 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -26,21 +26,22 @@ #include "mips.h" #include "mips_cpudevs.h" #include "pc.h" +#include "serial.h" #include "isa.h" #include "fdc.h" -#include "sysemu.h" -#include "arch_init.h" +#include "sysemu/sysemu.h" +#include "sysemu/arch_init.h" #include "boards.h" -#include "net.h" +#include "net/net.h" #include "esp.h" #include "mips-bios.h" #include "loader.h" #include "mc146818rtc.h" #include "i8254.h" #include "pcspk.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "sysbus.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" enum jazz_model_e { @@ -55,12 +56,12 @@ static void main_cpu_reset(void *opaque) cpu_reset(CPU(cpu)); } -static uint64_t rtc_read(void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t rtc_read(void *opaque, hwaddr addr, unsigned size) { return cpu_inw(0x71); } -static void rtc_write(void *opaque, target_phys_addr_t addr, +static void rtc_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { cpu_outw(0x71, val & 0xff); @@ -72,7 +73,7 @@ static const MemoryRegionOps rtc_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint64_t dma_dummy_read(void *opaque, target_phys_addr_t addr, +static uint64_t dma_dummy_read(void *opaque, hwaddr addr, unsigned size) { /* Nothing to do. That is only to ensure that @@ -80,7 +81,7 @@ static uint64_t dma_dummy_read(void *opaque, target_phys_addr_t addr, return 0xff; } -static void dma_dummy_write(void *opaque, target_phys_addr_t addr, +static void dma_dummy_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { /* Nothing to do. That is only to ensure that @@ -302,21 +303,19 @@ static void mips_jazz_init(MemoryRegion *address_space, } static -void mips_magnum_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +void mips_magnum_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; mips_jazz_init(get_system_memory(), get_system_io(), ram_size, cpu_model, JAZZ_MAGNUM); } static -void mips_pica61_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +void mips_pica61_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; mips_jazz_init(get_system_memory(), get_system_io(), ram_size, cpu_model, JAZZ_PICA61); } @@ -325,14 +324,14 @@ static QEMUMachine mips_magnum_machine = { .name = "magnum", .desc = "MIPS Magnum", .init = mips_magnum_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, }; static QEMUMachine mips_pica61_machine = { .name = "pica61", .desc = "Acer Pica 61", .init = mips_pica61_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, }; static void mips_jazz_machine_init(void) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 351c88ebca..635143d20c 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -24,29 +24,29 @@ #include "hw.h" #include "pc.h" +#include "serial.h" #include "fdc.h" -#include "net.h" +#include "net/net.h" #include "boards.h" #include "smbus.h" -#include "block.h" +#include "block/block.h" #include "flash.h" #include "mips.h" #include "mips_cpudevs.h" -#include "pci.h" -#include "vmware_vga.h" -#include "qemu-char.h" -#include "sysemu.h" -#include "arch_init.h" +#include "pci/pci.h" +#include "char/char.h" +#include "sysemu/sysemu.h" +#include "sysemu/arch_init.h" #include "boards.h" -#include "qemu-log.h" +#include "qemu/log.h" #include "mips-bios.h" #include "ide.h" #include "loader.h" #include "elf.h" #include "mc146818rtc.h" #include "i8254.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" #include "sysbus.h" /* SysBusDevice */ //#define DEBUG_BOARD_INIT @@ -231,7 +231,7 @@ static void eeprom24c0x_write(int scl, int sda) eeprom.sda = sda; } -static uint64_t malta_fpga_read(void *opaque, target_phys_addr_t addr, +static uint64_t malta_fpga_read(void *opaque, hwaddr addr, unsigned size) { MaltaFPGAState *s = opaque; @@ -319,7 +319,7 @@ static uint64_t malta_fpga_read(void *opaque, target_phys_addr_t addr, return val; } -static void malta_fpga_write(void *opaque, target_phys_addr_t addr, +static void malta_fpga_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { MaltaFPGAState *s = opaque; @@ -441,7 +441,7 @@ static void malta_fpga_led_init(CharDriverState *chr) } static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space, - target_phys_addr_t base, qemu_irq uart_irq, CharDriverState *uart_chr) + hwaddr base, qemu_irq uart_irq, CharDriverState *uart_chr) { MaltaFPGAState *s; @@ -776,11 +776,13 @@ static void cpu_request_exit(void *opaque, int irq, int level) } static -void mips_malta_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +void mips_malta_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; char *filename; pflash_t *fl; MemoryRegion *system_memory = get_system_memory(); @@ -859,7 +861,8 @@ void mips_malta_init (ram_addr_t ram_size, be = 0; #endif /* FPGA */ - malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[2], serial_hds[2]); + /* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */ + malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[4], serial_hds[2]); /* Load firmware in flash / BIOS. */ dinfo = drive_get(IF_PFLASH, 0, fl_idx); @@ -986,13 +989,7 @@ void mips_malta_init (ram_addr_t ram_size, network_init(); /* Optional PCI video card */ - if (cirrus_vga_enabled) { - pci_cirrus_vga_init(pci_bus); - } else if (vmsvga_enabled) { - pci_vmsvga_init(pci_bus); - } else if (std_vga_enabled) { - pci_vga_init(pci_bus); - } + pci_vga_init(pci_bus); } static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev) diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index 830f635597..67066c0ca1 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -27,16 +27,16 @@ #include "hw.h" #include "mips.h" #include "mips_cpudevs.h" -#include "pc.h" +#include "serial.h" #include "isa.h" -#include "net.h" -#include "sysemu.h" +#include "net/net.h" +#include "sysemu/sysemu.h" #include "boards.h" #include "mips-bios.h" #include "loader.h" #include "elf.h" #include "sysbus.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" static struct _loaderparams { int ram_size; @@ -131,11 +131,13 @@ static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd) } static void -mips_mipssim_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +mips_mipssim_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; char *filename; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); @@ -215,7 +217,8 @@ mips_mipssim_init (ram_addr_t ram_size, /* A single 16450 sits at offset 0x3f8. It is attached to MIPS CPU INT2, which is interrupt 4. */ if (serial_hds[0]) - serial_init(0x3f8, env->irq[4], 115200, serial_hds[0]); + serial_init(0x3f8, env->irq[4], 115200, serial_hds[0], + get_system_io()); if (nd_table[0].used) /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */ diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 967a76e533..59c43e591c 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -11,20 +11,21 @@ #include "mips.h" #include "mips_cpudevs.h" #include "pc.h" +#include "serial.h" #include "isa.h" -#include "net.h" -#include "sysemu.h" +#include "net/net.h" +#include "sysemu/sysemu.h" #include "boards.h" #include "flash.h" -#include "qemu-log.h" +#include "qemu/log.h" #include "mips-bios.h" #include "ide.h" #include "loader.h" #include "elf.h" #include "mc146818rtc.h" #include "i8254.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" #define MAX_IDE_BUS 2 @@ -43,7 +44,7 @@ static struct _loaderparams { const char *initrd_filename; } loaderparams; -static void mips_qemu_write (void *opaque, target_phys_addr_t addr, +static void mips_qemu_write (void *opaque, hwaddr addr, uint64_t val, unsigned size) { if ((addr & 0xffff) == 0 && val == 42) @@ -52,7 +53,7 @@ static void mips_qemu_write (void *opaque, target_phys_addr_t addr, qemu_system_shutdown_request (); } -static uint64_t mips_qemu_read (void *opaque, target_phys_addr_t addr, +static uint64_t mips_qemu_read (void *opaque, hwaddr addr, unsigned size) { return 0; @@ -151,11 +152,13 @@ static void main_cpu_reset(void *opaque) static const int sector_len = 32 * 1024; static -void mips_r4k_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +void mips_r4k_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; char *filename; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/mips_timer.c b/hw/mips_timer.c index 7aa9004a0e..83c400c158 100644 --- a/hw/mips_timer.c +++ b/hw/mips_timer.c @@ -22,7 +22,7 @@ #include "hw.h" #include "mips_cpudevs.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #define TIMER_FREQ 100 * 1000 * 1000 diff --git a/hw/mipsnet.c b/hw/mipsnet.c index 28063b1106..bb752d3950 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -1,5 +1,5 @@ #include "hw.h" -#include "net.h" +#include "net/net.h" #include "trace.h" #include "sysbus.h" @@ -96,7 +96,7 @@ static ssize_t mipsnet_receive(NetClientState *nc, const uint8_t *buf, size_t si return size; } -static uint64_t mipsnet_ioport_read(void *opaque, target_phys_addr_t addr, +static uint64_t mipsnet_ioport_read(void *opaque, hwaddr addr, unsigned int size) { MIPSnetState *s = opaque; @@ -142,7 +142,7 @@ static uint64_t mipsnet_ioport_read(void *opaque, target_phys_addr_t addr, return ret; } -static void mipsnet_ioport_write(void *opaque, target_phys_addr_t addr, +static void mipsnet_ioport_write(void *opaque, hwaddr addr, uint64_t val, unsigned int size) { MIPSnetState *s = opaque; diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c index 13b0dddc1e..84522e9722 100644 --- a/hw/mpc8544_guts.c +++ b/hw/mpc8544_guts.c @@ -18,7 +18,7 @@ */ #include "hw.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "sysbus.h" #define MPC8544_GUTS_MMIO_SIZE 0x1000 @@ -58,7 +58,7 @@ struct GutsState { typedef struct GutsState GutsState; -static uint64_t mpc8544_guts_read(void *opaque, target_phys_addr_t addr, +static uint64_t mpc8544_guts_read(void *opaque, hwaddr addr, unsigned size) { uint32_t value = 0; @@ -80,7 +80,7 @@ static uint64_t mpc8544_guts_read(void *opaque, target_phys_addr_t addr, return value; } -static void mpc8544_guts_write(void *opaque, target_phys_addr_t addr, +static void mpc8544_guts_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { addr &= MPC8544_GUTS_MMIO_SIZE - 1; diff --git a/hw/msmouse.c b/hw/msmouse.c index 9c492a4637..ef47aed4e9 100644 --- a/hw/msmouse.c +++ b/hw/msmouse.c @@ -22,9 +22,9 @@ * THE SOFTWARE. */ #include <stdlib.h> -#include "../qemu-common.h" -#include "../qemu-char.h" -#include "../console.h" +#include "qemu-common.h" +#include "char/char.h" +#include "ui/console.h" #include "msmouse.h" #define MSMOUSE_LO6(n) ((n) & 0x3f) diff --git a/hw/msmouse.h b/hw/msmouse.h index 456cb21424..8cff3a71c3 100644 --- a/hw/msmouse.h +++ b/hw/msmouse.h @@ -1,2 +1,7 @@ +#ifndef HW_MSMOUSE_H +#define HW_MSMOUSE_H 1 + /* msmouse.c */ CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts); + +#endif diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c index 024192d135..fb4b739c7c 100644 --- a/hw/mst_fpga.c +++ b/hw/mst_fpga.c @@ -91,7 +91,7 @@ mst_fpga_set_irq(void *opaque, int irq, int level) static uint64_t -mst_fpga_readb(void *opaque, target_phys_addr_t addr, unsigned size) +mst_fpga_readb(void *opaque, hwaddr addr, unsigned size) { mst_irq_state *s = (mst_irq_state *) opaque; @@ -128,7 +128,7 @@ mst_fpga_readb(void *opaque, target_phys_addr_t addr, unsigned size) } static void -mst_fpga_writeb(void *opaque, target_phys_addr_t addr, uint64_t value, +mst_fpga_writeb(void *opaque, hwaddr addr, uint64_t value, unsigned size) { mst_irq_state *s = (mst_irq_state *) opaque; diff --git a/hw/multiboot.c b/hw/multiboot.c index b1e04c5718..c4ec2e34a7 100644 --- a/hw/multiboot.c +++ b/hw/multiboot.c @@ -27,7 +27,7 @@ #include "multiboot.h" #include "loader.h" #include "elf.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" /* Show multiboot debug output */ //#define DEBUG_MULTIBOOT @@ -80,15 +80,15 @@ typedef struct { /* buffer holding kernel, cmdlines and mb_infos */ void *mb_buf; /* address in target */ - target_phys_addr_t mb_buf_phys; + hwaddr mb_buf_phys; /* size of mb_buf in bytes */ unsigned mb_buf_size; /* offset of mb-info's in bytes */ - target_phys_addr_t offset_mbinfo; + hwaddr offset_mbinfo; /* offset in buffer for cmdlines in bytes */ - target_phys_addr_t offset_cmdlines; + hwaddr offset_cmdlines; /* offset of modules in bytes */ - target_phys_addr_t offset_mods; + hwaddr offset_mods; /* available slots for mb modules infos */ int mb_mods_avail; /* currently used slots of mb modules */ @@ -97,7 +97,7 @@ typedef struct { static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline) { - target_phys_addr_t p = s->offset_cmdlines; + hwaddr p = s->offset_cmdlines; char *b = (char *)s->mb_buf + p; get_opt_value(b, strlen(cmdline) + 1, cmdline); @@ -106,8 +106,8 @@ static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline) } static void mb_add_mod(MultibootState *s, - target_phys_addr_t start, target_phys_addr_t end, - target_phys_addr_t cmdline_phys) + hwaddr start, hwaddr end, + hwaddr cmdline_phys) { char *p; assert(s->mb_mods_count < s->mb_mods_avail); @@ -276,7 +276,7 @@ int load_multiboot(void *fw_cfg, *next_initrd = '\0'; /* if a space comes after the module filename, treat everything after that as parameters */ - target_phys_addr_t c = mb_add_cmdline(&mbs, initrd_filename); + hwaddr c = mb_add_cmdline(&mbs, initrd_filename); if ((next_space = strchr(initrd_filename, ' '))) *next_space = '\0'; mb_debug("multiboot loading module: %s\n", initrd_filename); diff --git a/hw/musicpal.c b/hw/musicpal.c index ad725b5599..77a585eee6 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -12,18 +12,19 @@ #include "sysbus.h" #include "arm-misc.h" #include "devices.h" -#include "net.h" -#include "sysemu.h" +#include "net/net.h" +#include "sysemu/sysemu.h" #include "boards.h" -#include "pc.h" -#include "qemu-timer.h" +#include "serial.h" +#include "qemu/timer.h" #include "ptimer.h" -#include "block.h" +#include "block/block.h" #include "flash.h" -#include "console.h" +#include "ui/console.h" #include "i2c.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" +#include "ui/pixel_ops.h" #define MP_MISC_BASE 0x80002000 #define MP_MISC_SIZE 0x00001000 @@ -266,7 +267,7 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index) } while (desc_addr != s->tx_queue[queue_index]); } -static uint64_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset, +static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset, unsigned size) { mv88w8618_eth_state *s = opaque; @@ -308,7 +309,7 @@ static uint64_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset, } } -static void mv88w8618_eth_write(void *opaque, target_phys_addr_t offset, +static void mv88w8618_eth_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { mv88w8618_eth_state *s = opaque; @@ -492,8 +493,6 @@ SET_LCD_PIXEL(8, uint8_t) SET_LCD_PIXEL(16, uint16_t) SET_LCD_PIXEL(32, uint32_t) -#include "pixel_ops.h" - static void lcd_refresh(void *opaque) { musicpal_lcd_state *s = opaque; @@ -526,7 +525,7 @@ static void lcd_refresh(void *opaque) ds_get_bits_per_pixel(s->ds)); } - dpy_update(s->ds, 0, 0, 128*3, 64*3); + dpy_gfx_update(s->ds, 0, 0, 128*3, 64*3); } static void lcd_invalidate(void *opaque) @@ -540,7 +539,7 @@ static void musicpal_lcd_gpio_brigthness_in(void *opaque, int irq, int level) s->brightness |= level << irq; } -static uint64_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset, +static uint64_t musicpal_lcd_read(void *opaque, hwaddr offset, unsigned size) { musicpal_lcd_state *s = opaque; @@ -554,7 +553,7 @@ static uint64_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset, } } -static void musicpal_lcd_write(void *opaque, target_phys_addr_t offset, +static void musicpal_lcd_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { musicpal_lcd_state *s = opaque; @@ -682,7 +681,7 @@ static void mv88w8618_pic_set_irq(void *opaque, int irq, int level) mv88w8618_pic_update(s); } -static uint64_t mv88w8618_pic_read(void *opaque, target_phys_addr_t offset, +static uint64_t mv88w8618_pic_read(void *opaque, hwaddr offset, unsigned size) { mv88w8618_pic_state *s = opaque; @@ -696,7 +695,7 @@ static uint64_t mv88w8618_pic_read(void *opaque, target_phys_addr_t offset, } } -static void mv88w8618_pic_write(void *opaque, target_phys_addr_t offset, +static void mv88w8618_pic_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { mv88w8618_pic_state *s = opaque; @@ -815,7 +814,7 @@ static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s, s->ptimer = ptimer_init(bh); } -static uint64_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset, +static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset, unsigned size) { mv88w8618_pit_state *s = opaque; @@ -831,7 +830,7 @@ static uint64_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset, } } -static void mv88w8618_pit_write(void *opaque, target_phys_addr_t offset, +static void mv88w8618_pit_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { mv88w8618_pit_state *s = opaque; @@ -957,7 +956,7 @@ typedef struct mv88w8618_flashcfg_state { } mv88w8618_flashcfg_state; static uint64_t mv88w8618_flashcfg_read(void *opaque, - target_phys_addr_t offset, + hwaddr offset, unsigned size) { mv88w8618_flashcfg_state *s = opaque; @@ -971,7 +970,7 @@ static uint64_t mv88w8618_flashcfg_read(void *opaque, } } -static void mv88w8618_flashcfg_write(void *opaque, target_phys_addr_t offset, +static void mv88w8618_flashcfg_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { mv88w8618_flashcfg_state *s = opaque; @@ -1032,7 +1031,7 @@ static TypeInfo mv88w8618_flashcfg_info = { #define MP_BOARD_REVISION 0x31 -static uint64_t musicpal_misc_read(void *opaque, target_phys_addr_t offset, +static uint64_t musicpal_misc_read(void *opaque, hwaddr offset, unsigned size) { switch (offset) { @@ -1044,7 +1043,7 @@ static uint64_t musicpal_misc_read(void *opaque, target_phys_addr_t offset, } } -static void musicpal_misc_write(void *opaque, target_phys_addr_t offset, +static void musicpal_misc_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { } @@ -1068,7 +1067,7 @@ static void musicpal_misc_init(SysBusDevice *dev) #define MP_WLAN_MAGIC1 0x11c #define MP_WLAN_MAGIC2 0x124 -static uint64_t mv88w8618_wlan_read(void *opaque, target_phys_addr_t offset, +static uint64_t mv88w8618_wlan_read(void *opaque, hwaddr offset, unsigned size) { switch (offset) { @@ -1084,7 +1083,7 @@ static uint64_t mv88w8618_wlan_read(void *opaque, target_phys_addr_t offset, } } -static void mv88w8618_wlan_write(void *opaque, target_phys_addr_t offset, +static void mv88w8618_wlan_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { } @@ -1202,7 +1201,7 @@ static void musicpal_gpio_pin_event(void *opaque, int pin, int level) } } -static uint64_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset, +static uint64_t musicpal_gpio_read(void *opaque, hwaddr offset, unsigned size) { musicpal_gpio_state *s = opaque; @@ -1241,7 +1240,7 @@ static uint64_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset, } } -static void musicpal_gpio_write(void *opaque, target_phys_addr_t offset, +static void musicpal_gpio_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { musicpal_gpio_state *s = opaque; @@ -1508,11 +1507,12 @@ static struct arm_boot_info musicpal_binfo = { .board_id = 0x20e, }; -static void musicpal_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void musicpal_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; ARMCPU *cpu; qemu_irq *cpu_pic; qemu_irq pic[32]; @@ -1583,7 +1583,7 @@ static void musicpal_init(ram_addr_t ram_size, * image is smaller than 32 MB. */ #ifdef TARGET_WORDS_BIGENDIAN - pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL, + pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, "musicpal.flash", flash_size, dinfo->bdrv, 0x10000, (flash_size + 0xffff) >> 16, @@ -1591,7 +1591,7 @@ static void musicpal_init(ram_addr_t ram_size, 2, 0x00BF, 0x236D, 0x0000, 0x0000, 0x5555, 0x2AAA, 1); #else - pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL, + pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, "musicpal.flash", flash_size, dinfo->bdrv, 0x10000, (flash_size + 0xffff) >> 16, @@ -20,9 +20,9 @@ # include "hw.h" # include "flash.h" -# include "blockdev.h" +# include "sysemu/blockdev.h" # include "sysbus.h" -#include "qemu-error.h" +#include "qemu/error-report.h" # define NAND_CMD_READ0 0x00 # define NAND_CMD_READ1 0x01 @@ -654,7 +654,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s) sector = SECTOR(s->addr); off = (s->addr & PAGE_MASK) + s->offset; soff = SECTOR_OFFSET(s->addr); - if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) { + if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, sector); return; } @@ -666,21 +666,23 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s) MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE)); } - if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) + if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, sector); + } } else { off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset; sector = off >> 9; soff = off & 0x1ff; - if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) { + if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, sector); return; } mem_and(iobuf + soff, s->io, s->iolen); - if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) + if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, sector); + } } s->offset = 0; } @@ -704,31 +706,37 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s) i = SECTOR(addr); page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift)); for (; i < page; i ++) - if (bdrv_write(s->bdrv, i, iobuf, 1) == -1) + if (bdrv_write(s->bdrv, i, iobuf, 1) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, i); + } } else { addr = PAGE_START(addr); page = addr >> 9; - if (bdrv_read(s->bdrv, page, iobuf, 1) == -1) + if (bdrv_read(s->bdrv, page, iobuf, 1) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, page); + } memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1); - if (bdrv_write(s->bdrv, page, iobuf, 1) == -1) + if (bdrv_write(s->bdrv, page, iobuf, 1) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, page); + } memset(iobuf, 0xff, 0x200); i = (addr & ~0x1ff) + 0x200; for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200; i < addr; i += 0x200) - if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1) + if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, i >> 9); + } page = i >> 9; - if (bdrv_read(s->bdrv, page, iobuf, 1) == -1) + if (bdrv_read(s->bdrv, page, iobuf, 1) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, page); + } memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1); - if (bdrv_write(s->bdrv, page, iobuf, 1) == -1) + if (bdrv_write(s->bdrv, page, iobuf, 1) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, page); + } } } @@ -740,18 +748,20 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s, if (s->bdrv) { if (s->mem_oob) { - if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) == -1) + if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, SECTOR(addr)); + } memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE, s->storage + (PAGE(s->addr) << OOB_SHIFT), OOB_SIZE); s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset; } else { if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9, - s->io, (PAGE_SECTORS + 2)) == -1) + s->io, (PAGE_SECTORS + 2)) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, PAGE_START(addr) >> 9); + } s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset; } } else { diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c index 69982a9abb..c2c00c215f 100644 --- a/hw/ne2000-isa.c +++ b/hw/ne2000-isa.c @@ -25,9 +25,9 @@ #include "pc.h" #include "isa.h" #include "qdev.h" -#include "net.h" +#include "net/net.h" #include "ne2000.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" typedef struct ISANE2000State { ISADevice dev; diff --git a/hw/ne2000.c b/hw/ne2000.c index 15605c478f..00efa74a0f 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -22,11 +22,11 @@ * THE SOFTWARE. */ #include "hw.h" -#include "pci.h" -#include "net.h" +#include "pci/pci.h" +#include "net/net.h" #include "ne2000.h" #include "loader.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" /* debug NE2000 card */ //#define DEBUG_NE2000 @@ -652,7 +652,7 @@ static const VMStateDescription vmstate_pci_ne2000 = { } }; -static uint64_t ne2000_read(void *opaque, target_phys_addr_t addr, +static uint64_t ne2000_read(void *opaque, hwaddr addr, unsigned size) { NE2000State *s = opaque; @@ -671,7 +671,7 @@ static uint64_t ne2000_read(void *opaque, target_phys_addr_t addr, return ((uint64_t)1 << (size * 8)) - 1; } -static void ne2000_write(void *opaque, target_phys_addr_t addr, +static void ne2000_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { NE2000State *s = opaque; diff --git a/hw/ne2000.h b/hw/ne2000.h index 1e7ab073e3..b31ae030f9 100644 --- a/hw/ne2000.h +++ b/hw/ne2000.h @@ -1,3 +1,6 @@ +#ifndef HW_NE2000_H +#define HW_NE2000_H 1 + #define NE2000_PMEM_SIZE (32*1024) #define NE2000_PMEM_START (16*1024) #define NE2000_PMEM_END (NE2000_PMEM_SIZE+NE2000_PMEM_START) @@ -33,3 +36,5 @@ extern const VMStateDescription vmstate_ne2000; void ne2000_reset(NE2000State *s); int ne2000_can_receive(NetClientState *nc); ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_); + +#endif diff --git a/hw/nseries.c b/hw/nseries.c index 4df2670327..d96b750ccd 100644 --- a/hw/nseries.c +++ b/hw/nseries.c @@ -19,11 +19,11 @@ */ #include "qemu-common.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "omap.h" #include "arm-misc.h" #include "irq.h" -#include "console.h" +#include "ui/console.h" #include "boards.h" #include "i2c.h" #include "devices.h" @@ -31,9 +31,9 @@ #include "hw.h" #include "bt.h" #include "loader.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "sysbus.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" /* Nokia N8x0 support */ struct n800_s { @@ -189,6 +189,17 @@ static void n8x0_nand_setup(struct n800_s *s) /* XXX: in theory should also update the OOB for both pages */ } +static qemu_irq n8x0_system_powerdown; + +static void n8x0_powerdown_req(Notifier *n, void *opaque) +{ + qemu_irq_raise(n8x0_system_powerdown); +} + +static Notifier n8x0_system_powerdown_notifier = { + .notify = n8x0_powerdown_req +}; + static void n8x0_i2c_setup(struct n800_s *s) { DeviceState *dev; @@ -201,7 +212,8 @@ static void n8x0_i2c_setup(struct n800_s *s) qdev_get_gpio_in(s->mpu->ih[0], OMAP_INT_24XX_SYS_NIRQ)); - qemu_system_powerdown = qdev_get_gpio_in(dev, 3); + n8x0_system_powerdown = qdev_get_gpio_in(dev, 3); + qemu_register_powerdown_notifier(&n8x0_system_powerdown_notifier); /* Attach a TMP105 PM chip (A0 wired to ground) */ dev = i2c_create_slave(i2c, "tmp105", N8X0_TMP105_ADDR); @@ -1272,17 +1284,15 @@ static int n810_atag_setup(const struct arm_boot_info *info, void *p) return n8x0_atag_setup(p, 810); } -static void n8x0_init(ram_addr_t ram_size, const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, const char *initrd_filename, - const char *cpu_model, struct arm_boot_info *binfo, int model) +static void n8x0_init(QEMUMachineInitArgs *args, + struct arm_boot_info *binfo, int model) { MemoryRegion *sysmem = get_system_memory(); struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s)); int sdram_size = binfo->ram_size; DisplayState *ds; - s->mpu = omap2420_mpu_init(sysmem, sdram_size, cpu_model); + s->mpu = omap2420_mpu_init(sysmem, sdram_size, args->cpu_model); /* Setup peripherals * @@ -1322,20 +1332,22 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device, n8x0_dss_setup(s); n8x0_cbus_setup(s); n8x0_uart_setup(s); - if (usb_enabled) + if (usb_enabled(false)) { n8x0_usb_setup(s); + } - if (kernel_filename) { + if (args->kernel_filename) { /* Or at the linux loader. */ - binfo->kernel_filename = kernel_filename; - binfo->kernel_cmdline = kernel_cmdline; - binfo->initrd_filename = initrd_filename; + binfo->kernel_filename = args->kernel_filename; + binfo->kernel_cmdline = args->kernel_cmdline; + binfo->initrd_filename = args->initrd_filename; arm_load_kernel(s->mpu->cpu, binfo); qemu_register_reset(n8x0_boot_init, s); } - if (option_rom[0].name && (boot_device[0] == 'n' || !kernel_filename)) { + if (option_rom[0].name && + (args->boot_device[0] == 'n' || !args->kernel_filename)) { int rom_size; uint8_t nolo_tags[0x10000]; /* No, wait, better start at the ROM. */ @@ -1363,7 +1375,7 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device, size until the guest activates the display. */ ds = get_displaystate(); ds->surface = qemu_resize_displaysurface(ds, 800, 480); - dpy_resize(ds); + dpy_gfx_resize(ds); } static struct arm_boot_info n800_binfo = { @@ -1385,24 +1397,14 @@ static struct arm_boot_info n810_binfo = { .atag_board = n810_atag_setup, }; -static void n800_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void n800_init(QEMUMachineInitArgs *args) { - return n8x0_init(ram_size, boot_device, - kernel_filename, kernel_cmdline, initrd_filename, - cpu_model, &n800_binfo, 800); + return n8x0_init(args, &n800_binfo, 800); } -static void n810_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void n810_init(QEMUMachineInitArgs *args) { - return n8x0_init(ram_size, boot_device, - kernel_filename, kernel_cmdline, initrd_filename, - cpu_model, &n810_binfo, 810); + return n8x0_init(args, &n810_binfo, 810); } static QEMUMachine n800_machine = { diff --git a/hw/null-machine.c b/hw/null-machine.c new file mode 100644 index 0000000000..d813c089e7 --- /dev/null +++ b/hw/null-machine.c @@ -0,0 +1,35 @@ +/* + * Empty machine + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "hw/hw.h" +#include "hw/boards.h" + +static void machine_none_init(QEMUMachineInitArgs *args) +{ +} + +static QEMUMachine machine_none = { + .name = "none", + .desc = "empty machine", + .init = machine_none_init, + .max_cpus = 0, +}; + +static void register_machines(void) +{ + qemu_register_machine(&machine_none); +} + +machine_init(register_machines); + diff --git a/hw/nvram.h b/hw/nvram.h index 8924da47d8..59337faaad 100644 --- a/hw/nvram.h +++ b/hw/nvram.h @@ -10,17 +10,9 @@ typedef struct nvram_t { nvram_write_t write_fn; } nvram_t; -void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value); -uint8_t NVRAM_get_byte (nvram_t *nvram, uint32_t addr); -void NVRAM_set_word (nvram_t *nvram, uint32_t addr, uint16_t value); -uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr); -void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value); uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr); -void NVRAM_set_string (nvram_t *nvram, uint32_t addr, - const char *str, uint32_t max); int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max); -void NVRAM_set_crc (nvram_t *nvram, uint32_t addr, - uint32_t start, uint32_t count); + int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size, const char *arch, uint32_t RAM_size, int boot_device, @@ -36,8 +28,7 @@ uint32_t m48t59_read (void *private, uint32_t addr); void m48t59_toggle_lock (void *private, int lock); M48t59State *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size, int type); -M48t59State *m48t59_init(qemu_irq IRQ, target_phys_addr_t mem_base, +M48t59State *m48t59_init(qemu_irq IRQ, hwaddr mem_base, uint32_t io_base, uint16_t size, int type); -void m48t59_set_addr (void *opaque, uint32_t addr); #endif /* !NVRAM_H */ @@ -17,8 +17,9 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ #ifndef hw_omap_h -#include "memory.h" +#include "exec/memory.h" # define hw_omap_h "omap.h" +#include "hw/irq.h" # define OMAP_EMIFS_BASE 0x00000000 # define OMAP2_Q0_BASE 0x00000000 @@ -65,7 +66,7 @@ void omap_clk_reparent(omap_clk clk, omap_clk parent); /* OMAP2 l4 Interconnect */ struct omap_l4_s; struct omap_l4_region_s { - target_phys_addr_t offset; + hwaddr offset; size_t size; int access; }; @@ -80,13 +81,13 @@ struct omap_target_agent_s { struct omap_l4_s *bus; int regions; const struct omap_l4_region_s *start; - target_phys_addr_t base; + hwaddr base; uint32_t component; uint32_t control; uint32_t status; }; struct omap_l4_s *omap_l4_init(MemoryRegion *address_space, - target_phys_addr_t base, int ta_num); + hwaddr base, int ta_num); struct omap_target_agent_s; struct omap_target_agent_s *omap_l4ta_get( @@ -94,23 +95,23 @@ struct omap_target_agent_s *omap_l4ta_get( const struct omap_l4_region_s *regions, const struct omap_l4_agent_info_s *agents, int cs); -target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, +hwaddr omap_l4_attach(struct omap_target_agent_s *ta, int region, MemoryRegion *mr); -target_phys_addr_t omap_l4_region_base(struct omap_target_agent_s *ta, +hwaddr omap_l4_region_base(struct omap_target_agent_s *ta, int region); -target_phys_addr_t omap_l4_region_size(struct omap_target_agent_s *ta, +hwaddr omap_l4_region_size(struct omap_target_agent_s *ta, int region); /* OMAP2 SDRAM controller */ struct omap_sdrc_s; struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem, - target_phys_addr_t base); + hwaddr base); void omap_sdrc_reset(struct omap_sdrc_s *s); /* OMAP2 general purpose memory controller */ struct omap_gpmc_s; struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu, - target_phys_addr_t base, + hwaddr base, qemu_irq irq, qemu_irq drq); void omap_gpmc_reset(struct omap_gpmc_s *s); void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem); @@ -433,11 +434,11 @@ enum omap_dma_model { }; struct soc_dma_s; -struct soc_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, +struct soc_dma_s *omap_dma_init(hwaddr base, qemu_irq *irqs, MemoryRegion *sysmem, qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk, enum omap_dma_model model); -struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs, +struct soc_dma_s *omap_dma4_init(hwaddr base, qemu_irq *irqs, MemoryRegion *sysmem, struct omap_mpu_state_s *mpu, int fifo, int chans, omap_clk iclk, omap_clk fclk); @@ -469,10 +470,10 @@ typedef enum { /* Only used in OMAP DMA 3.x gigacells */ struct omap_dma_lcd_channel_s { enum omap_dma_port src; - target_phys_addr_t src_f1_top; - target_phys_addr_t src_f1_bottom; - target_phys_addr_t src_f2_top; - target_phys_addr_t src_f2_bottom; + hwaddr src_f1_top; + hwaddr src_f1_bottom; + hwaddr src_f2_top; + hwaddr src_f2_bottom; /* Used in OMAP DMA 3.2 gigacell */ unsigned char brust_f1; @@ -508,7 +509,7 @@ struct omap_dma_lcd_channel_s { int dual; int current_frame; - target_phys_addr_t phys_framebuffer[2]; + hwaddr phys_framebuffer[2]; qemu_irq irq; struct omap_mpu_state_s *mpu; } *omap_dma_get_lcdch(struct soc_dma_s *s); @@ -659,7 +660,7 @@ struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta, void omap_synctimer_reset(struct omap_synctimer_s *s); struct omap_uart_s; -struct omap_uart_s *omap_uart_init(target_phys_addr_t base, +struct omap_uart_s *omap_uart_init(hwaddr base, qemu_irq irq, omap_clk fclk, omap_clk iclk, qemu_irq txdma, qemu_irq rxdma, const char *label, CharDriverState *chr); @@ -728,7 +729,7 @@ void omap_tap_init(struct omap_target_agent_s *ta, struct omap_lcd_panel_s; void omap_lcdc_reset(struct omap_lcd_panel_s *s); struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem, - target_phys_addr_t base, + hwaddr base, qemu_irq irq, struct omap_dma_lcd_channel_s *dma, omap_clk clk); @@ -744,7 +745,7 @@ struct omap_dss_s; void omap_dss_reset(struct omap_dss_s *s); struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta, MemoryRegion *sysmem, - target_phys_addr_t l3_base, + hwaddr l3_base, qemu_irq irq, qemu_irq drq, omap_clk fck1, omap_clk fck2, omap_clk ck54m, omap_clk ick1, omap_clk ick2); @@ -752,7 +753,7 @@ void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip); /* omap_mmc.c */ struct omap_mmc_s; -struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, +struct omap_mmc_s *omap_mmc_init(hwaddr base, MemoryRegion *sysmem, BlockDriverState *bd, qemu_irq irq, qemu_irq dma[], omap_clk clk); @@ -829,11 +830,11 @@ struct omap_mpu_state_s { struct omap_dma_port_if_s { uint32_t (*read[3])(struct omap_mpu_state_s *s, - target_phys_addr_t offset); + hwaddr offset); void (*write[3])(struct omap_mpu_state_s *s, - target_phys_addr_t offset, uint32_t value); + hwaddr offset, uint32_t value); int (*addr_valid)(struct omap_mpu_state_s *s, - target_phys_addr_t addr); + hwaddr addr); } port[__omap_dma_port_last]; unsigned long sdram_size; @@ -942,16 +943,16 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, unsigned long sdram_size, const char *core); -#define OMAP_FMT_plx "%#08" TARGET_PRIxPHYS +#define OMAP_FMT_plx "%#08" HWADDR_PRIx -uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr); -void omap_badwidth_write8(void *opaque, target_phys_addr_t addr, +uint32_t omap_badwidth_read8(void *opaque, hwaddr addr); +void omap_badwidth_write8(void *opaque, hwaddr addr, uint32_t value); -uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr); -void omap_badwidth_write16(void *opaque, target_phys_addr_t addr, +uint32_t omap_badwidth_read16(void *opaque, hwaddr addr); +void omap_badwidth_write16(void *opaque, hwaddr addr, uint32_t value); -uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr); -void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, +uint32_t omap_badwidth_read32(void *opaque, hwaddr addr); +void omap_badwidth_write32(void *opaque, hwaddr addr, uint32_t value); void omap_mpu_wakeup(void *opaque, int irq, int req); diff --git a/hw/omap1.c b/hw/omap1.c index ad60cc4919..8536e96687 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -19,14 +19,14 @@ #include "hw.h" #include "arm-misc.h" #include "omap.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "soc_dma.h" -#include "blockdev.h" -#include "range.h" +#include "sysemu/blockdev.h" +#include "qemu/range.h" #include "sysbus.h" /* Should signal the TCMI/GPMC */ -uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr) +uint32_t omap_badwidth_read8(void *opaque, hwaddr addr) { uint8_t ret; @@ -35,7 +35,7 @@ uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr) return ret; } -void omap_badwidth_write8(void *opaque, target_phys_addr_t addr, +void omap_badwidth_write8(void *opaque, hwaddr addr, uint32_t value) { uint8_t val8 = value; @@ -44,7 +44,7 @@ void omap_badwidth_write8(void *opaque, target_phys_addr_t addr, cpu_physical_memory_write(addr, (void *) &val8, 1); } -uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr) +uint32_t omap_badwidth_read16(void *opaque, hwaddr addr) { uint16_t ret; @@ -53,7 +53,7 @@ uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr) return ret; } -void omap_badwidth_write16(void *opaque, target_phys_addr_t addr, +void omap_badwidth_write16(void *opaque, hwaddr addr, uint32_t value) { uint16_t val16 = value; @@ -62,7 +62,7 @@ void omap_badwidth_write16(void *opaque, target_phys_addr_t addr, cpu_physical_memory_write(addr, (void *) &val16, 2); } -uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr) +uint32_t omap_badwidth_read32(void *opaque, hwaddr addr) { uint32_t ret; @@ -71,7 +71,7 @@ uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr) return ret; } -void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, +void omap_badwidth_write32(void *opaque, hwaddr addr, uint32_t value) { OMAP_32B_REG(addr); @@ -176,7 +176,7 @@ static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer) timer->rate = omap_clk_getrate(timer->clk); } -static uint64_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_mpu_timer_read(void *opaque, hwaddr addr, unsigned size) { struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; @@ -200,7 +200,7 @@ static uint64_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_mpu_timer_write(void *opaque, target_phys_addr_t addr, +static void omap_mpu_timer_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; @@ -251,7 +251,7 @@ static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s) } static struct omap_mpu_timer_s *omap_mpu_timer_init(MemoryRegion *system_memory, - target_phys_addr_t base, + hwaddr base, qemu_irq irq, omap_clk clk) { struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) @@ -282,7 +282,7 @@ struct omap_watchdog_timer_s { int reset; }; -static uint64_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_wd_timer_read(void *opaque, hwaddr addr, unsigned size) { struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; @@ -307,7 +307,7 @@ static uint64_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_wd_timer_write(void *opaque, target_phys_addr_t addr, +static void omap_wd_timer_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; @@ -380,7 +380,7 @@ static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s) } static struct omap_watchdog_timer_s *omap_wd_timer_init(MemoryRegion *memory, - target_phys_addr_t base, + hwaddr base, qemu_irq irq, omap_clk clk) { struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) @@ -405,7 +405,7 @@ struct omap_32khz_timer_s { MemoryRegion iomem; }; -static uint64_t omap_os_timer_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_os_timer_read(void *opaque, hwaddr addr, unsigned size) { struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; @@ -432,7 +432,7 @@ static uint64_t omap_os_timer_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_os_timer_write(void *opaque, target_phys_addr_t addr, +static void omap_os_timer_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; @@ -486,7 +486,7 @@ static void omap_os_timer_reset(struct omap_32khz_timer_s *s) } static struct omap_32khz_timer_s *omap_os_timer_init(MemoryRegion *memory, - target_phys_addr_t base, + hwaddr base, qemu_irq irq, omap_clk clk) { struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) @@ -506,7 +506,7 @@ static struct omap_32khz_timer_s *omap_os_timer_init(MemoryRegion *memory, } /* Ultra Low-Power Device Module */ -static uint64_t omap_ulpd_pm_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_ulpd_pm_read(void *opaque, hwaddr addr, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; @@ -573,7 +573,7 @@ static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s, omap_clk_canidle(omap_findclk(s, "usb_clk0"), (~value >> 3) & 1); } -static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr, +static void omap_ulpd_pm_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; @@ -726,7 +726,7 @@ static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu) } static void omap_ulpd_pm_init(MemoryRegion *system_memory, - target_phys_addr_t base, + hwaddr base, struct omap_mpu_state_s *mpu) { memory_region_init_io(&mpu->ulpd_pm_iomem, &omap_ulpd_pm_ops, mpu, @@ -736,7 +736,7 @@ static void omap_ulpd_pm_init(MemoryRegion *system_memory, } /* OMAP Pin Configuration */ -static uint64_t omap_pin_cfg_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_pin_cfg_read(void *opaque, hwaddr addr, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; @@ -843,7 +843,7 @@ static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s, omap_clk_onoff(omap_findclk(s, "usb_hhc_ck"), (value >> 9) & 1); } -static void omap_pin_cfg_write(void *opaque, target_phys_addr_t addr, +static void omap_pin_cfg_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; @@ -944,7 +944,7 @@ static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu) } static void omap_pin_cfg_init(MemoryRegion *system_memory, - target_phys_addr_t base, + hwaddr base, struct omap_mpu_state_s *mpu) { memory_region_init_io(&mpu->pin_cfg_iomem, &omap_pin_cfg_ops, mpu, @@ -954,7 +954,7 @@ static void omap_pin_cfg_init(MemoryRegion *system_memory, } /* Device Identification, Die Identification */ -static uint64_t omap_id_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_id_read(void *opaque, hwaddr addr, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; @@ -1001,7 +1001,7 @@ static uint64_t omap_id_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_id_write(void *opaque, target_phys_addr_t addr, +static void omap_id_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { if (size != 4) { @@ -1035,7 +1035,7 @@ static void omap_id_init(MemoryRegion *memory, struct omap_mpu_state_s *mpu) } /* MPUI Control (Dummy) */ -static uint64_t omap_mpui_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_mpui_read(void *opaque, hwaddr addr, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; @@ -1068,7 +1068,7 @@ static uint64_t omap_mpui_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_mpui_write(void *opaque, target_phys_addr_t addr, +static void omap_mpui_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; @@ -1109,7 +1109,7 @@ static void omap_mpui_reset(struct omap_mpu_state_s *s) s->mpui_ctrl = 0x0003ff1b; } -static void omap_mpui_init(MemoryRegion *memory, target_phys_addr_t base, +static void omap_mpui_init(MemoryRegion *memory, hwaddr base, struct omap_mpu_state_s *mpu) { memory_region_init_io(&mpu->mpui_iomem, &omap_mpui_ops, mpu, @@ -1131,7 +1131,7 @@ struct omap_tipb_bridge_s { uint16_t enh_control; }; -static uint64_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_tipb_bridge_read(void *opaque, hwaddr addr, unsigned size) { struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; @@ -1161,7 +1161,7 @@ static uint64_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_tipb_bridge_write(void *opaque, target_phys_addr_t addr, +static void omap_tipb_bridge_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque; @@ -1215,7 +1215,7 @@ static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s) } static struct omap_tipb_bridge_s *omap_tipb_bridge_init( - MemoryRegion *memory, target_phys_addr_t base, + MemoryRegion *memory, hwaddr base, qemu_irq abort_irq, omap_clk clk) { struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) @@ -1232,7 +1232,7 @@ static struct omap_tipb_bridge_s *omap_tipb_bridge_init( } /* Dummy Traffic Controller's Memory Interface */ -static uint64_t omap_tcmi_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_tcmi_read(void *opaque, hwaddr addr, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; @@ -1270,7 +1270,7 @@ static uint64_t omap_tcmi_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_tcmi_write(void *opaque, target_phys_addr_t addr, +static void omap_tcmi_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; @@ -1330,7 +1330,7 @@ static void omap_tcmi_reset(struct omap_mpu_state_s *mpu) mpu->tcmi_regs[0x40 >> 2] = 0x00000000; } -static void omap_tcmi_init(MemoryRegion *memory, target_phys_addr_t base, +static void omap_tcmi_init(MemoryRegion *memory, hwaddr base, struct omap_mpu_state_s *mpu) { memory_region_init_io(&mpu->tcmi_iomem, &omap_tcmi_ops, mpu, @@ -1346,7 +1346,7 @@ struct dpll_ctl_s { omap_clk dpll; }; -static uint64_t omap_dpll_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_dpll_read(void *opaque, hwaddr addr, unsigned size) { struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; @@ -1362,7 +1362,7 @@ static uint64_t omap_dpll_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_dpll_write(void *opaque, target_phys_addr_t addr, +static void omap_dpll_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque; @@ -1412,7 +1412,7 @@ static void omap_dpll_reset(struct dpll_ctl_s *s) } static struct dpll_ctl_s *omap_dpll_init(MemoryRegion *memory, - target_phys_addr_t base, omap_clk clk) + hwaddr base, omap_clk clk) { struct dpll_ctl_s *s = g_malloc0(sizeof(*s)); memory_region_init_io(&s->iomem, &omap_dpll_ops, s, "omap-dpll", 0x100); @@ -1425,7 +1425,7 @@ static struct dpll_ctl_s *omap_dpll_init(MemoryRegion *memory, } /* MPU Clock/Reset/Power Mode Control */ -static uint64_t omap_clkm_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_clkm_read(void *opaque, hwaddr addr, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; @@ -1627,7 +1627,7 @@ static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s, } } -static void omap_clkm_write(void *opaque, target_phys_addr_t addr, +static void omap_clkm_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; @@ -1714,7 +1714,7 @@ static const MemoryRegionOps omap_clkm_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint64_t omap_clkdsp_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_clkdsp_read(void *opaque, hwaddr addr, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; @@ -1758,7 +1758,7 @@ static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s, SET_ONOFF("dspxor_ck", 1); /* EN_XORPCK */ } -static void omap_clkdsp_write(void *opaque, target_phys_addr_t addr, +static void omap_clkdsp_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; @@ -1823,8 +1823,8 @@ static void omap_clkm_reset(struct omap_mpu_state_s *s) s->clkm.dsp_rstct2 = 0x0000; } -static void omap_clkm_init(MemoryRegion *memory, target_phys_addr_t mpu_base, - target_phys_addr_t dsp_base, struct omap_mpu_state_s *s) +static void omap_clkm_init(MemoryRegion *memory, hwaddr mpu_base, + hwaddr dsp_base, struct omap_mpu_state_s *s) { memory_region_init_io(&s->clkm_iomem, &omap_clkm_ops, s, "omap-clkm", 0x100); @@ -1903,7 +1903,7 @@ static void omap_mpuio_kbd_update(struct omap_mpuio_s *s) s->row_latch = ~rows; } -static uint64_t omap_mpuio_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_mpuio_read(void *opaque, hwaddr addr, unsigned size) { struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; @@ -1963,7 +1963,7 @@ static uint64_t omap_mpuio_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_mpuio_write(void *opaque, target_phys_addr_t addr, +static void omap_mpuio_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque; @@ -2072,7 +2072,7 @@ static void omap_mpuio_onoff(void *opaque, int line, int on) } static struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory, - target_phys_addr_t base, + hwaddr base, qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup, omap_clk clk) { @@ -2159,7 +2159,7 @@ static void omap_uwire_transfer_start(struct omap_uwire_s *s) } } -static uint64_t omap_uwire_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_uwire_read(void *opaque, hwaddr addr, unsigned size) { struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; @@ -2193,7 +2193,7 @@ static uint64_t omap_uwire_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_uwire_write(void *opaque, target_phys_addr_t addr, +static void omap_uwire_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; @@ -2263,7 +2263,7 @@ static void omap_uwire_reset(struct omap_uwire_s *s) } static struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory, - target_phys_addr_t base, + hwaddr base, qemu_irq txirq, qemu_irq rxirq, qemu_irq dma, omap_clk clk) @@ -2312,7 +2312,7 @@ static void omap_pwl_update(struct omap_pwl_s *s) } } -static uint64_t omap_pwl_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_pwl_read(void *opaque, hwaddr addr, unsigned size) { struct omap_pwl_s *s = (struct omap_pwl_s *) opaque; @@ -2332,7 +2332,7 @@ static uint64_t omap_pwl_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_pwl_write(void *opaque, target_phys_addr_t addr, +static void omap_pwl_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_pwl_s *s = (struct omap_pwl_s *) opaque; @@ -2381,7 +2381,7 @@ static void omap_pwl_clk_update(void *opaque, int line, int on) } static struct omap_pwl_s *omap_pwl_init(MemoryRegion *system_memory, - target_phys_addr_t base, + hwaddr base, omap_clk clk) { struct omap_pwl_s *s = g_malloc0(sizeof(*s)); @@ -2405,7 +2405,7 @@ struct omap_pwt_s { omap_clk clk; }; -static uint64_t omap_pwt_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_pwt_read(void *opaque, hwaddr addr, unsigned size) { struct omap_pwt_s *s = (struct omap_pwt_s *) opaque; @@ -2427,7 +2427,7 @@ static uint64_t omap_pwt_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_pwt_write(void *opaque, target_phys_addr_t addr, +static void omap_pwt_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_pwt_s *s = (struct omap_pwt_s *) opaque; @@ -2488,7 +2488,7 @@ static void omap_pwt_reset(struct omap_pwt_s *s) } static struct omap_pwt_s *omap_pwt_init(MemoryRegion *system_memory, - target_phys_addr_t base, + hwaddr base, omap_clk clk) { struct omap_pwt_s *s = g_malloc0(sizeof(*s)); @@ -2536,7 +2536,7 @@ static void omap_rtc_alarm_update(struct omap_rtc_s *s) printf("%s: conversion failed\n", __FUNCTION__); } -static uint64_t omap_rtc_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_rtc_read(void *opaque, hwaddr addr, unsigned size) { struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; @@ -2618,7 +2618,7 @@ static uint64_t omap_rtc_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_rtc_write(void *opaque, target_phys_addr_t addr, +static void omap_rtc_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_rtc_s *s = (struct omap_rtc_s *) opaque; @@ -2901,7 +2901,7 @@ static void omap_rtc_reset(struct omap_rtc_s *s) } static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory, - target_phys_addr_t base, + hwaddr base, qemu_irq timerirq, qemu_irq alarmirq, omap_clk clk) { @@ -3129,7 +3129,7 @@ static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) omap_mcbsp_rx_stop(s); } -static uint64_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_mcbsp_read(void *opaque, hwaddr addr, unsigned size) { struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; @@ -3227,7 +3227,7 @@ static uint64_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_mcbsp_writeh(void *opaque, target_phys_addr_t addr, +static void omap_mcbsp_writeh(void *opaque, hwaddr addr, uint32_t value) { struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; @@ -3365,7 +3365,7 @@ static void omap_mcbsp_writeh(void *opaque, target_phys_addr_t addr, OMAP_BAD_REG(addr); } -static void omap_mcbsp_writew(void *opaque, target_phys_addr_t addr, +static void omap_mcbsp_writew(void *opaque, hwaddr addr, uint32_t value) { struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; @@ -3396,7 +3396,7 @@ static void omap_mcbsp_writew(void *opaque, target_phys_addr_t addr, omap_badwidth_write16(opaque, addr, value); } -static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, +static void omap_mcbsp_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { switch (size) { @@ -3432,7 +3432,7 @@ static void omap_mcbsp_reset(struct omap_mcbsp_s *s) } static struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory, - target_phys_addr_t base, + hwaddr base, qemu_irq txirq, qemu_irq rxirq, qemu_irq *dma, omap_clk clk) { @@ -3547,7 +3547,7 @@ static void omap_lpg_reset(struct omap_lpg_s *s) omap_lpg_update(s); } -static uint64_t omap_lpg_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_lpg_read(void *opaque, hwaddr addr, unsigned size) { struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; @@ -3569,7 +3569,7 @@ static uint64_t omap_lpg_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_lpg_write(void *opaque, target_phys_addr_t addr, +static void omap_lpg_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_lpg_s *s = (struct omap_lpg_s *) opaque; @@ -3613,7 +3613,7 @@ static void omap_lpg_clk_update(void *opaque, int line, int on) } static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory, - target_phys_addr_t base, omap_clk clk) + hwaddr base, omap_clk clk) { struct omap_lpg_s *s = (struct omap_lpg_s *) g_malloc0(sizeof(struct omap_lpg_s)); @@ -3631,7 +3631,7 @@ static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory, } /* MPUI Peripheral Bridge configuration */ -static uint64_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_mpui_io_read(void *opaque, hwaddr addr, unsigned size) { if (size != 2) { @@ -3645,7 +3645,7 @@ static uint64_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_mpui_io_write(void *opaque, target_phys_addr_t addr, +static void omap_mpui_io_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { /* FIXME: infinite loop */ @@ -3706,8 +3706,8 @@ static void omap1_mpu_reset(void *opaque) } static const struct omap_map_s { - target_phys_addr_t phys_dsp; - target_phys_addr_t phys_mpu; + hwaddr phys_dsp; + hwaddr phys_mpu; uint32_t size; const char *name; } omap15xx_dsp_mm[] = { @@ -3778,38 +3778,38 @@ static const struct dma_irq_map omap1_dma_irq_map[] = { /* DMA ports for OMAP1 */ static int omap_validate_emiff_addr(struct omap_mpu_state_s *s, - target_phys_addr_t addr) + hwaddr addr) { return range_covers_byte(OMAP_EMIFF_BASE, s->sdram_size, addr); } static int omap_validate_emifs_addr(struct omap_mpu_state_s *s, - target_phys_addr_t addr) + hwaddr addr) { return range_covers_byte(OMAP_EMIFS_BASE, OMAP_EMIFF_BASE - OMAP_EMIFS_BASE, addr); } static int omap_validate_imif_addr(struct omap_mpu_state_s *s, - target_phys_addr_t addr) + hwaddr addr) { return range_covers_byte(OMAP_IMIF_BASE, s->sram_size, addr); } static int omap_validate_tipb_addr(struct omap_mpu_state_s *s, - target_phys_addr_t addr) + hwaddr addr) { return range_covers_byte(0xfffb0000, 0xffff0000 - 0xfffb0000, addr); } static int omap_validate_local_addr(struct omap_mpu_state_s *s, - target_phys_addr_t addr) + hwaddr addr) { return range_covers_byte(OMAP_LOCALBUS_BASE, 0x1000000, addr); } static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s, - target_phys_addr_t addr) + hwaddr addr) { return range_covers_byte(0xe1010000, 0xe1020004 - 0xe1010000, addr); } diff --git a/hw/omap2.c b/hw/omap2.c index 4278dd19c4..c8358500bc 100644 --- a/hw/omap2.c +++ b/hw/omap2.c @@ -18,13 +18,13 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "hw.h" #include "arm-misc.h" #include "omap.h" -#include "sysemu.h" -#include "qemu-timer.h" -#include "qemu-char.h" +#include "sysemu/sysemu.h" +#include "qemu/timer.h" +#include "char/char.h" #include "flash.h" #include "soc_dma.h" #include "sysbus.h" @@ -324,7 +324,7 @@ static void omap_eac_reset(struct omap_eac_s *s) omap_eac_interrupt_update(s); } -static uint64_t omap_eac_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_eac_read(void *opaque, hwaddr addr, unsigned size) { struct omap_eac_s *s = (struct omap_eac_s *) opaque; @@ -440,7 +440,7 @@ static uint64_t omap_eac_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_eac_write(void *opaque, target_phys_addr_t addr, +static void omap_eac_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_eac_s *s = (struct omap_eac_s *) opaque; @@ -644,7 +644,7 @@ static void omap_sti_reset(struct omap_sti_s *s) omap_sti_interrupt_update(s); } -static uint64_t omap_sti_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_sti_read(void *opaque, hwaddr addr, unsigned size) { struct omap_sti_s *s = (struct omap_sti_s *) opaque; @@ -685,7 +685,7 @@ static uint64_t omap_sti_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_sti_write(void *opaque, target_phys_addr_t addr, +static void omap_sti_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_sti_s *s = (struct omap_sti_s *) opaque; @@ -741,14 +741,14 @@ static const MemoryRegionOps omap_sti_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint64_t omap_sti_fifo_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_sti_fifo_read(void *opaque, hwaddr addr, unsigned size) { OMAP_BAD_REG(addr); return 0; } -static void omap_sti_fifo_write(void *opaque, target_phys_addr_t addr, +static void omap_sti_fifo_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_sti_s *s = (struct omap_sti_s *) opaque; @@ -780,7 +780,7 @@ static const MemoryRegionOps omap_sti_fifo_ops = { static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta, MemoryRegion *sysmem, - target_phys_addr_t channel_base, qemu_irq irq, omap_clk clk, + hwaddr channel_base, qemu_irq irq, omap_clk clk, CharDriverState *chr) { struct omap_sti_s *s = (struct omap_sti_s *) @@ -1040,7 +1040,7 @@ static void omap_prcm_int_update(struct omap_prcm_s *s, int dom) /* XXX or is the mask applied before PRCM_IRQSTATUS_* ? */ } -static uint64_t omap_prcm_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_prcm_read(void *opaque, hwaddr addr, unsigned size) { struct omap_prcm_s *s = (struct omap_prcm_s *) opaque; @@ -1352,7 +1352,7 @@ static void omap_prcm_dpll_update(struct omap_prcm_s *s) } } -static void omap_prcm_write(void *opaque, target_phys_addr_t addr, +static void omap_prcm_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_prcm_s *s = (struct omap_prcm_s *) opaque; @@ -1832,7 +1832,7 @@ struct omap_sysctl_s { uint32_t msuspendmux[5]; }; -static uint32_t omap_sysctl_read8(void *opaque, target_phys_addr_t addr) +static uint32_t omap_sysctl_read8(void *opaque, hwaddr addr) { struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; @@ -1857,7 +1857,7 @@ static uint32_t omap_sysctl_read8(void *opaque, target_phys_addr_t addr) return 0; } -static uint32_t omap_sysctl_read(void *opaque, target_phys_addr_t addr) +static uint32_t omap_sysctl_read(void *opaque, hwaddr addr) { struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; @@ -1957,7 +1957,7 @@ static uint32_t omap_sysctl_read(void *opaque, target_phys_addr_t addr) return 0; } -static void omap_sysctl_write8(void *opaque, target_phys_addr_t addr, +static void omap_sysctl_write8(void *opaque, hwaddr addr, uint32_t value) { struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; @@ -1981,7 +1981,7 @@ static void omap_sysctl_write8(void *opaque, target_phys_addr_t addr, } } -static void omap_sysctl_write(void *opaque, target_phys_addr_t addr, +static void omap_sysctl_write(void *opaque, hwaddr addr, uint32_t value) { struct omap_sysctl_s *s = (struct omap_sysctl_s *) opaque; @@ -2226,7 +2226,7 @@ static void omap2_mpu_reset(void *opaque) } static int omap2_validate_addr(struct omap_mpu_state_s *s, - target_phys_addr_t addr) + hwaddr addr) { return 1; } diff --git a/hw/omap_dma.c b/hw/omap_dma.c index 389cb78dee..aec5874311 100644 --- a/hw/omap_dma.c +++ b/hw/omap_dma.c @@ -18,7 +18,7 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "qemu-common.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "omap.h" #include "irq.h" #include "soc_dma.h" @@ -31,7 +31,7 @@ struct omap_dma_channel_s { int endian_lock[2]; int translate[2]; enum omap_dma_port port[2]; - target_phys_addr_t addr[2]; + hwaddr addr[2]; omap_dma_addressing_t mode[2]; uint32_t elements; uint16_t frames; @@ -78,7 +78,7 @@ struct omap_dma_channel_s { struct omap_dma_channel_s *sibling; struct omap_dma_reg_set_s { - target_phys_addr_t src, dest; + hwaddr src, dest; int frame; int element; int pck_element; @@ -914,7 +914,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, break; case 0x06: /* SYS_DMA_CSR_CH0 */ - OMAP_RO_REG((target_phys_addr_t) reg); + OMAP_RO_REG((hwaddr) reg); break; case 0x08: /* SYS_DMA_CSSA_L_CH0 */ @@ -954,7 +954,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, break; case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */ - OMAP_RO_REG((target_phys_addr_t) reg); + OMAP_RO_REG((hwaddr) reg); break; case 0x1c: /* DMA_CDEI */ @@ -1446,7 +1446,7 @@ static int omap_dma_sys_read(struct omap_dma_s *s, int offset, return 0; } -static uint64_t omap_dma_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_dma_read(void *opaque, hwaddr addr, unsigned size) { struct omap_dma_s *s = (struct omap_dma_s *) opaque; @@ -1494,7 +1494,7 @@ static uint64_t omap_dma_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_dma_write(void *opaque, target_phys_addr_t addr, +static void omap_dma_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_dma_s *s = (struct omap_dma_s *) opaque; @@ -1618,7 +1618,7 @@ static void omap_dma_setcaps(struct omap_dma_s *s) } } -struct soc_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, +struct soc_dma_s *omap_dma_init(hwaddr base, qemu_irq *irqs, MemoryRegion *sysmem, qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk, enum omap_dma_model model) @@ -1692,7 +1692,7 @@ static void omap_dma_interrupts_4_update(struct omap_dma_s *s) qemu_irq_raise(s->irq[3]); } -static uint64_t omap_dma4_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_dma4_read(void *opaque, hwaddr addr, unsigned size) { struct omap_dma_s *s = (struct omap_dma_s *) opaque; @@ -1842,7 +1842,7 @@ static uint64_t omap_dma4_read(void *opaque, target_phys_addr_t addr, } } -static void omap_dma4_write(void *opaque, target_phys_addr_t addr, +static void omap_dma4_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_dma_s *s = (struct omap_dma_s *) opaque; @@ -1988,12 +1988,12 @@ static void omap_dma4_write(void *opaque, target_phys_addr_t addr, break; case 0x1c: /* DMA4_CSSA */ - ch->addr[0] = (target_phys_addr_t) (uint32_t) value; + ch->addr[0] = (hwaddr) (uint32_t) value; ch->set_update = 1; break; case 0x20: /* DMA4_CDSA */ - ch->addr[1] = (target_phys_addr_t) (uint32_t) value; + ch->addr[1] = (hwaddr) (uint32_t) value; ch->set_update = 1; break; @@ -2040,7 +2040,7 @@ static const MemoryRegionOps omap_dma4_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs, +struct soc_dma_s *omap_dma4_init(hwaddr base, qemu_irq *irqs, MemoryRegion *sysmem, struct omap_mpu_state_s *mpu, int fifo, int chans, omap_clk iclk, omap_clk fclk) diff --git a/hw/omap_dss.c b/hw/omap_dss.c index 86ed6ea5d9..ae51bdfe41 100644 --- a/hw/omap_dss.c +++ b/hw/omap_dss.c @@ -18,7 +18,7 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "hw.h" -#include "console.h" +#include "ui/console.h" #include "omap.h" struct omap_dss_s { @@ -60,7 +60,7 @@ struct omap_dss_s { int nx; int ny; - target_phys_addr_t addr[3]; + hwaddr addr[3]; uint32_t attr; uint32_t tresh; @@ -168,7 +168,7 @@ void omap_dss_reset(struct omap_dss_s *s) omap_dispc_interrupt_update(s); } -static uint64_t omap_diss_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_diss_read(void *opaque, hwaddr addr, unsigned size) { struct omap_dss_s *s = (struct omap_dss_s *) opaque; @@ -206,7 +206,7 @@ static uint64_t omap_diss_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_diss_write(void *opaque, target_phys_addr_t addr, +static void omap_diss_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_dss_s *s = (struct omap_dss_s *) opaque; @@ -246,7 +246,7 @@ static const MemoryRegionOps omap_diss_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint64_t omap_disc_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_disc_read(void *opaque, hwaddr addr, unsigned size) { struct omap_dss_s *s = (struct omap_dss_s *) opaque; @@ -371,7 +371,7 @@ static uint64_t omap_disc_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_disc_write(void *opaque, target_phys_addr_t addr, +static void omap_disc_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_dss_s *s = (struct omap_dss_s *) opaque; @@ -502,11 +502,11 @@ static void omap_disc_write(void *opaque, target_phys_addr_t addr, s->dispc.invalidate = 1; break; case 0x080: /* DISPC_GFX_BA0 */ - s->dispc.l[0].addr[0] = (target_phys_addr_t) value; + s->dispc.l[0].addr[0] = (hwaddr) value; s->dispc.invalidate = 1; break; case 0x084: /* DISPC_GFX_BA1 */ - s->dispc.l[0].addr[1] = (target_phys_addr_t) value; + s->dispc.l[0].addr[1] = (hwaddr) value; s->dispc.invalidate = 1; break; case 0x088: /* DISPC_GFX_POSITION */ @@ -543,7 +543,7 @@ static void omap_disc_write(void *opaque, target_phys_addr_t addr, s->dispc.l[0].wininc = value; break; case 0x0b8: /* DISPC_GFX_TABLE_BA */ - s->dispc.l[0].addr[2] = (target_phys_addr_t) value; + s->dispc.l[0].addr[2] = (hwaddr) value; s->dispc.invalidate = 1; break; @@ -602,11 +602,11 @@ static void omap_rfbi_transfer_stop(struct omap_dss_s *s) static void omap_rfbi_transfer_start(struct omap_dss_s *s) { void *data; - target_phys_addr_t len; - target_phys_addr_t data_addr; + hwaddr len; + hwaddr data_addr; int pitch; static void *bounce_buffer; - static target_phys_addr_t bounce_len; + static hwaddr bounce_len; if (!s->rfbi.enable || s->rfbi.busy) return; @@ -663,7 +663,7 @@ static void omap_rfbi_transfer_start(struct omap_dss_s *s) omap_dispc_interrupt_update(s); } -static uint64_t omap_rfbi_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_rfbi_read(void *opaque, hwaddr addr, unsigned size) { struct omap_dss_s *s = (struct omap_dss_s *) opaque; @@ -730,7 +730,7 @@ static uint64_t omap_rfbi_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_rfbi_write(void *opaque, target_phys_addr_t addr, +static void omap_rfbi_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_dss_s *s = (struct omap_dss_s *) opaque; @@ -864,7 +864,7 @@ static const MemoryRegionOps omap_rfbi_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint64_t omap_venc_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_venc_read(void *opaque, hwaddr addr, unsigned size) { if (size != 4) { @@ -924,7 +924,7 @@ static uint64_t omap_venc_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_venc_write(void *opaque, target_phys_addr_t addr, +static void omap_venc_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { if (size != 4) { @@ -986,7 +986,7 @@ static const MemoryRegionOps omap_venc_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint64_t omap_im3_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_im3_read(void *opaque, hwaddr addr, unsigned size) { if (size != 4) { @@ -1012,7 +1012,7 @@ static uint64_t omap_im3_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_im3_write(void *opaque, target_phys_addr_t addr, +static void omap_im3_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { if (size != 4) { @@ -1041,7 +1041,7 @@ static const MemoryRegionOps omap_im3_ops = { struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta, MemoryRegion *sysmem, - target_phys_addr_t l3_base, + hwaddr l3_base, qemu_irq irq, qemu_irq drq, omap_clk fck1, omap_clk fck2, omap_clk ck54m, omap_clk ick1, omap_clk ick2) diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c index 201ff77c36..25655325d0 100644 --- a/hw/omap_gpio.c +++ b/hw/omap_gpio.c @@ -61,7 +61,7 @@ static void omap_gpio_set(void *opaque, int line, int level) } } -static uint64_t omap_gpio_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_gpio_read(void *opaque, hwaddr addr, unsigned size) { struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; @@ -99,7 +99,7 @@ static uint64_t omap_gpio_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_gpio_write(void *opaque, target_phys_addr_t addr, +static void omap_gpio_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; @@ -300,7 +300,7 @@ static void omap2_gpio_module_reset(struct omap2_gpio_s *s) s->delay = 0; } -static uint32_t omap2_gpio_module_read(void *opaque, target_phys_addr_t addr) +static uint32_t omap2_gpio_module_read(void *opaque, hwaddr addr) { struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; @@ -372,7 +372,7 @@ static uint32_t omap2_gpio_module_read(void *opaque, target_phys_addr_t addr) return 0; } -static void omap2_gpio_module_write(void *opaque, target_phys_addr_t addr, +static void omap2_gpio_module_write(void *opaque, hwaddr addr, uint32_t value) { struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; @@ -514,12 +514,12 @@ static void omap2_gpio_module_write(void *opaque, target_phys_addr_t addr, } } -static uint32_t omap2_gpio_module_readp(void *opaque, target_phys_addr_t addr) +static uint32_t omap2_gpio_module_readp(void *opaque, hwaddr addr) { return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3); } -static void omap2_gpio_module_writep(void *opaque, target_phys_addr_t addr, +static void omap2_gpio_module_writep(void *opaque, hwaddr addr, uint32_t value) { uint32_t cur = 0; @@ -604,7 +604,7 @@ static void omap2_gpif_reset(DeviceState *dev) s->gpo = 0; } -static uint64_t omap2_gpif_top_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap2_gpif_top_read(void *opaque, hwaddr addr, unsigned size) { struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque; @@ -633,7 +633,7 @@ static uint64_t omap2_gpif_top_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap2_gpif_top_write(void *opaque, target_phys_addr_t addr, +static void omap2_gpif_top_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque; diff --git a/hw/omap_gpmc.c b/hw/omap_gpmc.c index 2fc4137203..02ab0ab568 100644 --- a/hw/omap_gpmc.c +++ b/hw/omap_gpmc.c @@ -21,8 +21,8 @@ #include "hw.h" #include "flash.h" #include "omap.h" -#include "memory.h" -#include "exec-memory.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" /* General-Purpose Memory Controller */ struct omap_gpmc_s { @@ -121,7 +121,7 @@ static void omap_gpmc_dma_update(struct omap_gpmc_s *s, int value) * all addresses in the region behave like accesses to the relevant * GPMC_NAND_DATA_i register (which is actually implemented to call these) */ -static uint64_t omap_nand_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_nand_read(void *opaque, hwaddr addr, unsigned size) { struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque; @@ -200,7 +200,7 @@ static void omap_nand_setio(DeviceState *dev, uint64_t value, } } -static void omap_nand_write(void *opaque, target_phys_addr_t addr, +static void omap_nand_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque; @@ -281,7 +281,7 @@ static void fill_prefetch_fifo(struct omap_gpmc_s *s) * engine is enabled -- all addresses in the region behave alike: * data is read or written to the FIFO. */ -static uint64_t omap_gpmc_prefetch_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_gpmc_prefetch_read(void *opaque, hwaddr addr, unsigned size) { struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; @@ -311,7 +311,7 @@ static uint64_t omap_gpmc_prefetch_read(void *opaque, target_phys_addr_t addr, return data; } -static void omap_gpmc_prefetch_write(void *opaque, target_phys_addr_t addr, +static void omap_gpmc_prefetch_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; @@ -484,7 +484,7 @@ void omap_gpmc_reset(struct omap_gpmc_s *s) ecc_reset(&s->ecc[i]); } -static int gpmc_wordaccess_only(target_phys_addr_t addr) +static int gpmc_wordaccess_only(hwaddr addr) { /* Return true if the register offset is to a register that * only permits word width accesses. @@ -502,7 +502,7 @@ static int gpmc_wordaccess_only(target_phys_addr_t addr) return 1; } -static uint64_t omap_gpmc_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_gpmc_read(void *opaque, hwaddr addr, unsigned size) { struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; @@ -614,7 +614,7 @@ static uint64_t omap_gpmc_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_gpmc_write(void *opaque, target_phys_addr_t addr, +static void omap_gpmc_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; @@ -819,7 +819,7 @@ static const MemoryRegionOps omap_gpmc_ops = { }; struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu, - target_phys_addr_t base, + hwaddr base, qemu_irq irq, qemu_irq drq) { int cs; diff --git a/hw/omap_gptimer.c b/hw/omap_gptimer.c index 7a145198a4..a5db710dcb 100644 --- a/hw/omap_gptimer.c +++ b/hw/omap_gptimer.c @@ -18,7 +18,7 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "hw.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "omap.h" /* GP timers */ @@ -258,7 +258,7 @@ void omap_gp_timer_reset(struct omap_gp_timer_s *s) omap_gp_timer_update(s); } -static uint32_t omap_gp_timer_readw(void *opaque, target_phys_addr_t addr) +static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr) { struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; @@ -324,7 +324,7 @@ static uint32_t omap_gp_timer_readw(void *opaque, target_phys_addr_t addr) return 0; } -static uint32_t omap_gp_timer_readh(void *opaque, target_phys_addr_t addr) +static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr) { struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; uint32_t ret; @@ -338,7 +338,7 @@ static uint32_t omap_gp_timer_readh(void *opaque, target_phys_addr_t addr) } } -static void omap_gp_timer_write(void *opaque, target_phys_addr_t addr, +static void omap_gp_timer_write(void *opaque, hwaddr addr, uint32_t value) { struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; @@ -438,7 +438,7 @@ static void omap_gp_timer_write(void *opaque, target_phys_addr_t addr, } } -static void omap_gp_timer_writeh(void *opaque, target_phys_addr_t addr, +static void omap_gp_timer_writeh(void *opaque, hwaddr addr, uint32_t value) { struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c index 20bc82e3b8..ba08e6400c 100644 --- a/hw/omap_i2c.c +++ b/hw/omap_i2c.c @@ -149,7 +149,7 @@ static void omap_i2c_reset(DeviceState *dev) s->test = 0; } -static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr) +static uint32_t omap_i2c_read(void *opaque, hwaddr addr) { OMAPI2CState *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; @@ -248,7 +248,7 @@ static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr) return 0; } -static void omap_i2c_write(void *opaque, target_phys_addr_t addr, +static void omap_i2c_write(void *opaque, hwaddr addr, uint32_t value) { OMAPI2CState *s = opaque; @@ -390,7 +390,7 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr, } } -static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr, +static void omap_i2c_writeb(void *opaque, hwaddr addr, uint32_t value) { OMAPI2CState *s = opaque; diff --git a/hw/omap_intc.c b/hw/omap_intc.c index 5076e07ed5..61e0dafbdd 100644 --- a/hw/omap_intc.c +++ b/hw/omap_intc.c @@ -145,7 +145,7 @@ static void omap_set_intr_noedge(void *opaque, int irq, int req) bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi; } -static uint64_t omap_inth_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_inth_read(void *opaque, hwaddr addr, unsigned size) { struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; @@ -223,7 +223,7 @@ static uint64_t omap_inth_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_inth_write(void *opaque, target_phys_addr_t addr, +static void omap_inth_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; @@ -396,7 +396,7 @@ static TypeInfo omap_intc_info = { .class_init = omap_intc_class_init, }; -static uint64_t omap2_inth_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap2_inth_read(void *opaque, hwaddr addr, unsigned size) { struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; @@ -477,7 +477,7 @@ static uint64_t omap2_inth_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap2_inth_write(void *opaque, target_phys_addr_t addr, +static void omap2_inth_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; diff --git a/hw/omap_l4.c b/hw/omap_l4.c index dbad7f67a8..09e983f319 100644 --- a/hw/omap_l4.c +++ b/hw/omap_l4.c @@ -22,13 +22,13 @@ struct omap_l4_s { MemoryRegion *address_space; - target_phys_addr_t base; + hwaddr base; int ta_num; struct omap_target_agent_s ta[0]; }; struct omap_l4_s *omap_l4_init(MemoryRegion *address_space, - target_phys_addr_t base, int ta_num) + hwaddr base, int ta_num) { struct omap_l4_s *bus = g_malloc0( sizeof(*bus) + ta_num * sizeof(*bus->ta)); @@ -40,19 +40,19 @@ struct omap_l4_s *omap_l4_init(MemoryRegion *address_space, return bus; } -target_phys_addr_t omap_l4_region_base(struct omap_target_agent_s *ta, +hwaddr omap_l4_region_base(struct omap_target_agent_s *ta, int region) { return ta->bus->base + ta->start[region].offset; } -target_phys_addr_t omap_l4_region_size(struct omap_target_agent_s *ta, +hwaddr omap_l4_region_size(struct omap_target_agent_s *ta, int region) { return ta->start[region].size; } -static uint64_t omap_l4ta_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_l4ta_read(void *opaque, hwaddr addr, unsigned size) { struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque; @@ -76,7 +76,7 @@ static uint64_t omap_l4ta_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_l4ta_write(void *opaque, target_phys_addr_t addr, +static void omap_l4ta_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque; @@ -143,10 +143,10 @@ struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus, return ta; } -target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, +hwaddr omap_l4_attach(struct omap_target_agent_s *ta, int region, MemoryRegion *mr) { - target_phys_addr_t base; + hwaddr base; if (region < 0 || region >= ta->regions) { fprintf(stderr, "%s: bad io region (%i)\n", __FUNCTION__, region); diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c index 4a08e9d002..936850a621 100644 --- a/hw/omap_lcdc.c +++ b/hw/omap_lcdc.c @@ -17,9 +17,10 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "hw.h" -#include "console.h" +#include "ui/console.h" #include "omap.h" #include "framebuffer.h" +#include "ui/pixel_ops.h" struct omap_lcd_panel_s { MemoryRegion *sysmem; @@ -66,8 +67,6 @@ static void omap_lcd_interrupts(struct omap_lcd_panel_s *s) qemu_irq_lower(s->irq); } -#include "pixel_ops.h" - #define draw_line_func drawfn #define DEPTH 8 @@ -117,7 +116,7 @@ static void omap_update_display(void *opaque) draw_line_func draw_line; int size, height, first, last; int width, linesize, step, bpp, frame_offset; - target_phys_addr_t frame_base; + hwaddr frame_base; if (!omap_lcd || omap_lcd->plm == 1 || !omap_lcd->enable || !ds_get_bits_per_pixel(omap_lcd->state)) @@ -219,23 +218,29 @@ static void omap_update_display(void *opaque) draw_line, omap_lcd->palette, &first, &last); if (first >= 0) { - dpy_update(omap_lcd->state, 0, first, width, last - first + 1); + dpy_gfx_update(omap_lcd->state, 0, first, width, last - first + 1); } omap_lcd->invalidate = 0; } -static int ppm_save(const char *filename, uint8_t *data, - int w, int h, int linesize) +static void omap_ppm_save(const char *filename, uint8_t *data, + int w, int h, int linesize, Error **errp) { FILE *f; uint8_t *d, *d1; unsigned int v; - int y, x, bpp; + int ret, y, x, bpp; f = fopen(filename, "wb"); - if (!f) - return -1; - fprintf(f, "P6\n%d %d\n%d\n", w, h, 255); + if (!f) { + error_setg(errp, "failed to open file '%s': %s", filename, + strerror(errno)); + return; + } + ret = fprintf(f, "P6\n%d %d\n%d\n", w, h, 255); + if (ret < 0) { + goto write_err; + } d1 = data; bpp = linesize / w; for (y = 0; y < h; y ++) { @@ -244,35 +249,61 @@ static int ppm_save(const char *filename, uint8_t *data, v = *(uint32_t *) d; switch (bpp) { case 2: - fputc((v >> 8) & 0xf8, f); - fputc((v >> 3) & 0xfc, f); - fputc((v << 3) & 0xf8, f); + ret = fputc((v >> 8) & 0xf8, f); + if (ret == EOF) { + goto write_err; + } + ret = fputc((v >> 3) & 0xfc, f); + if (ret == EOF) { + goto write_err; + } + ret = fputc((v << 3) & 0xf8, f); + if (ret == EOF) { + goto write_err; + } break; case 3: case 4: default: - fputc((v >> 16) & 0xff, f); - fputc((v >> 8) & 0xff, f); - fputc((v) & 0xff, f); + ret = fputc((v >> 16) & 0xff, f); + if (ret == EOF) { + goto write_err; + } + ret = fputc((v >> 8) & 0xff, f); + if (ret == EOF) { + goto write_err; + } + ret = fputc((v) & 0xff, f); + if (ret == EOF) { + goto write_err; + } break; } d += bpp; } d1 += linesize; } +out: fclose(f); - return 0; + return; + +write_err: + error_setg(errp, "failed to write to file '%s': %s", filename, + strerror(errno)); + unlink(filename); + goto out; } -static void omap_screen_dump(void *opaque, const char *filename, bool cswitch) +static void omap_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp) { struct omap_lcd_panel_s *omap_lcd = opaque; omap_update_display(opaque); if (omap_lcd && ds_get_data(omap_lcd->state)) - ppm_save(filename, ds_get_data(omap_lcd->state), - omap_lcd->width, omap_lcd->height, - ds_get_linesize(omap_lcd->state)); + omap_ppm_save(filename, ds_get_data(omap_lcd->state), + omap_lcd->width, omap_lcd->height, + ds_get_linesize(omap_lcd->state), errp); } static void omap_invalidate_display(void *opaque) { @@ -327,7 +358,7 @@ static void omap_lcd_update(struct omap_lcd_panel_s *s) { } } -static uint64_t omap_lcdc_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_lcdc_read(void *opaque, hwaddr addr, unsigned size) { struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque; @@ -360,7 +391,7 @@ static uint64_t omap_lcdc_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_lcdc_write(void *opaque, target_phys_addr_t addr, +static void omap_lcdc_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque; @@ -433,7 +464,7 @@ void omap_lcdc_reset(struct omap_lcd_panel_s *s) } struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem, - target_phys_addr_t base, + hwaddr base, qemu_irq irq, struct omap_dma_lcd_channel_s *dma, omap_clk clk) diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c index aec0285675..7ecd9bd4ca 100644 --- a/hw/omap_mmc.c +++ b/hw/omap_mmc.c @@ -306,7 +306,7 @@ void omap_mmc_reset(struct omap_mmc_s *host) host->clkdiv = 0; } -static uint64_t omap_mmc_read(void *opaque, target_phys_addr_t offset, +static uint64_t omap_mmc_read(void *opaque, hwaddr offset, unsigned size) { uint16_t i; @@ -399,7 +399,7 @@ static uint64_t omap_mmc_read(void *opaque, target_phys_addr_t offset, return 0; } -static void omap_mmc_write(void *opaque, target_phys_addr_t offset, +static void omap_mmc_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { int i; @@ -572,7 +572,7 @@ static void omap_mmc_cover_cb(void *opaque, int line, int level) } } -struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, +struct omap_mmc_s *omap_mmc_init(hwaddr base, MemoryRegion *sysmem, BlockDriverState *bd, qemu_irq irq, qemu_irq dma[], omap_clk clk) diff --git a/hw/omap_sdrc.c b/hw/omap_sdrc.c index 784e326105..b0f3b8e675 100644 --- a/hw/omap_sdrc.c +++ b/hw/omap_sdrc.c @@ -31,7 +31,7 @@ void omap_sdrc_reset(struct omap_sdrc_s *s) s->config = 0x10; } -static uint64_t omap_sdrc_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_sdrc_read(void *opaque, hwaddr addr, unsigned size) { struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque; @@ -86,7 +86,7 @@ static uint64_t omap_sdrc_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_sdrc_write(void *opaque, target_phys_addr_t addr, +static void omap_sdrc_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque; @@ -154,7 +154,7 @@ static const MemoryRegionOps omap_sdrc_ops = { }; struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem, - target_phys_addr_t base) + hwaddr base) { struct omap_sdrc_s *s = (struct omap_sdrc_s *) g_malloc0(sizeof(struct omap_sdrc_s)); diff --git a/hw/omap_spi.c b/hw/omap_spi.c index 8f2b697d2d..42d5149a2b 100644 --- a/hw/omap_spi.c +++ b/hw/omap_spi.c @@ -130,7 +130,7 @@ void omap_mcspi_reset(struct omap_mcspi_s *s) omap_mcspi_interrupt_update(s); } -static uint64_t omap_mcspi_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_mcspi_read(void *opaque, hwaddr addr, unsigned size) { struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque; @@ -204,7 +204,7 @@ static uint64_t omap_mcspi_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_mcspi_write(void *opaque, target_phys_addr_t addr, +static void omap_mcspi_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque; diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c index abca341926..0f03121505 100644 --- a/hw/omap_sx1.c +++ b/hw/omap_sx1.c @@ -26,13 +26,13 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "hw.h" -#include "console.h" +#include "ui/console.h" #include "omap.h" #include "boards.h" #include "arm-misc.h" #include "flash.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" /*****************************************************************************/ /* Siemens SX1 Cellphone V1 */ @@ -59,7 +59,7 @@ * - 1 RTC */ -static uint64_t static_read(void *opaque, target_phys_addr_t offset, +static uint64_t static_read(void *opaque, hwaddr offset, unsigned size) { uint32_t *val = (uint32_t *) opaque; @@ -68,7 +68,7 @@ static uint64_t static_read(void *opaque, target_phys_addr_t offset, return *val >> ((offset & mask) << 3); } -static void static_write(void *opaque, target_phys_addr_t offset, +static void static_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { #ifdef SPY @@ -97,11 +97,7 @@ static struct arm_boot_info sx1_binfo = { .board_id = 0x265, }; -static void sx1_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model, - const int version) +static void sx1_init(QEMUMachineInitArgs *args, const int version) { struct omap_mpu_state_s *mpu; MemoryRegion *address_space = get_system_memory(); @@ -121,7 +117,7 @@ static void sx1_init(ram_addr_t ram_size, flash_size = flash2_size; } - mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, cpu_model); + mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, args->cpu_model); /* External Flash (EMIFS) */ memory_region_init_ram(flash, "omap_sx1.flash0-0", flash_size); @@ -192,16 +188,16 @@ static void sx1_init(ram_addr_t ram_size, OMAP_CS1_BASE, &cs[1]); } - if (!kernel_filename && !fl_idx) { + if (!args->kernel_filename && !fl_idx) { fprintf(stderr, "Kernel or Flash image must be specified\n"); exit(1); } /* Load the kernel. */ - if (kernel_filename) { - sx1_binfo.kernel_filename = kernel_filename; - sx1_binfo.kernel_cmdline = kernel_cmdline; - sx1_binfo.initrd_filename = initrd_filename; + if (args->kernel_filename) { + sx1_binfo.kernel_filename = args->kernel_filename; + sx1_binfo.kernel_cmdline = args->kernel_cmdline; + sx1_binfo.initrd_filename = args->initrd_filename; arm_load_kernel(mpu->cpu, &sx1_binfo); } @@ -209,22 +205,14 @@ static void sx1_init(ram_addr_t ram_size, //~ qemu_console_resize(ds, 640, 480); } -static void sx1_init_v1(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void sx1_init_v1(QEMUMachineInitArgs *args) { - sx1_init(ram_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, 1); + sx1_init(args, 1); } -static void sx1_init_v2(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void sx1_init_v2(QEMUMachineInitArgs *args) { - sx1_init(ram_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, 2); + sx1_init(args, 2); } static QEMUMachine sx1_machine_v2 = { diff --git a/hw/omap_synctimer.c b/hw/omap_synctimer.c index 367f26e3a1..945711eff5 100644 --- a/hw/omap_synctimer.c +++ b/hw/omap_synctimer.c @@ -18,7 +18,7 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "hw.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "omap.h" struct omap_synctimer_s { MemoryRegion iomem; @@ -36,7 +36,7 @@ void omap_synctimer_reset(struct omap_synctimer_s *s) s->val = omap_synctimer_read(s); } -static uint32_t omap_synctimer_readw(void *opaque, target_phys_addr_t addr) +static uint32_t omap_synctimer_readw(void *opaque, hwaddr addr) { struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque; @@ -52,7 +52,7 @@ static uint32_t omap_synctimer_readw(void *opaque, target_phys_addr_t addr) return 0; } -static uint32_t omap_synctimer_readh(void *opaque, target_phys_addr_t addr) +static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr) { struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque; uint32_t ret; @@ -66,7 +66,7 @@ static uint32_t omap_synctimer_readh(void *opaque, target_phys_addr_t addr) } } -static void omap_synctimer_write(void *opaque, target_phys_addr_t addr, +static void omap_synctimer_write(void *opaque, hwaddr addr, uint32_t value) { OMAP_BAD_REG(addr); diff --git a/hw/omap_tap.c b/hw/omap_tap.c index 0277c73652..e273e971ed 100644 --- a/hw/omap_tap.c +++ b/hw/omap_tap.c @@ -22,7 +22,7 @@ #include "omap.h" /* TEST-Chip-level TAP */ -static uint64_t omap_tap_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_tap_read(void *opaque, hwaddr addr, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; @@ -91,7 +91,7 @@ static uint64_t omap_tap_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_tap_write(void *opaque, target_phys_addr_t addr, +static void omap_tap_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { if (size != 4) { diff --git a/hw/omap_uart.c b/hw/omap_uart.c index 167d5c4e50..0ebfbf8cae 100644 --- a/hw/omap_uart.c +++ b/hw/omap_uart.c @@ -17,17 +17,16 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "qemu-char.h" +#include "char/char.h" #include "hw.h" #include "omap.h" -/* We use pc-style serial ports. */ -#include "pc.h" -#include "exec-memory.h" +#include "serial.h" +#include "exec/address-spaces.h" /* UARTs */ struct omap_uart_s { MemoryRegion iomem; - target_phys_addr_t base; + hwaddr base; SerialState *serial; /* TODO */ struct omap_target_agent_s *ta; omap_clk fclk; @@ -51,7 +50,7 @@ void omap_uart_reset(struct omap_uart_s *s) s->clksel = 0; } -struct omap_uart_s *omap_uart_init(target_phys_addr_t base, +struct omap_uart_s *omap_uart_init(hwaddr base, qemu_irq irq, omap_clk fclk, omap_clk iclk, qemu_irq txdma, qemu_irq rxdma, const char *label, CharDriverState *chr) @@ -69,7 +68,7 @@ struct omap_uart_s *omap_uart_init(target_phys_addr_t base, return s; } -static uint64_t omap_uart_read(void *opaque, target_phys_addr_t addr, +static uint64_t omap_uart_read(void *opaque, hwaddr addr, unsigned size) { struct omap_uart_s *s = (struct omap_uart_s *) opaque; @@ -107,7 +106,7 @@ static uint64_t omap_uart_read(void *opaque, target_phys_addr_t addr, return 0; } -static void omap_uart_write(void *opaque, target_phys_addr_t addr, +static void omap_uart_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct omap_uart_s *s = (struct omap_uart_s *) opaque; @@ -165,7 +164,7 @@ struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem, qemu_irq txdma, qemu_irq rxdma, const char *label, CharDriverState *chr) { - target_phys_addr_t base = omap_l4_attach(ta, 0, NULL); + hwaddr base = omap_l4_attach(ta, 0, NULL); struct omap_uart_s *s = omap_uart_init(base, irq, fclk, iclk, txdma, rxdma, label, chr); diff --git a/hw/onenand.c b/hw/onenand.c index db6af682c4..26bf991d6d 100644 --- a/hw/onenand.c +++ b/hw/onenand.c @@ -22,11 +22,11 @@ #include "hw.h" #include "flash.h" #include "irq.h" -#include "blockdev.h" -#include "memory.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" #include "sysbus.h" -#include "qemu-error.h" +#include "qemu/error-report.h" /* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */ #define PAGE_SHIFT 11 @@ -42,7 +42,7 @@ typedef struct { uint16_t ver; } id; int shift; - target_phys_addr_t base; + hwaddr base; qemu_irq intr; qemu_irq rdy; BlockDriverState *bdrv; @@ -351,7 +351,7 @@ static inline int onenand_erase(OneNANDState *s, int sec, int num) for (; num > 0; num--, sec++) { if (s->bdrv_cur) { int erasesec = s->secs_cur + (sec >> 5); - if (bdrv_write(s->bdrv_cur, sec, blankbuf, 1)) { + if (bdrv_write(s->bdrv_cur, sec, blankbuf, 1) < 0) { goto fail; } if (bdrv_read(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) { @@ -588,7 +588,7 @@ static void onenand_command(OneNANDState *s) onenand_intr_update(s); } -static uint64_t onenand_read(void *opaque, target_phys_addr_t addr, +static uint64_t onenand_read(void *opaque, hwaddr addr, unsigned size) { OneNANDState *s = (OneNANDState *) opaque; @@ -653,7 +653,7 @@ static uint64_t onenand_read(void *opaque, target_phys_addr_t addr, return 0; } -static void onenand_write(void *opaque, target_phys_addr_t addr, +static void onenand_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { OneNANDState *s = (OneNANDState *) opaque; @@ -760,7 +760,7 @@ static int onenand_initfn(SysBusDevice *dev) OneNANDState *s = (OneNANDState *)dev; uint32_t size = 1 << (24 + ((s->id.dev >> 4) & 7)); void *ram; - s->base = (target_phys_addr_t)-1; + s->base = (hwaddr)-1; s->rdy = NULL; s->blocks = size >> BLOCK_SHIFT; s->secs = size >> 9; diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c index 8c15969e2b..a0dfdce1f9 100644 --- a/hw/opencores_eth.c +++ b/hw/opencores_eth.c @@ -33,8 +33,8 @@ #include "hw.h" #include "sysbus.h" -#include "net.h" -#include "sysemu.h" +#include "net/net.h" +#include "sysemu/sysemu.h" #include "trace.h" /* RECSMALL is not used because it breaks tap networking in linux: @@ -528,7 +528,7 @@ static void open_eth_check_start_xmit(OpenEthState *s) } static uint64_t open_eth_reg_read(void *opaque, - target_phys_addr_t addr, unsigned int size) + hwaddr addr, unsigned int size) { static uint32_t (*reg_read[REG_MAX])(OpenEthState *s) = { }; @@ -620,7 +620,7 @@ static void open_eth_mii_tx_host_write(OpenEthState *s, uint32_t val) } static void open_eth_reg_write(void *opaque, - target_phys_addr_t addr, uint64_t val, unsigned int size) + hwaddr addr, uint64_t val, unsigned int size) { static void (*reg_write[REG_MAX])(OpenEthState *s, uint32_t val) = { [MODER] = open_eth_moder_host_write, @@ -644,7 +644,7 @@ static void open_eth_reg_write(void *opaque, } static uint64_t open_eth_desc_read(void *opaque, - target_phys_addr_t addr, unsigned int size) + hwaddr addr, unsigned int size) { OpenEthState *s = opaque; uint64_t v = 0; @@ -656,7 +656,7 @@ static uint64_t open_eth_desc_read(void *opaque, } static void open_eth_desc_write(void *opaque, - target_phys_addr_t addr, uint64_t val, unsigned int size) + hwaddr addr, uint64_t val, unsigned int size) { OpenEthState *s = opaque; diff --git a/hw/openpic.c b/hw/openpic.c index 58ef871f68..9c956b9dcc 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -35,8 +35,10 @@ */ #include "hw.h" #include "ppc_mac.h" -#include "pci.h" +#include "pci/pci.h" #include "openpic.h" +#include "sysbus.h" +#include "pci/msi.h" //#define DEBUG_OPENPIC @@ -46,118 +48,109 @@ #define DPRINTF(fmt, ...) do { } while (0) #endif -#define USE_MPCxxx /* Intel model is broken, for now */ - -#if defined (USE_INTEL_GW80314) -/* Intel GW80314 I/O Companion chip */ - -#define MAX_CPU 4 -#define MAX_IRQ 32 -#define MAX_DBL 4 -#define MAX_MBX 4 -#define MAX_TMR 4 -#define VECTOR_BITS 8 -#define MAX_IPI 4 - -#define VID (0x00000000) - -#elif defined(USE_MPCxxx) - -#define MAX_CPU 15 -#define MAX_IRQ 128 -#define MAX_DBL 0 -#define MAX_MBX 0 +#define MAX_CPU 15 +#define MAX_SRC 256 #define MAX_TMR 4 #define VECTOR_BITS 8 #define MAX_IPI 4 +#define MAX_MSI 8 +#define MAX_IRQ (MAX_SRC + MAX_IPI + MAX_TMR) #define VID 0x03 /* MPIC version ID */ -#define VENI 0x00000000 /* Vendor ID */ -enum { - IRQ_IPVP = 0, - IRQ_IDE, -}; +/* OpenPIC capability flags */ +#define OPENPIC_FLAG_IDE_CRIT (1 << 0) + +/* OpenPIC address map */ +#define OPENPIC_GLB_REG_START 0x0 +#define OPENPIC_GLB_REG_SIZE 0x10F0 +#define OPENPIC_TMR_REG_START 0x10F0 +#define OPENPIC_TMR_REG_SIZE 0x220 +#define OPENPIC_MSI_REG_START 0x1600 +#define OPENPIC_MSI_REG_SIZE 0x200 +#define OPENPIC_SRC_REG_START 0x10000 +#define OPENPIC_SRC_REG_SIZE (MAX_SRC * 0x20) +#define OPENPIC_CPU_REG_START 0x20000 +#define OPENPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000) + +/* Raven */ +#define RAVEN_MAX_CPU 2 +#define RAVEN_MAX_EXT 48 +#define RAVEN_MAX_IRQ 64 +#define RAVEN_MAX_TMR MAX_TMR +#define RAVEN_MAX_IPI MAX_IPI -/* OpenPIC */ -#define OPENPIC_MAX_CPU 2 -#define OPENPIC_MAX_IRQ 64 -#define OPENPIC_EXT_IRQ 48 -#define OPENPIC_MAX_TMR MAX_TMR -#define OPENPIC_MAX_IPI MAX_IPI +/* Interrupt definitions */ +#define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */ +#define RAVEN_ERR_IRQ (RAVEN_MAX_EXT + 1) /* Error IRQ */ +#define RAVEN_TMR_IRQ (RAVEN_MAX_EXT + 2) /* First timer IRQ */ +#define RAVEN_IPI_IRQ (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */ +/* First doorbell IRQ */ +#define RAVEN_DBL_IRQ (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI)) + +/* FSL_MPIC_20 */ +#define FSL_MPIC_20_MAX_CPU 1 +#define FSL_MPIC_20_MAX_EXT 12 +#define FSL_MPIC_20_MAX_INT 64 +#define FSL_MPIC_20_MAX_IRQ MAX_IRQ /* Interrupt definitions */ -#define OPENPIC_IRQ_FE (OPENPIC_EXT_IRQ) /* Internal functional IRQ */ -#define OPENPIC_IRQ_ERR (OPENPIC_EXT_IRQ + 1) /* Error IRQ */ -#define OPENPIC_IRQ_TIM0 (OPENPIC_EXT_IRQ + 2) /* First timer IRQ */ -#if OPENPIC_MAX_IPI > 0 -#define OPENPIC_IRQ_IPI0 (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First IPI IRQ */ -#define OPENPIC_IRQ_DBL0 (OPENPIC_IRQ_IPI0 + (OPENPIC_MAX_CPU * OPENPIC_MAX_IPI)) /* First doorbell IRQ */ -#else -#define OPENPIC_IRQ_DBL0 (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First doorbell IRQ */ -#define OPENPIC_IRQ_MBX0 (OPENPIC_IRQ_DBL0 + OPENPIC_MAX_DBL) /* First mailbox IRQ */ -#endif +/* IRQs, accessible through the IRQ region */ +#define FSL_MPIC_20_EXT_IRQ 0x00 +#define FSL_MPIC_20_INT_IRQ 0x10 +#define FSL_MPIC_20_MSG_IRQ 0xb0 +#define FSL_MPIC_20_MSI_IRQ 0xe0 +/* These are available through separate regions, but + for simplicity's sake mapped into the same number space */ +#define FSL_MPIC_20_TMR_IRQ 0x100 +#define FSL_MPIC_20_IPI_IRQ 0x104 + +/* + * Block Revision Register1 (BRR1): QEMU does not fully emulate + * any version on MPIC. So to start with, set the IP version to 0. + * + * NOTE: This is Freescale MPIC specific register. Keep it here till + * this code is refactored for different variants of OPENPIC and MPIC. + */ +#define FSL_BRR1_IPID (0x0040 << 16) /* 16 bit IP-block ID */ +#define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */ +#define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */ -/* MPIC */ -#define MPIC_MAX_CPU 1 -#define MPIC_MAX_EXT 12 -#define MPIC_MAX_INT 64 -#define MPIC_MAX_MSG 4 -#define MPIC_MAX_MSI 8 -#define MPIC_MAX_TMR MAX_TMR -#define MPIC_MAX_IPI MAX_IPI -#define MPIC_MAX_IRQ (MPIC_MAX_EXT + MPIC_MAX_INT + MPIC_MAX_TMR + MPIC_MAX_MSG + MPIC_MAX_MSI + (MPIC_MAX_IPI * MPIC_MAX_CPU)) +#define FREP_NIRQ_SHIFT 16 +#define FREP_NCPU_SHIFT 8 +#define FREP_VID_SHIFT 0 -/* Interrupt definitions */ -#define MPIC_EXT_IRQ 0 -#define MPIC_INT_IRQ (MPIC_EXT_IRQ + MPIC_MAX_EXT) -#define MPIC_TMR_IRQ (MPIC_INT_IRQ + MPIC_MAX_INT) -#define MPIC_MSG_IRQ (MPIC_TMR_IRQ + MPIC_MAX_TMR) -#define MPIC_MSI_IRQ (MPIC_MSG_IRQ + MPIC_MAX_MSG) -#define MPIC_IPI_IRQ (MPIC_MSI_IRQ + MPIC_MAX_MSI) - -#define MPIC_GLB_REG_START 0x0 -#define MPIC_GLB_REG_SIZE 0x10F0 -#define MPIC_TMR_REG_START 0x10F0 -#define MPIC_TMR_REG_SIZE 0x220 -#define MPIC_EXT_REG_START 0x10000 -#define MPIC_EXT_REG_SIZE 0x180 -#define MPIC_INT_REG_START 0x10200 -#define MPIC_INT_REG_SIZE 0x800 -#define MPIC_MSG_REG_START 0x11600 -#define MPIC_MSG_REG_SIZE 0x100 -#define MPIC_MSI_REG_START 0x11C00 -#define MPIC_MSI_REG_SIZE 0x100 -#define MPIC_CPU_REG_START 0x20000 -#define MPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000) - -enum mpic_ide_bits { - IDR_EP = 31, - IDR_CI0 = 30, - IDR_CI1 = 29, - IDR_P1 = 1, - IDR_P0 = 0, -}; +#define VID_REVISION_1_2 2 +#define VID_REVISION_1_3 3 -#else -#error "Please select which OpenPic implementation is to be emulated" -#endif +#define VENI_GENERIC 0x00000000 /* Generic Vendor ID */ -#define OPENPIC_PAGE_SIZE 4096 +#define IDR_EP_SHIFT 31 +#define IDR_EP_MASK (1 << IDR_EP_SHIFT) +#define IDR_CI0_SHIFT 30 +#define IDR_CI1_SHIFT 29 +#define IDR_P1_SHIFT 1 +#define IDR_P0_SHIFT 0 + +#define MSIIR_OFFSET 0x140 +#define MSIIR_SRS_SHIFT 29 +#define MSIIR_SRS_MASK (0x7 << MSIIR_SRS_SHIFT) +#define MSIIR_IBS_SHIFT 24 +#define MSIIR_IBS_MASK (0x1f << MSIIR_IBS_SHIFT) #define BF_WIDTH(_bits_) \ (((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8)) -static inline void set_bit (uint32_t *field, int bit) +static inline void set_bit(uint32_t *field, int bit) { field[bit >> 5] |= 1 << (bit & 0x1F); } -static inline void reset_bit (uint32_t *field, int bit) +static inline void reset_bit(uint32_t *field, int bit) { field[bit >> 5] &= ~(1 << (bit & 0x1F)); } -static inline int test_bit (uint32_t *field, int bit) +static inline int test_bit(uint32_t *field, int bit) { return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0; } @@ -167,46 +160,42 @@ static int get_current_cpu(void) return cpu_single_env->cpu_index; } -static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr, +static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, int idx); -static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr, +static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx); -enum { - IRQ_EXTERNAL = 0x01, - IRQ_INTERNAL = 0x02, - IRQ_TIMER = 0x04, - IRQ_SPECIAL = 0x08, -}; - typedef struct IRQ_queue_t { uint32_t queue[BF_WIDTH(MAX_IRQ)]; int next; int priority; + int pending; /* nr of pending bits in queue */ } IRQ_queue_t; typedef struct IRQ_src_t { uint32_t ipvp; /* IRQ vector/priority register */ uint32_t ide; /* IRQ destination register */ - int type; int last_cpu; int pending; /* TRUE if IRQ is pending */ } IRQ_src_t; -enum IPVP_bits { - IPVP_MASK = 31, - IPVP_ACTIVITY = 30, - IPVP_MODE = 29, - IPVP_POLARITY = 23, - IPVP_SENSE = 22, -}; +#define IPVP_MASK_SHIFT 31 +#define IPVP_MASK_MASK (1 << IPVP_MASK_SHIFT) +#define IPVP_ACTIVITY_SHIFT 30 +#define IPVP_ACTIVITY_MASK (1 << IPVP_ACTIVITY_SHIFT) +#define IPVP_MODE_SHIFT 29 +#define IPVP_MODE_MASK (1 << IPVP_MODE_SHIFT) +#define IPVP_POLARITY_SHIFT 23 +#define IPVP_POLARITY_MASK (1 << IPVP_POLARITY_SHIFT) +#define IPVP_SENSE_SHIFT 22 +#define IPVP_SENSE_MASK (1 << IPVP_SENSE_SHIFT) + #define IPVP_PRIORITY_MASK (0x1F << 16) #define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16)) #define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1) #define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK) typedef struct IRQ_dst_t { - uint32_t tfrr; uint32_t pctp; /* CPU current task priority */ uint32_t pcsr; /* CPU sensitivity register */ IRQ_queue_t raised; @@ -214,18 +203,28 @@ typedef struct IRQ_dst_t { qemu_irq *irqs; } IRQ_dst_t; -typedef struct openpic_t { - PCIDevice pci_dev; +typedef struct OpenPICState { + SysBusDevice busdev; MemoryRegion mem; + /* Behavior control */ + uint32_t model; + uint32_t flags; + uint32_t nb_irqs; + uint32_t vid; + uint32_t veni; /* Vendor identification register */ + uint32_t spve_mask; + uint32_t tifr_reset; + uint32_t ipvp_reset; + uint32_t ide_reset; + uint32_t brr1; + /* Sub-regions */ - MemoryRegion sub_io_mem[7]; + MemoryRegion sub_io_mem[5]; /* Global registers */ uint32_t frep; /* Feature reporting register */ uint32_t glbc; /* Global configuration register */ - uint32_t micr; /* MPIC interrupt configuration register */ - uint32_t veni; /* Vendor identification register */ uint32_t pint; /* Processor initialization register */ uint32_t spve; /* Spurious vector register */ uint32_t tifr; /* Timer frequency reporting register */ @@ -233,56 +232,54 @@ typedef struct openpic_t { IRQ_src_t src[MAX_IRQ]; /* Local registers per output pin */ IRQ_dst_t dst[MAX_CPU]; - int nb_cpus; + uint32_t nb_cpus; /* Timer registers */ struct { uint32_t ticc; /* Global timer current count register */ uint32_t tibc; /* Global timer base count register */ } timers[MAX_TMR]; -#if MAX_DBL > 0 - /* Doorbell registers */ - uint32_t dar; /* Doorbell activate register */ - struct { - uint32_t dmr; /* Doorbell messaging register */ - } doorbells[MAX_DBL]; -#endif -#if MAX_MBX > 0 - /* Mailbox registers */ + /* Shared MSI registers */ struct { - uint32_t mbr; /* Mailbox register */ - } mailboxes[MAX_MAILBOXES]; -#endif - /* IRQ out is used when in bypass mode (not implemented) */ - qemu_irq irq_out; - int max_irq; - int irq_ipi0; - int irq_tim0; - void (*reset) (void *); - void (*irq_raise) (struct openpic_t *, int, IRQ_src_t *); -} openpic_t; - -static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ) + uint32_t msir; /* Shared Message Signaled Interrupt Register */ + } msi[MAX_MSI]; + uint32_t max_irq; + uint32_t irq_ipi0; + uint32_t irq_tim0; + uint32_t irq_msi; +} OpenPICState; + +static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQ_src_t *src); + +static inline void IRQ_setbit(IRQ_queue_t *q, int n_IRQ) { + q->pending++; set_bit(q->queue, n_IRQ); } -static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ) +static inline void IRQ_resetbit(IRQ_queue_t *q, int n_IRQ) { + q->pending--; reset_bit(q->queue, n_IRQ); } -static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ) +static inline int IRQ_testbit(IRQ_queue_t *q, int n_IRQ) { return test_bit(q->queue, n_IRQ); } -static void IRQ_check (openpic_t *opp, IRQ_queue_t *q) +static void IRQ_check(OpenPICState *opp, IRQ_queue_t *q) { int next, i; int priority; next = -1; priority = -1; + + if (!q->pending) { + /* IRQ bitmap is empty */ + goto out; + } + for (i = 0; i < opp->max_irq; i++) { if (IRQ_testbit(q, i)) { DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n", @@ -293,11 +290,13 @@ static void IRQ_check (openpic_t *opp, IRQ_queue_t *q) } } } + +out: q->next = next; q->priority = priority; } -static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q) +static int IRQ_get_next(OpenPICState *opp, IRQ_queue_t *q) { if (q->next == -1) { /* XXX: optimize */ @@ -307,7 +306,7 @@ static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q) return q->next; } -static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) +static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) { IRQ_dst_t *dst; IRQ_src_t *src; @@ -328,7 +327,7 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) __func__, n_IRQ, n_CPU); return; } - set_bit(&src->ipvp, IPVP_ACTIVITY); + src->ipvp |= IPVP_ACTIVITY_MASK; IRQ_setbit(&dst->raised, n_IRQ); if (priority < dst->raised.priority) { /* An higher priority IRQ is already raised */ @@ -345,11 +344,11 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) return; } DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ); - opp->irq_raise(opp, n_CPU, src); + openpic_irq_raise(opp, n_CPU, src); } /* update pic state because registers for n_IRQ have changed value */ -static void openpic_update_irq(openpic_t *opp, int n_IRQ) +static void openpic_update_irq(OpenPICState *opp, int n_IRQ) { IRQ_src_t *src; int i; @@ -361,7 +360,7 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ); return; } - if (test_bit(&src->ipvp, IPVP_MASK)) { + if (src->ipvp & IPVP_MASK_MASK) { /* Interrupt source is disabled */ DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); return; @@ -371,7 +370,7 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ); return; } - if (test_bit(&src->ipvp, IPVP_ACTIVITY)) { + if (src->ipvp & IPVP_ACTIVITY_MASK) { /* IRQ already active */ DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ); return; @@ -385,18 +384,19 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) if (src->ide == (1 << src->last_cpu)) { /* Only one CPU is allowed to receive this IRQ */ IRQ_local_pipe(opp, src->last_cpu, n_IRQ); - } else if (!test_bit(&src->ipvp, IPVP_MODE)) { + } else if (!(src->ipvp & IPVP_MODE_MASK)) { /* Directed delivery mode */ for (i = 0; i < opp->nb_cpus; i++) { - if (test_bit(&src->ide, i)) + if (src->ide & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ); + } } } else { /* Distributed delivery mode */ for (i = src->last_cpu + 1; i != src->last_cpu; i++) { if (i == opp->nb_cpus) i = 0; - if (test_bit(&src->ide, i)) { + if (src->ide & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ); src->last_cpu = i; break; @@ -407,17 +407,18 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) static void openpic_set_irq(void *opaque, int n_IRQ, int level) { - openpic_t *opp = opaque; + OpenPICState *opp = opaque; IRQ_src_t *src; src = &opp->src[n_IRQ]; DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", n_IRQ, level, src->ipvp); - if (test_bit(&src->ipvp, IPVP_SENSE)) { + if (src->ipvp & IPVP_SENSE_MASK) { /* level-sensitive irq */ src->pending = level; - if (!level) - reset_bit(&src->ipvp, IPVP_ACTIVITY); + if (!level) { + src->ipvp &= ~IPVP_ACTIVITY_MASK; + } } else { /* edge-sensitive irq */ if (level) @@ -426,24 +427,24 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) openpic_update_irq(opp, n_IRQ); } -static void openpic_reset (void *opaque) +static void openpic_reset(DeviceState *d) { - openpic_t *opp = (openpic_t *)opaque; + OpenPICState *opp = FROM_SYSBUS(typeof (*opp), sysbus_from_qdev(d)); int i; opp->glbc = 0x80000000; /* Initialise controller registers */ - opp->frep = ((OPENPIC_EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID; - opp->veni = VENI; + opp->frep = ((opp->nb_irqs -1) << FREP_NIRQ_SHIFT) | + ((opp->nb_cpus -1) << FREP_NCPU_SHIFT) | + (opp->vid << FREP_VID_SHIFT); + opp->pint = 0x00000000; - opp->spve = 0x000000FF; - opp->tifr = 0x003F7A00; - /* ? */ - opp->micr = 0x00000000; + opp->spve = -1 & opp->spve_mask; + opp->tifr = opp->tifr_reset; /* Initialise IRQ sources */ for (i = 0; i < opp->max_irq; i++) { - opp->src[i].ipvp = 0xA0000000; - opp->src[i].ide = 0x00000000; + opp->src[i].ipvp = opp->ipvp_reset; + opp->src[i].ide = opp->ide_reset; } /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { @@ -459,34 +460,21 @@ static void openpic_reset (void *opaque) opp->timers[i].ticc = 0x00000000; opp->timers[i].tibc = 0x80000000; } - /* Initialise doorbells */ -#if MAX_DBL > 0 - opp->dar = 0x00000000; - for (i = 0; i < MAX_DBL; i++) { - opp->doorbells[i].dmr = 0x00000000; - } -#endif - /* Initialise mailboxes */ -#if MAX_MBX > 0 - for (i = 0; i < MAX_MBX; i++) { /* ? */ - opp->mailboxes[i].mbr = 0x00000000; - } -#endif /* Go out of RESET state */ opp->glbc = 0x00000000; } -static inline uint32_t read_IRQreg_ide(openpic_t *opp, int n_IRQ) +static inline uint32_t read_IRQreg_ide(OpenPICState *opp, int n_IRQ) { return opp->src[n_IRQ].ide; } -static inline uint32_t read_IRQreg_ipvp(openpic_t *opp, int n_IRQ) +static inline uint32_t read_IRQreg_ipvp(OpenPICState *opp, int n_IRQ) { return opp->src[n_IRQ].ipvp; } -static inline void write_IRQreg_ide(openpic_t *opp, int n_IRQ, uint32_t val) +static inline void write_IRQreg_ide(OpenPICState *opp, int n_IRQ, uint32_t val) { uint32_t tmp; @@ -496,7 +484,7 @@ static inline void write_IRQreg_ide(openpic_t *opp, int n_IRQ, uint32_t val) DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide); } -static inline void write_IRQreg_ipvp(openpic_t *opp, int n_IRQ, uint32_t val) +static inline void write_IRQreg_ipvp(OpenPICState *opp, int n_IRQ, uint32_t val) { /* NOTE: not fully accurate for special IRQs, but simple and sufficient */ /* ACTIVITY bit is read-only */ @@ -507,87 +495,10 @@ static inline void write_IRQreg_ipvp(openpic_t *opp, int n_IRQ, uint32_t val) opp->src[n_IRQ].ipvp); } -#if 0 // Code provision for Intel model -#if MAX_DBL > 0 -static uint32_t read_doorbell_register (openpic_t *opp, - int n_dbl, uint32_t offset) +static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, + unsigned len) { - uint32_t retval; - - switch (offset) { - case DBL_IPVP_OFFSET: - retval = read_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl); - break; - case DBL_IDE_OFFSET: - retval = read_IRQreg_ide(opp, IRQ_DBL0 + n_dbl); - break; - case DBL_DMR_OFFSET: - retval = opp->doorbells[n_dbl].dmr; - break; - } - - return retval; -} - -static void write_doorbell_register (penpic_t *opp, int n_dbl, - uint32_t offset, uint32_t value) -{ - switch (offset) { - case DBL_IVPR_OFFSET: - write_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl, value); - break; - case DBL_IDE_OFFSET: - write_IRQreg_ide(opp, IRQ_DBL0 + n_dbl, value); - break; - case DBL_DMR_OFFSET: - opp->doorbells[n_dbl].dmr = value; - break; - } -} -#endif - -#if MAX_MBX > 0 -static uint32_t read_mailbox_register (openpic_t *opp, - int n_mbx, uint32_t offset) -{ - uint32_t retval; - - switch (offset) { - case MBX_MBR_OFFSET: - retval = opp->mailboxes[n_mbx].mbr; - break; - case MBX_IVPR_OFFSET: - retval = read_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx); - break; - case MBX_DMR_OFFSET: - retval = read_IRQreg_ide(opp, IRQ_MBX0 + n_mbx); - break; - } - - return retval; -} - -static void write_mailbox_register (openpic_t *opp, int n_mbx, - uint32_t address, uint32_t value) -{ - switch (offset) { - case MBX_MBR_OFFSET: - opp->mailboxes[n_mbx].mbr = value; - break; - case MBX_IVPR_OFFSET: - write_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx, value); - break; - case MBX_DMR_OFFSET: - write_IRQreg_ide(opp, IRQ_MBX0 + n_mbx, value); - break; - } -} -#endif -#endif /* 0 : Code provision for Intel model */ - -static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - openpic_t *opp = opaque; + OpenPICState *opp = opaque; IRQ_dst_t *dst; int idx; @@ -595,6 +506,8 @@ static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t v if (addr & 0xF) return; switch (addr) { + case 0x00: /* Block Revision Register1 (BRR1) is Readonly */ + break; case 0x40: case 0x50: case 0x60: @@ -608,9 +521,9 @@ static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t v case 0x1000: /* FREP */ break; case 0x1020: /* GLBC */ - if (val & 0x80000000 && opp->reset) - opp->reset(opp); - opp->glbc = val & ~0x80000000; + if (val & 0x80000000) { + openpic_reset(&opp->busdev.qdev); + } break; case 0x1080: /* VENI */ break; @@ -639,19 +552,16 @@ static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t v } break; case 0x10E0: /* SPVE */ - opp->spve = val & 0x000000FF; - break; - case 0x10F0: /* TIFR */ - opp->tifr = val; + opp->spve = val & opp->spve_mask; break; default: break; } } -static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr) +static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) { - openpic_t *opp = opaque; + OpenPICState *opp = opaque; uint32_t retval; DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); @@ -671,6 +581,7 @@ static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr) case 0x1090: /* PINT */ retval = 0x00000000; break; + case 0x00: /* Block Revision Register1 (BRR1) */ case 0x40: case 0x50: case 0x60: @@ -694,9 +605,6 @@ static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr) case 0x10E0: /* SPVE */ retval = opp->spve; break; - case 0x10F0: /* TIFR */ - retval = opp->tifr; - break; default: break; } @@ -705,73 +613,83 @@ static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr) return retval; } -static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val) +static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, + unsigned len) { - openpic_t *opp = opaque; + OpenPICState *opp = opaque; int idx; DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); if (addr & 0xF) return; - addr -= 0x10; - addr &= 0xFFFF; - idx = (addr & 0xFFF0) >> 6; + idx = (addr >> 6) & 0x3; addr = addr & 0x30; - switch (addr) { - case 0x00: /* TICC */ + + if (addr == 0x0) { + /* TIFR (TFRR) */ + opp->tifr = val; + return; + } + switch (addr & 0x30) { + case 0x00: /* TICC (GTCCR) */ break; - case 0x10: /* TIBC */ + case 0x10: /* TIBC (GTBCR) */ if ((opp->timers[idx].ticc & 0x80000000) != 0 && (val & 0x80000000) == 0 && (opp->timers[idx].tibc & 0x80000000) != 0) opp->timers[idx].ticc &= ~0x80000000; opp->timers[idx].tibc = val; break; - case 0x20: /* TIVP */ + case 0x20: /* TIVP (GTIVPR) */ write_IRQreg_ipvp(opp, opp->irq_tim0 + idx, val); break; - case 0x30: /* TIDE */ + case 0x30: /* TIDE (GTIDR) */ write_IRQreg_ide(opp, opp->irq_tim0 + idx, val); break; } } -static uint32_t openpic_timer_read (void *opaque, uint32_t addr) +static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) { - openpic_t *opp = opaque; - uint32_t retval; + OpenPICState *opp = opaque; + uint32_t retval = -1; int idx; DPRINTF("%s: addr %08x\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; - addr -= 0x10; - addr &= 0xFFFF; - idx = (addr & 0xFFF0) >> 6; - addr = addr & 0x30; - switch (addr) { - case 0x00: /* TICC */ + if (addr & 0xF) { + goto out; + } + idx = (addr >> 6) & 0x3; + if (addr == 0x0) { + /* TIFR (TFRR) */ + retval = opp->tifr; + goto out; + } + switch (addr & 0x30) { + case 0x00: /* TICC (GTCCR) */ retval = opp->timers[idx].ticc; break; - case 0x10: /* TIBC */ + case 0x10: /* TIBC (GTBCR) */ retval = opp->timers[idx].tibc; break; - case 0x20: /* TIPV */ + case 0x20: /* TIPV (TIPV) */ retval = read_IRQreg_ipvp(opp, opp->irq_tim0 + idx); break; - case 0x30: /* TIDE */ + case 0x30: /* TIDE (TIDR) */ retval = read_IRQreg_ide(opp, opp->irq_tim0 + idx); break; } + +out: DPRINTF("%s: => %08x\n", __func__, retval); return retval; } -static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val) +static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val, + unsigned len) { - openpic_t *opp = opaque; + OpenPICState *opp = opaque; int idx; DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); @@ -788,9 +706,9 @@ static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t openpic_src_read (void *opaque, uint32_t addr) +static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) { - openpic_t *opp = opaque; + OpenPICState *opp = opaque; uint32_t retval; int idx; @@ -812,10 +730,72 @@ static uint32_t openpic_src_read (void *opaque, uint32_t addr) return retval; } -static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr, +static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + OpenPICState *opp = opaque; + int idx = opp->irq_msi; + int srs, ibs; + + DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); + if (addr & 0xF) { + return; + } + + switch (addr) { + case MSIIR_OFFSET: + srs = val >> MSIIR_SRS_SHIFT; + idx += srs; + ibs = (val & MSIIR_IBS_MASK) >> MSIIR_IBS_SHIFT; + opp->msi[srs].msir |= 1 << ibs; + openpic_set_irq(opp, idx, 1); + break; + default: + /* most registers are read-only, thus ignored */ + break; + } +} + +static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size) +{ + OpenPICState *opp = opaque; + uint64_t r = 0; + int i, srs; + + DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); + if (addr & 0xF) { + return -1; + } + + srs = addr >> 4; + + switch (addr) { + case 0x00: + case 0x10: + case 0x20: + case 0x30: + case 0x40: + case 0x50: + case 0x60: + case 0x70: /* MSIRs */ + r = opp->msi[srs].msir; + /* Clear on read */ + opp->msi[srs].msir = 0; + break; + case 0x120: /* MSISR */ + for (i = 0; i < MAX_MSI; i++) { + r |= (opp->msi[i].msir ? 1 : 0) << i; + } + break; + } + + return r; +} + +static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx) { - openpic_t *opp = opaque; + OpenPICState *opp = opaque; IRQ_src_t *src; IRQ_dst_t *dst; int s_IRQ, n_IRQ; @@ -827,7 +807,6 @@ static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr, dst = &opp->dst[idx]; addr &= 0xFF0; switch (addr) { -#if MAX_IPI > 0 case 0x40: /* IPIDR */ case 0x50: case 0x60: @@ -839,7 +818,6 @@ static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr, openpic_set_irq(opp, opp->irq_ipi0 + idx, 1); openpic_set_irq(opp, opp->irq_ipi0 + idx, 0); break; -#endif case 0x80: /* PCTP */ dst->pctp = val & 0x0000000F; break; @@ -864,7 +842,7 @@ static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr, IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) { DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", idx, n_IRQ); - opp->irq_raise(opp, idx, src); + openpic_irq_raise(opp, idx, src); } break; default: @@ -872,15 +850,16 @@ static void openpic_cpu_write_internal(void *opaque, target_phys_addr_t addr, } } -static void openpic_cpu_write(void *opaque, target_phys_addr_t addr, uint32_t val) +static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val, + unsigned len) { openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12); } -static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr, +static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, int idx) { - openpic_t *opp = opaque; + OpenPICState *opp = opaque; IRQ_src_t *src; IRQ_dst_t *dst; uint32_t retval; @@ -893,6 +872,9 @@ static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr, dst = &opp->dst[idx]; addr &= 0xFF0; switch (addr) { + case 0x00: /* Block Revision Register1 (BRR1) */ + retval = opp->brr1; + break; case 0x80: /* PCTP */ retval = dst->pctp; break; @@ -909,13 +891,13 @@ static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr, retval = IPVP_VECTOR(opp->spve); } else { src = &opp->src[n_IRQ]; - if (!test_bit(&src->ipvp, IPVP_ACTIVITY) || + if (!(src->ipvp & IPVP_ACTIVITY_MASK) || !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) { /* - Spurious level-sensitive IRQ * - Priorities has been changed * and the pending IRQ isn't allowed anymore */ - reset_bit(&src->ipvp, IPVP_ACTIVITY); + src->ipvp &= ~IPVP_ACTIVITY_MASK; retval = IPVP_VECTOR(opp->spve); } else { /* IRQ enter servicing state */ @@ -924,20 +906,20 @@ static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr, } IRQ_resetbit(&dst->raised, n_IRQ); dst->raised.next = -1; - if (!test_bit(&src->ipvp, IPVP_SENSE)) { + if (!(src->ipvp & IPVP_SENSE_MASK)) { /* edge-sensitive IRQ */ - reset_bit(&src->ipvp, IPVP_ACTIVITY); + src->ipvp &= ~IPVP_ACTIVITY_MASK; src->pending = 0; } if ((n_IRQ >= opp->irq_ipi0) && (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) { src->ide &= ~(1 << idx); - if (src->ide && !test_bit(&src->ipvp, IPVP_SENSE)) { + if (src->ide && !(src->ipvp & IPVP_SENSE_MASK)) { /* trigger on CPUs that didn't know about it yet */ openpic_set_irq(opp, n_IRQ, 1); openpic_set_irq(opp, n_IRQ, 0); /* if all CPUs knew about it, set active bit again */ - set_bit(&src->ipvp, IPVP_ACTIVITY); + src->ipvp |= IPVP_ACTIVITY_MASK; } } } @@ -953,96 +935,109 @@ static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr, return retval; } -static uint32_t openpic_cpu_read(void *opaque, target_phys_addr_t addr) +static uint64_t openpic_cpu_read(void *opaque, hwaddr addr, unsigned len) { return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12); } -static void openpic_buggy_write (void *opaque, - target_phys_addr_t addr, uint32_t val) -{ - printf("Invalid OPENPIC write access !\n"); -} - -static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr) -{ - printf("Invalid OPENPIC read access !\n"); - - return -1; -} - -static void openpic_writel (void *opaque, - target_phys_addr_t addr, uint32_t val) -{ - openpic_t *opp = opaque; - - addr &= 0x3FFFF; - DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val); - if (addr < 0x1100) { - /* Global registers */ - openpic_gbl_write(opp, addr, val); - } else if (addr < 0x10000) { - /* Timers registers */ - openpic_timer_write(opp, addr, val); - } else if (addr < 0x20000) { - /* Source registers */ - openpic_src_write(opp, addr, val); - } else { - /* CPU registers */ - openpic_cpu_write(opp, addr, val); - } -} +static const MemoryRegionOps openpic_glb_ops_le = { + .write = openpic_gbl_write, + .read = openpic_gbl_read, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; -static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr) -{ - openpic_t *opp = opaque; - uint32_t retval; +static const MemoryRegionOps openpic_glb_ops_be = { + .write = openpic_gbl_write, + .read = openpic_gbl_read, + .endianness = DEVICE_BIG_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; - addr &= 0x3FFFF; - DPRINTF("%s: offset %08x\n", __func__, (int)addr); - if (addr < 0x1100) { - /* Global registers */ - retval = openpic_gbl_read(opp, addr); - } else if (addr < 0x10000) { - /* Timers registers */ - retval = openpic_timer_read(opp, addr); - } else if (addr < 0x20000) { - /* Source registers */ - retval = openpic_src_read(opp, addr); - } else { - /* CPU registers */ - retval = openpic_cpu_read(opp, addr); - } +static const MemoryRegionOps openpic_tmr_ops_le = { + .write = openpic_tmr_write, + .read = openpic_tmr_read, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; - return retval; -} +static const MemoryRegionOps openpic_tmr_ops_be = { + .write = openpic_tmr_write, + .read = openpic_tmr_read, + .endianness = DEVICE_BIG_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; -static uint64_t openpic_read(void *opaque, target_phys_addr_t addr, - unsigned size) -{ - openpic_t *opp = opaque; +static const MemoryRegionOps openpic_cpu_ops_le = { + .write = openpic_cpu_write, + .read = openpic_cpu_read, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; - switch (size) { - case 4: return openpic_readl(opp, addr); - default: return openpic_buggy_read(opp, addr); - } -} +static const MemoryRegionOps openpic_cpu_ops_be = { + .write = openpic_cpu_write, + .read = openpic_cpu_read, + .endianness = DEVICE_BIG_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; -static void openpic_write(void *opaque, target_phys_addr_t addr, - uint64_t data, unsigned size) -{ - openpic_t *opp = opaque; +static const MemoryRegionOps openpic_src_ops_le = { + .write = openpic_src_write, + .read = openpic_src_read, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; - switch (size) { - case 4: return openpic_writel(opp, addr, data); - default: return openpic_buggy_write(opp, addr, data); - } -} +static const MemoryRegionOps openpic_src_ops_be = { + .write = openpic_src_write, + .read = openpic_src_read, + .endianness = DEVICE_BIG_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; -static const MemoryRegionOps openpic_ops = { - .read = openpic_read, - .write = openpic_write, +static const MemoryRegionOps openpic_msi_ops_le = { + .read = openpic_msi_read, + .write = openpic_msi_write, .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static const MemoryRegionOps openpic_msi_ops_be = { + .read = openpic_msi_read, + .write = openpic_msi_write, + .endianness = DEVICE_BIG_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, }; static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q) @@ -1058,12 +1053,10 @@ static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q) static void openpic_save(QEMUFile* f, void *opaque) { - openpic_t *opp = (openpic_t *)opaque; + OpenPICState *opp = (OpenPICState *)opaque; unsigned int i; - qemu_put_be32s(f, &opp->frep); qemu_put_be32s(f, &opp->glbc); - qemu_put_be32s(f, &opp->micr); qemu_put_be32s(f, &opp->veni); qemu_put_be32s(f, &opp->pint); qemu_put_be32s(f, &opp->spve); @@ -1072,15 +1065,13 @@ static void openpic_save(QEMUFile* f, void *opaque) for (i = 0; i < opp->max_irq; i++) { qemu_put_be32s(f, &opp->src[i].ipvp); qemu_put_be32s(f, &opp->src[i].ide); - qemu_put_sbe32s(f, &opp->src[i].type); qemu_put_sbe32s(f, &opp->src[i].last_cpu); qemu_put_sbe32s(f, &opp->src[i].pending); } - qemu_put_sbe32s(f, &opp->nb_cpus); + qemu_put_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { - qemu_put_be32s(f, &opp->dst[i].tfrr); qemu_put_be32s(f, &opp->dst[i].pctp); qemu_put_be32s(f, &opp->dst[i].pcsr); openpic_save_IRQ_queue(f, &opp->dst[i].raised); @@ -1091,22 +1082,6 @@ static void openpic_save(QEMUFile* f, void *opaque) qemu_put_be32s(f, &opp->timers[i].ticc); qemu_put_be32s(f, &opp->timers[i].tibc); } - -#if MAX_DBL > 0 - qemu_put_be32s(f, &opp->dar); - - for (i = 0; i < MAX_DBL; i++) { - qemu_put_be32s(f, &opp->doorbells[i].dmr); - } -#endif - -#if MAX_MBX > 0 - for (i = 0; i < MAX_MAILBOXES; i++) { - qemu_put_be32s(f, &opp->mailboxes[i].mbr); - } -#endif - - pci_device_save(&opp->pci_dev, f); } static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q) @@ -1122,15 +1097,13 @@ static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q) static int openpic_load(QEMUFile* f, void *opaque, int version_id) { - openpic_t *opp = (openpic_t *)opaque; + OpenPICState *opp = (OpenPICState *)opaque; unsigned int i; if (version_id != 1) return -EINVAL; - qemu_get_be32s(f, &opp->frep); qemu_get_be32s(f, &opp->glbc); - qemu_get_be32s(f, &opp->micr); qemu_get_be32s(f, &opp->veni); qemu_get_be32s(f, &opp->pint); qemu_get_be32s(f, &opp->spve); @@ -1139,15 +1112,13 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) for (i = 0; i < opp->max_irq; i++) { qemu_get_be32s(f, &opp->src[i].ipvp); qemu_get_be32s(f, &opp->src[i].ide); - qemu_get_sbe32s(f, &opp->src[i].type); qemu_get_sbe32s(f, &opp->src[i].last_cpu); qemu_get_sbe32s(f, &opp->src[i].pending); } - qemu_get_sbe32s(f, &opp->nb_cpus); + qemu_get_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { - qemu_get_be32s(f, &opp->dst[i].tfrr); qemu_get_be32s(f, &opp->dst[i].pctp); qemu_get_be32s(f, &opp->dst[i].pcsr); openpic_load_IRQ_queue(f, &opp->dst[i].raised); @@ -1159,535 +1130,156 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_be32s(f, &opp->timers[i].tibc); } -#if MAX_DBL > 0 - qemu_get_be32s(f, &opp->dar); - - for (i = 0; i < MAX_DBL; i++) { - qemu_get_be32s(f, &opp->doorbells[i].dmr); - } -#endif - -#if MAX_MBX > 0 - for (i = 0; i < MAX_MAILBOXES; i++) { - qemu_get_be32s(f, &opp->mailboxes[i].mbr); - } -#endif - - return pci_device_load(&opp->pci_dev, f); -} - -static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src) -{ - qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); -} - -qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus, - qemu_irq **irqs, qemu_irq irq_out) -{ - openpic_t *opp; - int i, m; - - /* XXX: for now, only one CPU is supported */ - if (nb_cpus != 1) - return NULL; - opp = g_malloc0(sizeof(openpic_t)); - memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000); - - // isu_base &= 0xFFFC0000; - opp->nb_cpus = nb_cpus; - opp->max_irq = OPENPIC_MAX_IRQ; - opp->irq_ipi0 = OPENPIC_IRQ_IPI0; - opp->irq_tim0 = OPENPIC_IRQ_TIM0; - /* Set IRQ types */ - for (i = 0; i < OPENPIC_EXT_IRQ; i++) { - opp->src[i].type = IRQ_EXTERNAL; - } - for (; i < OPENPIC_IRQ_TIM0; i++) { - opp->src[i].type = IRQ_SPECIAL; - } -#if MAX_IPI > 0 - m = OPENPIC_IRQ_IPI0; -#else - m = OPENPIC_IRQ_DBL0; -#endif - for (; i < m; i++) { - opp->src[i].type = IRQ_TIMER; - } - for (; i < OPENPIC_MAX_IRQ; i++) { - opp->src[i].type = IRQ_INTERNAL; - } - for (i = 0; i < nb_cpus; i++) - opp->dst[i].irqs = irqs[i]; - opp->irq_out = irq_out; - - register_savevm(&opp->pci_dev.qdev, "openpic", 0, 2, - openpic_save, openpic_load, opp); - qemu_register_reset(openpic_reset, opp); - - opp->irq_raise = openpic_irq_raise; - opp->reset = openpic_reset; - - if (pmem) - *pmem = &opp->mem; - - return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq); + return 0; } -static void mpic_irq_raise(openpic_t *mpp, int n_CPU, IRQ_src_t *src) +static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQ_src_t *src) { - int n_ci = IDR_CI0 - n_CPU; - - if(test_bit(&src->ide, n_ci)) { - qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]); - } - else { - qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); - } -} + int n_ci = IDR_CI0_SHIFT - n_CPU; -static void mpic_reset (void *opaque) -{ - openpic_t *mpp = (openpic_t *)opaque; - int i; - - mpp->glbc = 0x80000000; - /* Initialise controller registers */ - mpp->frep = 0x004f0002 | ((mpp->nb_cpus - 1) << 8); - mpp->veni = VENI; - mpp->pint = 0x00000000; - mpp->spve = 0x0000FFFF; - /* Initialise IRQ sources */ - for (i = 0; i < mpp->max_irq; i++) { - mpp->src[i].ipvp = 0x80800000; - mpp->src[i].ide = 0x00000001; - } - /* Set IDE for IPIs to 0 so we don't get spurious interrupts */ - for (i = mpp->irq_ipi0; i < (mpp->irq_ipi0 + MAX_IPI); i++) { - mpp->src[i].ide = 0; - } - /* Initialise IRQ destinations */ - for (i = 0; i < MAX_CPU; i++) { - mpp->dst[i].pctp = 0x0000000F; - mpp->dst[i].tfrr = 0x00000000; - memset(&mpp->dst[i].raised, 0, sizeof(IRQ_queue_t)); - mpp->dst[i].raised.next = -1; - memset(&mpp->dst[i].servicing, 0, sizeof(IRQ_queue_t)); - mpp->dst[i].servicing.next = -1; - } - /* Initialise timers */ - for (i = 0; i < MAX_TMR; i++) { - mpp->timers[i].ticc = 0x00000000; - mpp->timers[i].tibc = 0x80000000; + if ((opp->flags & OPENPIC_FLAG_IDE_CRIT) && (src->ide & (1 << n_ci))) { + qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]); + } else { + qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); } - /* Go out of RESET state */ - mpp->glbc = 0x00000000; } -static void mpic_timer_write (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - openpic_t *mpp = opaque; - int idx, cpu; - - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return; - addr &= 0xFFFF; - cpu = addr >> 12; - idx = (addr >> 6) & 0x3; - switch (addr & 0x30) { - case 0x00: /* gtccr */ - break; - case 0x10: /* gtbcr */ - if ((mpp->timers[idx].ticc & 0x80000000) != 0 && - (val & 0x80000000) == 0 && - (mpp->timers[idx].tibc & 0x80000000) != 0) - mpp->timers[idx].ticc &= ~0x80000000; - mpp->timers[idx].tibc = val; - break; - case 0x20: /* GTIVPR */ - write_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx, val); - break; - case 0x30: /* GTIDR & TFRR */ - if ((addr & 0xF0) == 0xF0) - mpp->dst[cpu].tfrr = val; - else - write_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx, val); - break; - } -} +struct memreg { + const char *name; + MemoryRegionOps const *ops; + bool map; + hwaddr start_addr; + ram_addr_t size; +}; -static uint32_t mpic_timer_read (void *opaque, target_phys_addr_t addr) +static int openpic_init(SysBusDevice *dev) { - openpic_t *mpp = opaque; - uint32_t retval; - int idx, cpu; + OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev); + int i, j; + struct memreg list_le[] = { + {"glb", &openpic_glb_ops_le, true, + OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, + {"tmr", &openpic_tmr_ops_le, true, + OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE}, + {"msi", &openpic_msi_ops_le, true, + OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE}, + {"src", &openpic_src_ops_le, true, + OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE}, + {"cpu", &openpic_cpu_ops_le, true, + OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, + }; + struct memreg list_be[] = { + {"glb", &openpic_glb_ops_be, true, + OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, + {"tmr", &openpic_tmr_ops_be, true, + OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE}, + {"msi", &openpic_msi_ops_be, true, + OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE}, + {"src", &openpic_src_ops_be, true, + OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE}, + {"cpu", &openpic_cpu_ops_be, true, + OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, + }; + struct memreg *list; - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; - addr &= 0xFFFF; - cpu = addr >> 12; - idx = (addr >> 6) & 0x3; - switch (addr & 0x30) { - case 0x00: /* gtccr */ - retval = mpp->timers[idx].ticc; - break; - case 0x10: /* gtbcr */ - retval = mpp->timers[idx].tibc; - break; - case 0x20: /* TIPV */ - retval = read_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx); - break; - case 0x30: /* TIDR */ - if ((addr &0xF0) == 0XF0) - retval = mpp->dst[cpu].tfrr; - else - retval = read_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx); + switch (opp->model) { + case OPENPIC_MODEL_FSL_MPIC_20: + default: + opp->flags |= OPENPIC_FLAG_IDE_CRIT; + opp->nb_irqs = 80; + opp->vid = VID_REVISION_1_2; + opp->veni = VENI_GENERIC; + opp->spve_mask = 0xFFFF; + opp->tifr_reset = 0x00000000; + opp->ipvp_reset = 0x80000000; + opp->ide_reset = 0x00000001; + opp->max_irq = FSL_MPIC_20_MAX_IRQ; + opp->irq_ipi0 = FSL_MPIC_20_IPI_IRQ; + opp->irq_tim0 = FSL_MPIC_20_TMR_IRQ; + opp->irq_msi = FSL_MPIC_20_MSI_IRQ; + opp->brr1 = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN; + msi_supported = true; + list = list_be; break; - } - DPRINTF("%s: => %08x\n", __func__, retval); - - return retval; -} - -static void mpic_src_ext_write (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - openpic_t *mpp = opaque; - int idx = MPIC_EXT_IRQ; - - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return; - - if (addr < MPIC_EXT_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - write_IRQreg_ide(mpp, idx, val); - } else { - /* EXVP / IFEVP / IEEVP */ - write_IRQreg_ipvp(mpp, idx, val); + case OPENPIC_MODEL_RAVEN: + opp->nb_irqs = RAVEN_MAX_EXT; + opp->vid = VID_REVISION_1_3; + opp->veni = VENI_GENERIC; + opp->spve_mask = 0xFF; + opp->tifr_reset = 0x003F7A00; + opp->ipvp_reset = 0xA0000000; + opp->ide_reset = 0x00000000; + opp->max_irq = RAVEN_MAX_IRQ; + opp->irq_ipi0 = RAVEN_IPI_IRQ; + opp->irq_tim0 = RAVEN_TMR_IRQ; + opp->brr1 = -1; + list = list_le; + /* Don't map MSI region */ + list[2].map = false; + + /* Only UP supported today */ + if (opp->nb_cpus != 1) { + return -EINVAL; } + break; } -} -static uint32_t mpic_src_ext_read (void *opaque, target_phys_addr_t addr) -{ - openpic_t *mpp = opaque; - uint32_t retval; - int idx = MPIC_EXT_IRQ; - - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; + memory_region_init(&opp->mem, "openpic", 0x40000); - if (addr < MPIC_EXT_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg_ide(mpp, idx); - } else { - /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg_ipvp(mpp, idx); + for (i = 0; i < ARRAY_SIZE(list_le); i++) { + if (!list[i].map) { + continue; } - DPRINTF("%s: => %08x\n", __func__, retval); - } - - return retval; -} - -static void mpic_src_int_write (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - openpic_t *mpp = opaque; - int idx = MPIC_INT_IRQ; - - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return; - if (addr < MPIC_INT_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - write_IRQreg_ide(mpp, idx, val); - } else { - /* EXVP / IFEVP / IEEVP */ - write_IRQreg_ipvp(mpp, idx, val); - } - } -} - -static uint32_t mpic_src_int_read (void *opaque, target_phys_addr_t addr) -{ - openpic_t *mpp = opaque; - uint32_t retval; - int idx = MPIC_INT_IRQ; - - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; + memory_region_init_io(&opp->sub_io_mem[i], list[i].ops, opp, + list[i].name, list[i].size); - if (addr < MPIC_INT_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg_ide(mpp, idx); - } else { - /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg_ipvp(mpp, idx); - } - DPRINTF("%s: => %08x\n", __func__, retval); + memory_region_add_subregion(&opp->mem, list[i].start_addr, + &opp->sub_io_mem[i]); } - return retval; -} - -static void mpic_src_msg_write (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - openpic_t *mpp = opaque; - int idx = MPIC_MSG_IRQ; - - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return; - - if (addr < MPIC_MSG_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - write_IRQreg_ide(mpp, idx, val); - } else { - /* EXVP / IFEVP / IEEVP */ - write_IRQreg_ipvp(mpp, idx, val); + for (i = 0; i < opp->nb_cpus; i++) { + opp->dst[i].irqs = g_new(qemu_irq, OPENPIC_OUTPUT_NB); + for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { + sysbus_init_irq(dev, &opp->dst[i].irqs[j]); } } -} - -static uint32_t mpic_src_msg_read (void *opaque, target_phys_addr_t addr) -{ - openpic_t *mpp = opaque; - uint32_t retval; - int idx = MPIC_MSG_IRQ; - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; + register_savevm(&opp->busdev.qdev, "openpic", 0, 2, + openpic_save, openpic_load, opp); - if (addr < MPIC_MSG_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg_ide(mpp, idx); - } else { - /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg_ipvp(mpp, idx); - } - DPRINTF("%s: => %08x\n", __func__, retval); - } + sysbus_init_mmio(dev, &opp->mem); + qdev_init_gpio_in(&dev->qdev, openpic_set_irq, opp->max_irq); - return retval; + return 0; } -static void mpic_src_msi_write (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - openpic_t *mpp = opaque; - int idx = MPIC_MSI_IRQ; - - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return; +static Property openpic_properties[] = { + DEFINE_PROP_UINT32("model", OpenPICState, model, OPENPIC_MODEL_FSL_MPIC_20), + DEFINE_PROP_UINT32("nb_cpus", OpenPICState, nb_cpus, 1), + DEFINE_PROP_END_OF_LIST(), +}; - if (addr < MPIC_MSI_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - write_IRQreg_ide(mpp, idx, val); - } else { - /* EXVP / IFEVP / IEEVP */ - write_IRQreg_ipvp(mpp, idx, val); - } - } -} -static uint32_t mpic_src_msi_read (void *opaque, target_phys_addr_t addr) +static void openpic_class_init(ObjectClass *klass, void *data) { - openpic_t *mpp = opaque; - uint32_t retval; - int idx = MPIC_MSI_IRQ; - - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - if (addr < MPIC_MSI_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg_ide(mpp, idx); - } else { - /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg_ipvp(mpp, idx); - } - DPRINTF("%s: => %08x\n", __func__, retval); - } - - return retval; + k->init = openpic_init; + dc->props = openpic_properties; + dc->reset = openpic_reset; } -static const MemoryRegionOps mpic_glb_ops = { - .old_mmio = { - .write = { openpic_buggy_write, - openpic_buggy_write, - openpic_gbl_write, - }, - .read = { openpic_buggy_read, - openpic_buggy_read, - openpic_gbl_read, - }, - }, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static const MemoryRegionOps mpic_tmr_ops = { - .old_mmio = { - .write = { openpic_buggy_write, - openpic_buggy_write, - mpic_timer_write, - }, - .read = { openpic_buggy_read, - openpic_buggy_read, - mpic_timer_read, - }, - }, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static const MemoryRegionOps mpic_cpu_ops = { - .old_mmio = { - .write = { openpic_buggy_write, - openpic_buggy_write, - openpic_cpu_write, - }, - .read = { openpic_buggy_read, - openpic_buggy_read, - openpic_cpu_read, - }, - }, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static const MemoryRegionOps mpic_ext_ops = { - .old_mmio = { - .write = { openpic_buggy_write, - openpic_buggy_write, - mpic_src_ext_write, - }, - .read = { openpic_buggy_read, - openpic_buggy_read, - mpic_src_ext_read, - }, - }, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static const MemoryRegionOps mpic_int_ops = { - .old_mmio = { - .write = { openpic_buggy_write, - openpic_buggy_write, - mpic_src_int_write, - }, - .read = { openpic_buggy_read, - openpic_buggy_read, - mpic_src_int_read, - }, - }, - .endianness = DEVICE_BIG_ENDIAN, +static TypeInfo openpic_info = { + .name = "openpic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(OpenPICState), + .class_init = openpic_class_init, }; -static const MemoryRegionOps mpic_msg_ops = { - .old_mmio = { - .write = { openpic_buggy_write, - openpic_buggy_write, - mpic_src_msg_write, - }, - .read = { openpic_buggy_read, - openpic_buggy_read, - mpic_src_msg_read, - }, - }, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static const MemoryRegionOps mpic_msi_ops = { - .old_mmio = { - .write = { openpic_buggy_write, - openpic_buggy_write, - mpic_src_msi_write, - }, - .read = { openpic_buggy_read, - openpic_buggy_read, - mpic_src_msi_read, - }, - }, - .endianness = DEVICE_BIG_ENDIAN, -}; - -qemu_irq *mpic_init (MemoryRegion *address_space, target_phys_addr_t base, - int nb_cpus, qemu_irq **irqs, qemu_irq irq_out) +static void openpic_register_types(void) { - openpic_t *mpp; - int i; - struct { - const char *name; - MemoryRegionOps const *ops; - target_phys_addr_t start_addr; - ram_addr_t size; - } const list[] = { - {"glb", &mpic_glb_ops, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE}, - {"tmr", &mpic_tmr_ops, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE}, - {"ext", &mpic_ext_ops, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE}, - {"int", &mpic_int_ops, MPIC_INT_REG_START, MPIC_INT_REG_SIZE}, - {"msg", &mpic_msg_ops, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE}, - {"msi", &mpic_msi_ops, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE}, - {"cpu", &mpic_cpu_ops, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE}, - }; - - mpp = g_malloc0(sizeof(openpic_t)); - - memory_region_init(&mpp->mem, "mpic", 0x40000); - memory_region_add_subregion(address_space, base, &mpp->mem); - - for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) { - - memory_region_init_io(&mpp->sub_io_mem[i], list[i].ops, mpp, - list[i].name, list[i].size); - - memory_region_add_subregion(&mpp->mem, list[i].start_addr, - &mpp->sub_io_mem[i]); - } - - mpp->nb_cpus = nb_cpus; - mpp->max_irq = MPIC_MAX_IRQ; - mpp->irq_ipi0 = MPIC_IPI_IRQ; - mpp->irq_tim0 = MPIC_TMR_IRQ; - - for (i = 0; i < nb_cpus; i++) - mpp->dst[i].irqs = irqs[i]; - mpp->irq_out = irq_out; - - mpp->irq_raise = mpic_irq_raise; - mpp->reset = mpic_reset; - - register_savevm(NULL, "mpic", 0, 2, openpic_save, openpic_load, mpp); - qemu_register_reset(mpic_reset, mpp); - - return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq); + type_register_static(&openpic_info); } + +type_init(openpic_register_types) diff --git a/hw/openpic.h b/hw/openpic.h index 855603026b..e226d7b563 100644 --- a/hw/openpic.h +++ b/hw/openpic.h @@ -11,8 +11,7 @@ enum { OPENPIC_OUTPUT_NB, }; -qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus, - qemu_irq **irqs, qemu_irq irq_out); -qemu_irq *mpic_init (MemoryRegion *address_space, target_phys_addr_t base, - int nb_cpus, qemu_irq **irqs, qemu_irq irq_out); +#define OPENPIC_MODEL_RAVEN 0 +#define OPENPIC_MODEL_FSL_MPIC_20 1 + #endif /* __OPENPIC_H__ */ diff --git a/hw/openrisc_sim.c b/hw/openrisc_sim.c index 55e97f0959..d2b2379ae2 100644 --- a/hw/openrisc_sim.c +++ b/hw/openrisc_sim.c @@ -21,12 +21,13 @@ #include "hw.h" #include "boards.h" #include "elf.h" -#include "pc.h" +#include "serial.h" +#include "net/net.h" #include "loader.h" -#include "exec-memory.h" -#include "sysemu.h" +#include "exec/address-spaces.h" +#include "sysemu/sysemu.h" #include "sysbus.h" -#include "qtest.h" +#include "sysemu/qtest.h" #define KERNEL_LOAD_ADDR 0x100 @@ -38,8 +39,8 @@ static void main_cpu_reset(void *opaque) } static void openrisc_sim_net_init(MemoryRegion *address_space, - target_phys_addr_t base, - target_phys_addr_t descriptors, + hwaddr base, + hwaddr descriptors, qemu_irq irq, NICInfo *nd) { DeviceState *dev; @@ -63,7 +64,7 @@ static void cpu_openrisc_load_kernel(ram_addr_t ram_size, { long kernel_size; uint64_t elf_entry; - target_phys_addr_t entry; + hwaddr entry; if (kernel_filename && !qtest_enabled()) { kernel_size = load_elf(kernel_filename, NULL, NULL, @@ -90,13 +91,11 @@ static void cpu_openrisc_load_kernel(ram_addr_t ram_size, cpu->env.pc = entry; } -static void openrisc_sim_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void openrisc_sim_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; OpenRISCCPU *cpu = NULL; MemoryRegion *ram; int n; diff --git a/hw/openrisc_timer.c b/hw/openrisc_timer.c index 7916e61d24..d965be77de 100644 --- a/hw/openrisc_timer.c +++ b/hw/openrisc_timer.c @@ -20,7 +20,7 @@ #include "cpu.h" #include "hw.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #define TIMER_FREQ (20 * 1000 * 1000) /* 20MHz */ @@ -18,34 +18,34 @@ */ #include "hw.h" #include "audio/audio.h" -#include "sysemu.h" -#include "console.h" +#include "sysemu/sysemu.h" +#include "ui/console.h" #include "omap.h" #include "boards.h" #include "arm-misc.h" #include "devices.h" #include "loader.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" -static uint32_t static_readb(void *opaque, target_phys_addr_t offset) +static uint32_t static_readb(void *opaque, hwaddr offset) { uint32_t *val = (uint32_t *) opaque; return *val >> ((offset & 3) << 3); } -static uint32_t static_readh(void *opaque, target_phys_addr_t offset) +static uint32_t static_readh(void *opaque, hwaddr offset) { uint32_t *val = (uint32_t *) opaque; return *val >> ((offset & 1) << 3); } -static uint32_t static_readw(void *opaque, target_phys_addr_t offset) +static uint32_t static_readw(void *opaque, hwaddr offset) { uint32_t *val = (uint32_t *) opaque; return *val >> ((offset & 0) << 3); } -static void static_write(void *opaque, target_phys_addr_t offset, +static void static_write(void *opaque, hwaddr offset, uint32_t value) { #ifdef SPY @@ -190,11 +190,12 @@ static struct arm_boot_info palmte_binfo = { .board_id = 0x331, }; -static void palmte_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void palmte_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; MemoryRegion *address_space_mem = get_system_memory(); struct omap_mpu_state_s *mpu; int flash_size = 0x00800000; @@ -272,7 +273,7 @@ static void palmte_init(ram_addr_t ram_size, will set the size once configured, so this just sets an initial size until the guest activates the display. */ ds->surface = qemu_resize_displaysurface(ds, 320, 320); - dpy_resize(ds); + dpy_gfx_resize(ds); } static QEMUMachine palmte_machine = { diff --git a/hw/pam.c b/hw/pam.c new file mode 100644 index 0000000000..1d72e88e62 --- /dev/null +++ b/hw/pam.c @@ -0,0 +1,87 @@ +/* + * QEMU i440FX/PIIX3 PCI Bridge Emulation + * + * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2011 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * Copyright (c) 2012 Jason Baron <jbaron@redhat.com> + * + * Split out from piix_pci.c + * + * 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. + */ +#include "sysemu/sysemu.h" +#include "pam.h" + +void smram_update(MemoryRegion *smram_region, uint8_t smram, + uint8_t smm_enabled) +{ + bool smram_enabled; + + smram_enabled = ((smm_enabled && (smram & SMRAM_G_SMRAME)) || + (smram & SMRAM_D_OPEN)); + memory_region_set_enabled(smram_region, !smram_enabled); +} + +void smram_set_smm(uint8_t *host_smm_enabled, int smm, uint8_t smram, + MemoryRegion *smram_region) +{ + uint8_t smm_enabled = (smm != 0); + if (*host_smm_enabled != smm_enabled) { + *host_smm_enabled = smm_enabled; + smram_update(smram_region, smram, *host_smm_enabled); + } +} + +void init_pam(MemoryRegion *ram_memory, MemoryRegion *system_memory, + MemoryRegion *pci_address_space, PAMMemoryRegion *mem, + uint32_t start, uint32_t size) +{ + int i; + + /* RAM */ + memory_region_init_alias(&mem->alias[3], "pam-ram", ram_memory, + start, size); + /* ROM (XXX: not quite correct) */ + memory_region_init_alias(&mem->alias[1], "pam-rom", ram_memory, + start, size); + memory_region_set_readonly(&mem->alias[1], true); + + /* XXX: should distinguish read/write cases */ + memory_region_init_alias(&mem->alias[0], "pam-pci", pci_address_space, + start, size); + memory_region_init_alias(&mem->alias[2], "pam-pci", pci_address_space, + start, size); + + for (i = 0; i < 4; ++i) { + memory_region_set_enabled(&mem->alias[i], false); + memory_region_add_subregion_overlap(system_memory, start, + &mem->alias[i], 1); + } + mem->current = 0; +} + +void pam_update(PAMMemoryRegion *pam, int idx, uint8_t val) +{ + assert(0 <= idx && idx <= 12); + + memory_region_set_enabled(&pam->alias[pam->current], false); + pam->current = (val >> ((!(idx & 1)) * 4)) & PAM_ATTR_MASK; + memory_region_set_enabled(&pam->alias[pam->current], true); +} diff --git a/hw/pam.h b/hw/pam.h new file mode 100644 index 0000000000..8e9e349b1d --- /dev/null +++ b/hw/pam.h @@ -0,0 +1,97 @@ +#ifndef QEMU_PAM_H +#define QEMU_PAM_H + +/* + * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2011 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * Copyright (c) 2012 Jason Baron <jbaron@redhat.com> + * + * Split out from piix_pci.c + * + * 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. + */ + +/* + * SMRAM memory area and PAM memory area in Legacy address range for PC. + * PAM: Programmable Attribute Map registers + * + * 0xa0000 - 0xbffff compatible SMRAM + * + * 0xc0000 - 0xc3fff Expansion area memory segments + * 0xc4000 - 0xc7fff + * 0xc8000 - 0xcbfff + * 0xcc000 - 0xcffff + * 0xd0000 - 0xd3fff + * 0xd4000 - 0xd7fff + * 0xd8000 - 0xdbfff + * 0xdc000 - 0xdffff + * 0xe0000 - 0xe3fff Extended System BIOS Area Memory Segments + * 0xe4000 - 0xe7fff + * 0xe8000 - 0xebfff + * 0xec000 - 0xeffff + * + * 0xf0000 - 0xfffff System BIOS Area Memory Segments + */ + +#include "qemu-common.h" +#include "exec/memory.h" + +#define SMRAM_C_BASE 0xa0000 +#define SMRAM_C_END 0xc0000 +#define SMRAM_C_SIZE 0x20000 + +#define PAM_EXPAN_BASE 0xc0000 +#define PAM_EXPAN_SIZE 0x04000 + +#define PAM_EXBIOS_BASE 0xe0000 +#define PAM_EXBIOS_SIZE 0x04000 + +#define PAM_BIOS_BASE 0xf0000 +#define PAM_BIOS_END 0xfffff +/* 64KB: Intel 3 series express chipset family p. 58*/ +#define PAM_BIOS_SIZE 0x10000 + +/* PAM registers: log nibble and high nibble*/ +#define PAM_ATTR_WE ((uint8_t)2) +#define PAM_ATTR_RE ((uint8_t)1) +#define PAM_ATTR_MASK ((uint8_t)3) + +/* SMRAM register */ +#define SMRAM_D_OPEN ((uint8_t)(1 << 6)) +#define SMRAM_D_CLS ((uint8_t)(1 << 5)) +#define SMRAM_D_LCK ((uint8_t)(1 << 4)) +#define SMRAM_G_SMRAME ((uint8_t)(1 << 3)) +#define SMRAM_C_BASE_SEG_MASK ((uint8_t)0x7) +#define SMRAM_C_BASE_SEG ((uint8_t)0x2) /* hardwired to b010 */ + +typedef struct PAMMemoryRegion { + MemoryRegion alias[4]; /* index = PAM value */ + unsigned current; +} PAMMemoryRegion; + +void smram_update(MemoryRegion *smram_region, uint8_t smram, + uint8_t smm_enabled); +void smram_set_smm(uint8_t *host_smm_enabled, int smm, uint8_t smram, + MemoryRegion *smram_region); +void init_pam(MemoryRegion *ram, MemoryRegion *system, MemoryRegion *pci, + PAMMemoryRegion *mem, uint32_t start, uint32_t size); +void pam_update(PAMMemoryRegion *mem, int idx, uint8_t val); + +#endif /* QEMU_PAM_H */ diff --git a/hw/parallel.c b/hw/parallel.c index 219f38436f..64a46c6055 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -23,10 +23,10 @@ * THE SOFTWARE. */ #include "hw.h" -#include "qemu-char.h" +#include "char/char.h" #include "isa.h" #include "pc.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" //#define DEBUG_PARALLEL @@ -511,7 +511,7 @@ static int parallel_isa_initfn(ISADevice *dev) } /* Memory mapped interface */ -static uint32_t parallel_mm_readb (void *opaque, target_phys_addr_t addr) +static uint32_t parallel_mm_readb (void *opaque, hwaddr addr) { ParallelState *s = opaque; @@ -519,14 +519,14 @@ static uint32_t parallel_mm_readb (void *opaque, target_phys_addr_t addr) } static void parallel_mm_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { ParallelState *s = opaque; parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFF); } -static uint32_t parallel_mm_readw (void *opaque, target_phys_addr_t addr) +static uint32_t parallel_mm_readw (void *opaque, hwaddr addr) { ParallelState *s = opaque; @@ -534,14 +534,14 @@ static uint32_t parallel_mm_readw (void *opaque, target_phys_addr_t addr) } static void parallel_mm_writew (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { ParallelState *s = opaque; parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFFFF); } -static uint32_t parallel_mm_readl (void *opaque, target_phys_addr_t addr) +static uint32_t parallel_mm_readl (void *opaque, hwaddr addr) { ParallelState *s = opaque; @@ -549,7 +549,7 @@ static uint32_t parallel_mm_readl (void *opaque, target_phys_addr_t addr) } static void parallel_mm_writel (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { ParallelState *s = opaque; @@ -566,7 +566,7 @@ static const MemoryRegionOps parallel_mm_ops = { /* If fd is zero, it means that the parallel device uses the console */ bool parallel_mm_init(MemoryRegion *address_space, - target_phys_addr_t base, int it_shift, qemu_irq irq, + hwaddr base, int it_shift, qemu_irq irq, CharDriverState *chr) { ParallelState *s; diff --git a/hw/pc-testdev.c b/hw/pc-testdev.c new file mode 100644 index 0000000000..192848998c --- /dev/null +++ b/hw/pc-testdev.c @@ -0,0 +1,187 @@ +/* + * QEMU x86 ISA testdev + * + * Copyright (c) 2012 Avi Kivity, Gerd Hoffmann, Marcelo Tosatti + * + * 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. + */ + +/* + * This device is used to test KVM features specific to the x86 port, such + * as emulation, power management, interrupt routing, among others. It's meant + * to be used like: + * + * qemu-system-x86_64 -device pc-testdev -serial stdio \ + * -device isa-debug-exit,iobase=0xf4,iosize=0x4 \ + * -kernel /home/lmr/Code/virt-test.git/kvm/unittests/msr.flat + * + * Where msr.flat is one of the KVM unittests, present on a separate repo, + * git://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git +*/ + +#include "config-host.h" +#if defined(CONFIG_POSIX) +#include <sys/mman.h> +#endif +#include "hw.h" +#include "qdev.h" +#include "isa.h" + +#define IOMEM_LEN 0x10000 + +typedef struct PCTestdev { + ISADevice parent_obj; + + MemoryRegion ioport; + MemoryRegion flush; + MemoryRegion irq; + MemoryRegion iomem; + uint32_t ioport_data; + char iomem_buf[IOMEM_LEN]; +} PCTestdev; + +#define TYPE_TESTDEV "pc-testdev" +#define TESTDEV(obj) \ + OBJECT_CHECK(struct PCTestdev, (obj), TYPE_TESTDEV) + +static void test_irq_line(void *opaque, hwaddr addr, uint64_t data, + unsigned len) +{ + struct PCTestdev *dev = opaque; + struct ISADevice *isa = ISA_DEVICE(dev); + + qemu_set_irq(isa_get_irq(isa, addr), !!data); +} + +static const MemoryRegionOps test_irq_ops = { + .write = test_irq_line, + .valid.min_access_size = 1, + .valid.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void test_ioport_write(void *opaque, hwaddr addr, uint64_t data, + unsigned len) +{ + struct PCTestdev *dev = opaque; + dev->ioport_data = data; +} + +static uint64_t test_ioport_read(void *opaque, hwaddr addr, unsigned len) +{ + struct PCTestdev *dev = opaque; + return dev->ioport_data; +} + +static const MemoryRegionOps test_ioport_ops = { + .read = test_ioport_read, + .write = test_ioport_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void test_flush_page(void *opaque, hwaddr addr, uint64_t data, + unsigned len) +{ + hwaddr page = 4096; + void *a = cpu_physical_memory_map(data & ~0xffful, &page, 0); + + /* We might not be able to get the full page, only mprotect what we actually + have mapped */ +#if defined(CONFIG_POSIX) + mprotect(a, page, PROT_NONE); + mprotect(a, page, PROT_READ|PROT_WRITE); +#endif + cpu_physical_memory_unmap(a, page, 0, 0); +} + +static const MemoryRegionOps test_flush_ops = { + .write = test_flush_page, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static uint64_t test_iomem_read(void *opaque, hwaddr addr, unsigned len) +{ + struct PCTestdev *dev = opaque; + uint64_t ret = 0; + memcpy(&ret, &dev->iomem_buf[addr], len); + ret = le64_to_cpu(ret); + + return ret; +} + +static void test_iomem_write(void *opaque, hwaddr addr, uint64_t val, + unsigned len) +{ + struct PCTestdev *dev = opaque; + val = cpu_to_le64(val); + memcpy(&dev->iomem_buf[addr], &val, len); + dev->iomem_buf[addr] = val; +} + +static const MemoryRegionOps test_iomem_ops = { + .read = test_iomem_read, + .write = test_iomem_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static int init_test_device(ISADevice *isa) +{ + struct PCTestdev *dev = TESTDEV(isa); + MemoryRegion *mem = isa_address_space(isa); + MemoryRegion *io = isa_address_space_io(isa); + + memory_region_init_io(&dev->ioport, &test_ioport_ops, dev, + "pc-testdev-ioport", 4); + memory_region_init_io(&dev->flush, &test_flush_ops, dev, + "pc-testdev-flush-page", 4); + memory_region_init_io(&dev->irq, &test_irq_ops, dev, + "pc-testdev-irq-line", 24); + memory_region_init_io(&dev->iomem, &test_iomem_ops, dev, + "pc-testdev-iomem", IOMEM_LEN); + + memory_region_add_subregion(io, 0xe0, &dev->ioport); + memory_region_add_subregion(io, 0xe4, &dev->flush); + memory_region_add_subregion(io, 0x2000, &dev->irq); + memory_region_add_subregion(mem, 0xff000000, &dev->iomem); + + return 0; +} + +static void testdev_class_init(ObjectClass *klass, void *data) +{ + ISADeviceClass *k = ISA_DEVICE_CLASS(klass); + + k->init = init_test_device; +} + +static TypeInfo testdev_info = { + .name = TYPE_TESTDEV, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(struct PCTestdev), + .class_init = testdev_class_init, +}; + +static void testdev_register_types(void) +{ + type_register_static(&testdev_info); +} + +type_init(testdev_register_types) @@ -23,12 +23,12 @@ */ #include "hw.h" #include "pc.h" +#include "serial.h" #include "apic.h" #include "fdc.h" #include "ide.h" -#include "pci.h" -#include "vmware_vga.h" -#include "monitor.h" +#include "pci/pci.h" +#include "monitor/monitor.h" #include "fw_cfg.h" #include "hpet_emul.h" #include "smbios.h" @@ -38,22 +38,19 @@ #include "mc146818rtc.h" #include "i8254.h" #include "pcspk.h" -#include "msi.h" +#include "pci/msi.h" #include "sysbus.h" -#include "sysemu.h" -#include "kvm.h" +#include "sysemu/sysemu.h" +#include "sysemu/kvm.h" #include "kvm_i386.h" #include "xen.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "hw/block-common.h" #include "ui/qemu-spice.h" -#include "memory.h" -#include "exec-memory.h" -#include "arch_init.h" -#include "bitmap.h" - -/* output Bochs bios info messages */ -//#define DEBUG_BIOS +#include "exec/memory.h" +#include "exec/address-spaces.h" +#include "sysemu/arch_init.h" +#include "qemu/bitmap.h" /* debug PC/ISA interrupts */ //#define DEBUG_IRQ @@ -74,8 +71,6 @@ #define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3) #define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4) -#define MSI_ADDR_BASE 0xfee00000 - #define E820_NR_ENTRIES 16 struct e820_entry { @@ -103,7 +98,8 @@ void gsi_handler(void *opaque, int n, int level) qemu_set_irq(s->ioapic_irq[n], level); } -static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) +static void ioport80_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) { } @@ -121,7 +117,8 @@ void cpu_set_ferr(CPUX86State *s) qemu_irq_raise(ferr_irq); } -static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data) +static void ioportF0_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) { qemu_irq_lower(ferr_irq); } @@ -337,32 +334,37 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, /* various important CMOS locations needed by PC/Bochs bios */ /* memory size */ - val = 640; /* base memory in K */ + /* base memory (first MiB) */ + val = MIN(ram_size / 1024, 640); rtc_set_memory(s, 0x15, val); rtc_set_memory(s, 0x16, val >> 8); - - val = (ram_size / 1024) - 1024; + /* extended memory (next 64MiB) */ + if (ram_size > 1024 * 1024) { + val = (ram_size - 1024 * 1024) / 1024; + } else { + val = 0; + } if (val > 65535) val = 65535; rtc_set_memory(s, 0x17, val); rtc_set_memory(s, 0x18, val >> 8); rtc_set_memory(s, 0x30, val); rtc_set_memory(s, 0x31, val >> 8); - - if (above_4g_mem_size) { - rtc_set_memory(s, 0x5b, (unsigned int)above_4g_mem_size >> 16); - rtc_set_memory(s, 0x5c, (unsigned int)above_4g_mem_size >> 24); - rtc_set_memory(s, 0x5d, (uint64_t)above_4g_mem_size >> 32); - } - - if (ram_size > (16 * 1024 * 1024)) - val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); - else + /* memory between 16MiB and 4GiB */ + if (ram_size > 16 * 1024 * 1024) { + val = (ram_size - 16 * 1024 * 1024) / 65536; + } else { val = 0; + } if (val > 65535) val = 65535; rtc_set_memory(s, 0x34, val); rtc_set_memory(s, 0x35, val >> 8); + /* memory above 4GiB */ + val = above_4g_mem_size / 65536; + rtc_set_memory(s, 0x5b, val); + rtc_set_memory(s, 0x5c, val >> 8); + rtc_set_memory(s, 0x5d, val >> 16); /* set the number of CPU */ rtc_set_memory(s, 0x5f, smp_cpus - 1); @@ -419,7 +421,8 @@ typedef struct Port92State { qemu_irq *a20_out; } Port92State; -static void port92_write(void *opaque, uint32_t addr, uint32_t val) +static void port92_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) { Port92State *s = opaque; @@ -431,7 +434,8 @@ static void port92_write(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t port92_read(void *opaque, uint32_t addr) +static uint64_t port92_read(void *opaque, hwaddr addr, + unsigned size) { Port92State *s = opaque; uint32_t ret; @@ -466,13 +470,14 @@ static void port92_reset(DeviceState *d) s->outport &= ~1; } -static const MemoryRegionPortio port92_portio[] = { - { 0, 1, 1, .read = port92_read, .write = port92_write }, - PORTIO_END_OF_LIST(), -}; - static const MemoryRegionOps port92_ops = { - .old_portio = port92_portio + .read = port92_read, + .write = port92_write, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static int port92_initfn(ISADevice *dev) @@ -519,52 +524,6 @@ static void handle_a20_line_change(void *opaque, int irq, int level) cpu_x86_set_a20(cpu, level); } -/***********************************************************/ -/* Bochs BIOS debug ports */ - -static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) -{ - static const char shutdown_str[8] = "Shutdown"; - static int shutdown_index = 0; - - switch(addr) { - /* Bochs BIOS messages */ - case 0x400: - case 0x401: - /* used to be panic, now unused */ - break; - case 0x402: - case 0x403: -#ifdef DEBUG_BIOS - fprintf(stderr, "%c", val); -#endif - break; - case 0x8900: - /* same as Bochs power off */ - if (val == shutdown_str[shutdown_index]) { - shutdown_index++; - if (shutdown_index == 8) { - shutdown_index = 0; - qemu_system_shutdown_request(); - } - } else { - shutdown_index = 0; - } - break; - - /* LGPL'ed VGA BIOS messages */ - case 0x501: - case 0x502: - exit((val << 1) | 1); - case 0x500: - case 0x503: -#ifdef DEBUG_BIOS - fprintf(stderr, "%c", val); -#endif - break; - } -} - int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) { int index = le32_to_cpu(e820_table.count); @@ -590,18 +549,6 @@ static void *bochs_bios_init(void) uint64_t *numa_fw_cfg; int i, j; - register_ioport_write(0x400, 1, 2, bochs_bios_write, NULL); - register_ioport_write(0x401, 1, 2, bochs_bios_write, NULL); - register_ioport_write(0x402, 1, 1, bochs_bios_write, NULL); - register_ioport_write(0x403, 1, 1, bochs_bios_write, NULL); - register_ioport_write(0x8900, 1, 1, bochs_bios_write, NULL); - - register_ioport_write(0x501, 1, 1, bochs_bios_write, NULL); - register_ioport_write(0x501, 1, 2, bochs_bios_write, NULL); - register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL); - register_ioport_write(0x500, 1, 1, bochs_bios_write, NULL); - register_ioport_write(0x503, 1, 1, bochs_bios_write, NULL); - fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); @@ -660,13 +607,13 @@ static void load_linux(void *fw_cfg, const char *kernel_filename, const char *initrd_filename, const char *kernel_cmdline, - target_phys_addr_t max_ram_size) + hwaddr max_ram_size) { uint16_t protocol; int setup_size, kernel_size, initrd_size = 0, cmdline_size; uint32_t initrd_max; uint8_t header[8192], *setup, *kernel, *initrd_data; - target_phys_addr_t real_addr, prot_addr, cmdline_addr, initrd_addr = 0; + hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0; FILE *f; char *vmode; @@ -868,35 +815,6 @@ DeviceState *cpu_get_current_apic(void) } } -static DeviceState *apic_init(void *env, uint8_t apic_id) -{ - DeviceState *dev; - static int apic_mapped; - - if (kvm_irqchip_in_kernel()) { - dev = qdev_create(NULL, "kvm-apic"); - } else if (xen_enabled()) { - dev = qdev_create(NULL, "xen-apic"); - } else { - dev = qdev_create(NULL, "apic"); - } - - qdev_prop_set_uint8(dev, "id", apic_id); - qdev_prop_set_ptr(dev, "cpu_env", env); - qdev_init_nofail(dev); - - /* XXX: mapping more APICs at the same memory location */ - if (apic_mapped == 0) { - /* NOTE: the APIC is directly connected to the CPU - it is not - on the global memory bus. */ - /* XXX: what if the base changes? */ - sysbus_mmio_map(sysbus_from_qdev(dev), 0, MSI_ADDR_BASE); - apic_mapped = 1; - } - - return dev; -} - void pc_acpi_smi_interrupt(void *opaque, int irq, int level) { CPUX86State *s = opaque; @@ -906,24 +824,6 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level) } } -static X86CPU *pc_new_cpu(const char *cpu_model) -{ - X86CPU *cpu; - CPUX86State *env; - - cpu = cpu_x86_init(cpu_model); - if (cpu == NULL) { - fprintf(stderr, "Unable to find x86 CPU definition\n"); - exit(1); - } - env = &cpu->env; - if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) { - env->apic_state = apic_init(env, env->cpuid_apic_id); - } - cpu_reset(CPU(cpu)); - return cpu; -} - void pc_cpus_init(const char *cpu_model) { int i; @@ -937,11 +837,37 @@ void pc_cpus_init(const char *cpu_model) #endif } - for(i = 0; i < smp_cpus; i++) { - pc_new_cpu(cpu_model); + for (i = 0; i < smp_cpus; i++) { + if (!cpu_x86_init(cpu_model)) { + fprintf(stderr, "Unable to find x86 CPU definition\n"); + exit(1); + } } } +void pc_acpi_init(const char *default_dsdt) +{ + char *filename = NULL, *arg = NULL; + + if (acpi_tables != NULL) { + /* manually set via -acpitable, leave it alone */ + return; + } + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, default_dsdt); + if (filename == NULL) { + fprintf(stderr, "WARNING: failed to find %s\n", default_dsdt); + return; + } + + arg = g_strdup_printf("file=%s", filename); + if (acpi_table_add(arg) != 0) { + fprintf(stderr, "WARNING: failed to load %s\n", filename); + } + g_free(arg); + g_free(filename); +} + void *pc_memory_init(MemoryRegion *system_memory, const char *kernel_filename, const char *kernel_cmdline, @@ -1013,34 +939,13 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus) { DeviceState *dev = NULL; - if (cirrus_vga_enabled) { - if (pci_bus) { - dev = pci_cirrus_vga_init(pci_bus); - } else { - dev = &isa_create_simple(isa_bus, "isa-cirrus-vga")->qdev; - } - } else if (vmsvga_enabled) { - if (pci_bus) { - dev = pci_vmsvga_init(pci_bus); - } else { - fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); - } -#ifdef CONFIG_SPICE - } else if (qxl_enabled) { - if (pci_bus) { - dev = &pci_create_simple(pci_bus, -1, "qxl-vga")->qdev; - } else { - fprintf(stderr, "%s: qxl: no PCI bus\n", __FUNCTION__); - } -#endif - } else if (std_vga_enabled) { - if (pci_bus) { - dev = pci_vga_init(pci_bus); - } else { - dev = isa_vga_init(isa_bus); - } + if (pci_bus) { + PCIDevice *pcidev = pci_vga_init(pci_bus); + dev = pcidev ? &pcidev->qdev : NULL; + } else if (isa_bus) { + ISADevice *isadev = isa_vga_init(isa_bus); + dev = isadev ? &isadev->qdev : NULL; } - return dev; } @@ -1053,6 +958,24 @@ static void cpu_request_exit(void *opaque, int irq, int level) } } +static const MemoryRegionOps ioport80_io_ops = { + .write = ioport80_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static const MemoryRegionOps ioportF0_io_ops = { + .write = ioportF0_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, ISADevice **rtc_state, ISADevice **floppy, @@ -1067,10 +990,14 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, qemu_irq *a20_line; ISADevice *i8042, *port92, *vmmouse, *pit = NULL; qemu_irq *cpu_exit_irq; + MemoryRegion *ioport80_io = g_new(MemoryRegion, 1); + MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1); - register_ioport_write(0x80, 1, 1, ioport80_write, NULL); + memory_region_init_io(ioport80_io, &ioport80_io_ops, NULL, "ioport80", 1); + memory_region_add_subregion(isa_bus->address_space_io, 0x80, ioport80_io); - register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL); + memory_region_init_io(ioportF0_io, &ioportF0_io_ops, NULL, "ioportF0", 1); + memory_region_add_subregion(isa_bus->address_space_io, 0xf0, ioportF0_io); /* * Check if an HPET shall be created. @@ -1144,6 +1071,21 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, *floppy = fdctrl_init_isa(isa_bus, fd); } +void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus) +{ + int i; + + for (i = 0; i < nb_nics; i++) { + NICInfo *nd = &nd_table[i]; + + if (!pci_bus || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) { + pc_init_ne2k_isa(isa_bus, nd); + } else { + pci_nic_init_nofail(nd, "e1000", NULL); + } + } +} + void pc_pci_device_init(PCIBus *pci_bus) { int max_bus; @@ -1154,3 +1096,27 @@ void pc_pci_device_init(PCIBus *pci_bus) pci_create_simple(pci_bus, -1, "lsi53c895a"); } } + +void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name) +{ + DeviceState *dev; + SysBusDevice *d; + unsigned int i; + + if (kvm_irqchip_in_kernel()) { + dev = qdev_create(NULL, "kvm-ioapic"); + } else { + dev = qdev_create(NULL, "ioapic"); + } + if (parent_name) { + object_property_add_child(object_resolve_path(parent_name, NULL), + "ioapic", OBJECT(dev), NULL); + } + qdev_init_nofail(dev); + d = sysbus_from_qdev(dev); + sysbus_mmio_map(d, 0, 0xfec00000); + + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i); + } +} @@ -2,43 +2,16 @@ #define HW_PC_H #include "qemu-common.h" -#include "memory.h" -#include "ioport.h" +#include "exec/memory.h" +#include "exec/ioport.h" #include "isa.h" #include "fdc.h" -#include "net.h" -#include "memory.h" +#include "net/net.h" +#include "exec/memory.h" #include "ioapic.h" /* PC-style peripherals (also used by other machines). */ -/* serial.c */ - -SerialState *serial_init(int base, qemu_irq irq, int baudbase, - CharDriverState *chr); -SerialState *serial_mm_init(MemoryRegion *address_space, - target_phys_addr_t base, int it_shift, - qemu_irq irq, int baudbase, - CharDriverState *chr, enum device_endian); -static inline bool serial_isa_init(ISABus *bus, int index, - CharDriverState *chr) -{ - ISADevice *dev; - - dev = isa_try_create(bus, "isa-serial"); - if (!dev) { - return false; - } - qdev_prop_set_uint32(&dev->qdev, "index", index); - qdev_prop_set_chr(&dev->qdev, "chardev", chr); - if (qdev_init(&dev->qdev) < 0) { - return false; - } - return true; -} - -void serial_set_frequency(SerialState *s, uint32_t frequency); - /* parallel.c */ static inline bool parallel_init(ISABus *bus, int index, CharDriverState *chr) { @@ -57,7 +30,7 @@ static inline bool parallel_init(ISABus *bus, int index, CharDriverState *chr) } bool parallel_mm_init(MemoryRegion *address_space, - target_phys_addr_t base, int it_shift, qemu_irq irq, + hwaddr base, int it_shift, qemu_irq irq, CharDriverState *chr); /* i8259.c */ @@ -95,7 +68,7 @@ void vmmouse_set_data(const uint32_t *data); void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base); void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, MemoryRegion *region, ram_addr_t size, - target_phys_addr_t mask); + hwaddr mask); void i8042_isa_mouse_fake_event(void *opaque); void i8042_setup_a20_line(ISADevice *dev, qemu_irq *a20_out); @@ -106,6 +79,7 @@ void pc_register_ferr_irq(qemu_irq irq); void pc_acpi_smi_interrupt(void *opaque, int irq, int level); void pc_cpus_init(const char *cpu_model); +void pc_acpi_init(const char *default_dsdt); void *pc_memory_init(MemoryRegion *system_memory, const char *kernel_filename, const char *kernel_cmdline, @@ -125,11 +99,14 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, const char *boot_device, ISADevice *floppy, BusState *ide0, BusState *ide1, ISADevice *s); +void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus); void pc_pci_device_init(PCIBus *pci_bus); typedef void (*cpu_set_smm_t)(int smm, void *arg); void cpu_smm_register(cpu_set_smm_t callback, void *arg); +void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name); + /* acpi.c */ extern int acpi_enabled; extern char *acpi_tables; @@ -157,10 +134,10 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, ram_addr_t ram_size, - target_phys_addr_t pci_hole_start, - target_phys_addr_t pci_hole_size, - target_phys_addr_t pci_hole64_start, - target_phys_addr_t pci_hole64_size, + hwaddr pci_hole_start, + hwaddr pci_hole_size, + hwaddr pci_hole64_start, + hwaddr pci_hole64_size, MemoryRegion *pci_memory, MemoryRegion *ram_memory); @@ -176,27 +153,10 @@ enum vga_retrace_method { extern enum vga_retrace_method vga_retrace_method; -static inline DeviceState *isa_vga_init(ISABus *bus) -{ - ISADevice *dev; - - dev = isa_try_create(bus, "isa-vga"); - if (!dev) { - fprintf(stderr, "Warning: isa-vga not available\n"); - return NULL; - } - qdev_init_nofail(&dev->qdev); - return &dev->qdev; -} - -DeviceState *pci_vga_init(PCIBus *bus); -int isa_vga_mm_init(target_phys_addr_t vram_base, - target_phys_addr_t ctrl_base, int it_shift, +int isa_vga_mm_init(hwaddr vram_base, + hwaddr ctrl_base, int it_shift, MemoryRegion *address_space); -/* cirrus_vga.c */ -DeviceState *pci_cirrus_vga_init(PCIBus *bus); - /* ne2000.c */ static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd) { diff --git a/hw/pc87312.c b/hw/pc87312.c index b5fa01681b..6a17afd45c 100644 --- a/hw/pc87312.c +++ b/hw/pc87312.c @@ -24,8 +24,9 @@ */ #include "pc87312.h" -#include "blockdev.h" -#include "sysemu.h" +#include "sysemu/blockdev.h" +#include "sysemu/sysemu.h" +#include "char/char.h" #include "trace.h" diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 0c0096fd7e..2b3d58b852 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -27,22 +27,23 @@ #include "hw.h" #include "pc.h" #include "apic.h" -#include "pci.h" -#include "pci_ids.h" +#include "pci/pci.h" +#include "pci/pci_ids.h" #include "usb.h" -#include "net.h" +#include "net/net.h" #include "boards.h" #include "ide.h" -#include "kvm.h" +#include "sysemu/kvm.h" #include "kvm/clock.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "sysbus.h" -#include "arch_init.h" -#include "blockdev.h" +#include "sysemu/arch_init.h" +#include "sysemu/blockdev.h" #include "smbus.h" #include "xen.h" -#include "memory.h" -#include "exec-memory.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" +#include "cpu.h" #ifdef CONFIG_XEN # include <xen/hvm/hvm_info_table.h> #endif @@ -53,70 +54,6 @@ static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 }; static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 }; static const int ide_irq[MAX_IDE_BUS] = { 14, 15 }; -static void kvm_piix3_setup_irq_routing(bool pci_enabled) -{ -#ifdef CONFIG_KVM - KVMState *s = kvm_state; - int i; - - if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) { - for (i = 0; i < 8; ++i) { - if (i == 2) { - continue; - } - kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_MASTER, i); - } - for (i = 8; i < 16; ++i) { - kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8); - } - if (pci_enabled) { - for (i = 0; i < 24; ++i) { - if (i == 0) { - kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, 2); - } else if (i != 2) { - kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, i); - } - } - } - } -#endif /* CONFIG_KVM */ -} - -static void kvm_piix3_gsi_handler(void *opaque, int n, int level) -{ - GSIState *s = opaque; - - if (n < ISA_NUM_IRQS) { - /* Kernel will forward to both PIC and IOAPIC */ - qemu_set_irq(s->i8259_irq[n], level); - } else { - qemu_set_irq(s->ioapic_irq[n], level); - } -} - -static void ioapic_init(GSIState *gsi_state) -{ - DeviceState *dev; - SysBusDevice *d; - unsigned int i; - - if (kvm_irqchip_in_kernel()) { - dev = qdev_create(NULL, "kvm-ioapic"); - } else { - dev = qdev_create(NULL, "ioapic"); - } - /* FIXME: this should be under the piix3. */ - object_property_add_child(object_resolve_path("i440fx", NULL), - "ioapic", OBJECT(dev), NULL); - qdev_init_nofail(dev); - d = sysbus_from_qdev(dev); - sysbus_mmio_map(d, 0, 0xfec00000); - - for (i = 0; i < IOAPIC_NUM_PINS; i++) { - gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i); - } -} - /* PC hardware initialisation */ static void pc_init1(MemoryRegion *system_memory, MemoryRegion *system_io, @@ -150,6 +87,7 @@ static void pc_init1(MemoryRegion *system_memory, void *fw_cfg = NULL; pc_cpus_init(cpu_model); + pc_acpi_init("acpi-dsdt.aml"); if (kvmclock_enabled) { kvmclock_create(); @@ -177,13 +115,13 @@ static void pc_init1(MemoryRegion *system_memory, fw_cfg = pc_memory_init(system_memory, kernel_filename, kernel_cmdline, initrd_filename, below_4g_mem_size, above_4g_mem_size, - pci_enabled ? rom_memory : system_memory, &ram_memory); + rom_memory, &ram_memory); } gsi_state = g_malloc0(sizeof(*gsi_state)); if (kvm_irqchip_in_kernel()) { - kvm_piix3_setup_irq_routing(pci_enabled); - gsi = qemu_allocate_irqs(kvm_piix3_gsi_handler, gsi_state, + kvm_pc_setup_irq_routing(pci_enabled); + gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state, GSI_NUM_PINS); } else { gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS); @@ -195,7 +133,7 @@ static void pc_init1(MemoryRegion *system_memory, below_4g_mem_size, 0x100000000ULL - below_4g_mem_size, 0x100000000ULL + above_4g_mem_size, - (sizeof(target_phys_addr_t) == 4 + (sizeof(hwaddr) == 4 ? 0 : ((uint64_t)1 << 62)), pci_memory, ram_memory); @@ -220,7 +158,7 @@ static void pc_init1(MemoryRegion *system_memory, gsi_state->i8259_irq[i] = i8259[i]; } if (pci_enabled) { - ioapic_init(gsi_state); + ioapic_init_gsi(gsi_state, "i440fx"); } pc_register_ferr_irq(gsi[13]); @@ -233,14 +171,7 @@ static void pc_init1(MemoryRegion *system_memory, /* init basic PC hardware */ pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled()); - for(i = 0; i < nb_nics; i++) { - NICInfo *nd = &nd_table[i]; - - if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) - pc_init_ne2k_isa(isa_bus, nd); - else - pci_nic_init_nofail(nd, "e1000", NULL); - } + pc_nic_init(isa_bus, pci_bus); ide_drive_get(hd, MAX_IDE_BUS); if (pci_enabled) { @@ -267,7 +198,7 @@ static void pc_init1(MemoryRegion *system_memory, pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, floppy, idebus[0], idebus[1], rtc_state); - if (pci_enabled && usb_enabled) { + if (pci_enabled && usb_enabled(false)) { pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci"); } @@ -287,13 +218,14 @@ static void pc_init1(MemoryRegion *system_memory, } } -static void pc_init_pci(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void pc_init_pci(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; pc_init1(get_system_memory(), get_system_io(), ram_size, boot_device, @@ -301,13 +233,20 @@ static void pc_init_pci(ram_addr_t ram_size, initrd_filename, cpu_model, 1, 1); } -static void pc_init_pci_no_kvmclock(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void pc_init_pci_1_3(QEMUMachineInitArgs *args) +{ + enable_kvm_pv_eoi(); + pc_init_pci(args); +} + +static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; pc_init1(get_system_memory(), get_system_io(), ram_size, boot_device, @@ -315,13 +254,14 @@ static void pc_init_pci_no_kvmclock(ram_addr_t ram_size, initrd_filename, cpu_model, 1, 0); } -static void pc_init_isa(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void pc_init_isa(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; if (cpu_model == NULL) cpu_model = "486"; pc_init1(get_system_memory(), @@ -332,34 +272,93 @@ static void pc_init_isa(ram_addr_t ram_size, } #ifdef CONFIG_XEN -static void pc_xen_hvm_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void pc_xen_hvm_init(QEMUMachineInitArgs *args) { if (xen_hvm_init() != 0) { hw_error("xen hardware virtual machine initialisation failed"); } - pc_init_pci_no_kvmclock(ram_size, boot_device, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model); + pc_init_pci_no_kvmclock(args); xen_vcpu_init(); } #endif +static QEMUMachine pc_machine_v1_4 = { + .name = "pc-1.4", + .alias = "pc", + .desc = "Standard PC", + .init = pc_init_pci_1_3, + .max_cpus = 255, + .is_default = 1, +}; + +#define PC_COMPAT_1_3 \ + {\ + .driver = "usb-tablet",\ + .property = "usb_version",\ + .value = stringify(1),\ + } + +static QEMUMachine pc_machine_v1_3 = { + .name = "pc-1.3", + .desc = "Standard PC", + .init = pc_init_pci_1_3, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_1_3, + { /* end of list */ } + }, +}; + +#define PC_COMPAT_1_2 \ + PC_COMPAT_1_3,\ + {\ + .driver = "nec-usb-xhci",\ + .property = "msi",\ + .value = "off",\ + },{\ + .driver = "nec-usb-xhci",\ + .property = "msix",\ + .value = "off",\ + },{\ + .driver = "ivshmem",\ + .property = "use64",\ + .value = "0",\ + },{\ + .driver = "qxl",\ + .property = "revision",\ + .value = stringify(3),\ + },{\ + .driver = "qxl-vga",\ + .property = "revision",\ + .value = stringify(3),\ + },{\ + .driver = "VGA",\ + .property = "mmio",\ + .value = "off",\ + } + static QEMUMachine pc_machine_v1_2 = { .name = "pc-1.2", - .alias = "pc", .desc = "Standard PC", .init = pc_init_pci, .max_cpus = 255, - .is_default = 1, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_1_2, + { /* end of list */ } + }, }; #define PC_COMPAT_1_1 \ + PC_COMPAT_1_2,\ {\ + .driver = "virtio-scsi-pci",\ + .property = "hotplug",\ + .value = "off",\ + },{\ + .driver = "virtio-scsi-pci",\ + .property = "param_change",\ + .value = "off",\ + },{\ .driver = "VGA",\ .property = "vgamem_mb",\ .value = stringify(8),\ @@ -375,6 +374,10 @@ static QEMUMachine pc_machine_v1_2 = { .driver = "qxl",\ .property = "vgamem_mb",\ .value = stringify(8),\ + },{\ + .driver = "virtio-blk-pci",\ + .property = "config-wce",\ + .value = "off",\ } static QEMUMachine pc_machine_v1_1 = { @@ -643,6 +646,8 @@ static QEMUMachine xenfv_machine = { static void pc_machine_init(void) { + qemu_register_machine(&pc_machine_v1_4); + qemu_register_machine(&pc_machine_v1_3); qemu_register_machine(&pc_machine_v1_2); qemu_register_machine(&pc_machine_v1_1); qemu_register_machine(&pc_machine_v1_0); diff --git a/hw/pc_q35.c b/hw/pc_q35.c new file mode 100644 index 0000000000..ef540b6a71 --- /dev/null +++ b/hw/pc_q35.c @@ -0,0 +1,224 @@ +/* + * Q35 chipset based pc system emulator + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2009, 2010 + * Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * Copyright (C) 2012 Jason Baron <jbaron@redhat.com> + * + * This is based on pc.c, but heavily modified. + * + * 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. + */ +#include "hw.h" +#include "sysemu/arch_init.h" +#include "smbus.h" +#include "boards.h" +#include "mc146818rtc.h" +#include "xen.h" +#include "sysemu/kvm.h" +#include "kvm/clock.h" +#include "q35.h" +#include "exec/address-spaces.h" +#include "ich9.h" +#include "hw/ide/pci.h" +#include "hw/ide/ahci.h" +#include "hw/usb.h" + +/* ICH9 AHCI has 6 ports */ +#define MAX_SATA_PORTS 6 + +/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE) + * BIOS will read it and start S3 resume at POST Entry */ +static void pc_cmos_set_s3_resume(void *opaque, int irq, int level) +{ + ISADevice *s = opaque; + + if (level) { + rtc_set_memory(s, 0xF, 0xFE); + } +} + +/* PC hardware initialisation */ +static void pc_q35_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + ram_addr_t below_4g_mem_size, above_4g_mem_size; + Q35PCIHost *q35_host; + PCIBus *host_bus; + PCIDevice *lpc; + BusState *idebus[MAX_SATA_PORTS]; + ISADevice *rtc_state; + ISADevice *floppy; + MemoryRegion *pci_memory; + MemoryRegion *rom_memory; + MemoryRegion *ram_memory; + GSIState *gsi_state; + ISABus *isa_bus; + int pci_enabled = 1; + qemu_irq *cpu_irq; + qemu_irq *gsi; + qemu_irq *i8259; + int i; + ICH9LPCState *ich9_lpc; + PCIDevice *ahci; + qemu_irq *cmos_s3; + + pc_cpus_init(cpu_model); + pc_acpi_init("q35-acpi-dsdt.aml"); + + kvmclock_create(); + + if (ram_size >= 0xb0000000) { + above_4g_mem_size = ram_size - 0xb0000000; + below_4g_mem_size = 0xb0000000; + } else { + above_4g_mem_size = 0; + below_4g_mem_size = ram_size; + } + + /* pci enabled */ + if (pci_enabled) { + pci_memory = g_new(MemoryRegion, 1); + memory_region_init(pci_memory, "pci", INT64_MAX); + rom_memory = pci_memory; + } else { + pci_memory = NULL; + rom_memory = get_system_memory(); + } + + /* allocate ram and load rom/bios */ + if (!xen_enabled()) { + pc_memory_init(get_system_memory(), kernel_filename, kernel_cmdline, + initrd_filename, below_4g_mem_size, above_4g_mem_size, + rom_memory, &ram_memory); + } + + /* irq lines */ + gsi_state = g_malloc0(sizeof(*gsi_state)); + if (kvm_irqchip_in_kernel()) { + kvm_pc_setup_irq_routing(pci_enabled); + gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state, + GSI_NUM_PINS); + } else { + gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS); + } + + /* create pci host bus */ + q35_host = Q35_HOST_DEVICE(qdev_create(NULL, TYPE_Q35_HOST_DEVICE)); + + q35_host->mch.ram_memory = ram_memory; + q35_host->mch.pci_address_space = pci_memory; + q35_host->mch.system_memory = get_system_memory(); + q35_host->mch.address_space_io = get_system_io();; + q35_host->mch.below_4g_mem_size = below_4g_mem_size; + q35_host->mch.above_4g_mem_size = above_4g_mem_size; + /* pci */ + qdev_init_nofail(DEVICE(q35_host)); + host_bus = q35_host->host.pci.bus; + /* create ISA bus */ + lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV, + ICH9_LPC_FUNC), true, + TYPE_ICH9_LPC_DEVICE); + ich9_lpc = ICH9_LPC_DEVICE(lpc); + ich9_lpc->pic = gsi; + ich9_lpc->ioapic = gsi_state->ioapic_irq; + pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc, + ICH9_LPC_NB_PIRQS); + isa_bus = ich9_lpc->isa_bus; + + /*end early*/ + isa_bus_irqs(isa_bus, gsi); + + if (kvm_irqchip_in_kernel()) { + i8259 = kvm_i8259_init(isa_bus); + } else if (xen_enabled()) { + i8259 = xen_interrupt_controller_init(); + } else { + cpu_irq = pc_allocate_cpu_irq(); + i8259 = i8259_init(isa_bus, cpu_irq[0]); + } + + for (i = 0; i < ISA_NUM_IRQS; i++) { + gsi_state->i8259_irq[i] = i8259[i]; + } + if (pci_enabled) { + ioapic_init_gsi(gsi_state, NULL); + } + + pc_register_ferr_irq(gsi[13]); + + /* init basic PC hardware */ + pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, false); + + /* connect pm stuff to lpc */ + cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1); + ich9_lpc_pm_init(lpc, *cmos_s3); + + /* ahci and SATA device, for q35 1 ahci controller is built-in */ + ahci = pci_create_simple_multifunction(host_bus, + PCI_DEVFN(ICH9_SATA1_DEV, + ICH9_SATA1_FUNC), + true, "ich9-ahci"); + idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0"); + idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1"); + + if (usb_enabled(false)) { + /* Should we create 6 UHCI according to ich9 spec? */ + ehci_create_ich9_with_companions(host_bus, 0x1d); + } + + /* TODO: Populate SPD eeprom data. */ + smbus_eeprom_init(ich9_smb_init(host_bus, + PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC), + 0xb100), + 8, NULL, 0); + + pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, + floppy, idebus[0], idebus[1], rtc_state); + + /* the rest devices to which pci devfn is automatically assigned */ + pc_vga_init(isa_bus, host_bus); + audio_init(isa_bus, host_bus); + pc_nic_init(isa_bus, host_bus); + if (pci_enabled) { + pc_pci_device_init(host_bus); + } +} + +static QEMUMachine pc_q35_machine = { + .name = "q35-next", + .alias = "q35", + .desc = "Q35 chipset PC", + .init = pc_q35_init, + .max_cpus = 255, +}; + +static void pc_q35_machine_init(void) +{ + qemu_register_machine(&pc_q35_machine); +} + +machine_init(pc_q35_machine_init); diff --git a/hw/pc_sysfw.c b/hw/pc_sysfw.c index b45f0acc7d..7567593a63 100644 --- a/hw/pc_sysfw.c +++ b/hw/pc_sysfw.c @@ -23,15 +23,15 @@ * THE SOFTWARE. */ -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "sysbus.h" #include "hw.h" #include "pc.h" #include "hw/boards.h" #include "loader.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "flash.h" -#include "kvm.h" +#include "sysemu/kvm.h" #define BIOS_FILENAME "bios.bin" @@ -84,6 +84,10 @@ static void pc_fw_add_pflash_drv(void) bios_name = BIOS_FILENAME; } filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (!filename) { + error_report("Can't open BIOS image %s", bios_name); + exit(1); + } opts = drive_add(IF_PFLASH, -1, filename, "readonly=on"); @@ -98,7 +102,9 @@ static void pc_fw_add_pflash_drv(void) return; } - drive_init(opts, machine->use_scsi); + if (!drive_init(opts, machine->block_default_type)) { + qemu_opts_del(opts); + } } static void pc_system_flash_init(MemoryRegion *rom_memory, @@ -106,7 +112,7 @@ static void pc_system_flash_init(MemoryRegion *rom_memory, { BlockDriverState *bdrv; int64_t size; - target_phys_addr_t phys_addr; + hwaddr phys_addr; int sector_bits, sector_size; pflash_t *system_flash; MemoryRegion *flash_mem; diff --git a/hw/pci/Makefile.objs b/hw/pci/Makefile.objs new file mode 100644 index 0000000000..fe965fe2f6 --- /dev/null +++ b/hw/pci/Makefile.objs @@ -0,0 +1,9 @@ +common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o +common-obj-$(CONFIG_PCI) += msix.o msi.o +common-obj-$(CONFIG_PCI) += shpc.o +common-obj-$(CONFIG_PCI) += slotid_cap.o +common-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o +common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o +common-obj-$(CONFIG_NO_PCI) += pci-stub.o + +extra-obj-y += pci-stub.o diff --git a/hw/msi.c b/hw/pci/msi.c index e2273a09ae..2a04d18884 100644 --- a/hw/msi.c +++ b/hw/pci/msi.c @@ -18,8 +18,8 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "msi.h" -#include "range.h" +#include "hw/pci/msi.h" +#include "qemu/range.h" /* Eventually those constants should go to Linux pci_regs.h */ #define PCI_MSI_PENDING_32 0x10 @@ -122,6 +122,31 @@ void msi_set_message(PCIDevice *dev, MSIMessage msg) pci_set_word(dev->config + msi_data_off(dev, msi64bit), msg.data); } +MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector) +{ + uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); + bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; + unsigned int nr_vectors = msi_nr_vectors(flags); + MSIMessage msg; + + assert(vector < nr_vectors); + + if (msi64bit) { + msg.address = pci_get_quad(dev->config + msi_address_lo_off(dev)); + } else { + msg.address = pci_get_long(dev->config + msi_address_lo_off(dev)); + } + + /* upper bit 31:16 is zero */ + msg.data = pci_get_word(dev->config + msi_data_off(dev, msi64bit)); + if (nr_vectors > 1) { + msg.data &= ~(nr_vectors - 1); + msg.data |= vector; + } + + return msg; +} + bool msi_enabled(const PCIDevice *dev) { return msi_present(dev) && @@ -249,8 +274,7 @@ void msi_notify(PCIDevice *dev, unsigned int vector) uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; unsigned int nr_vectors = msi_nr_vectors(flags); - uint64_t address; - uint32_t data; + MSIMessage msg; assert(vector < nr_vectors); if (msi_is_masked(dev, vector)) { @@ -261,24 +285,13 @@ void msi_notify(PCIDevice *dev, unsigned int vector) return; } - if (msi64bit) { - address = pci_get_quad(dev->config + msi_address_lo_off(dev)); - } else { - address = pci_get_long(dev->config + msi_address_lo_off(dev)); - } - - /* upper bit 31:16 is zero */ - data = pci_get_word(dev->config + msi_data_off(dev, msi64bit)); - if (nr_vectors > 1) { - data &= ~(nr_vectors - 1); - data |= vector; - } + msg = msi_get_message(dev, vector); MSI_DEV_PRINTF(dev, "notify vector 0x%x" " address: 0x%"PRIx64" data: 0x%"PRIx32"\n", - vector, address, data); - stl_le_phys(address, data); + vector, msg.address, msg.data); + stl_le_phys(msg.address, msg.data); } /* Normally called by pci_default_write_config(). */ diff --git a/hw/msi.h b/hw/pci/msi.h index 6ec1f99f80..81a3848a31 100644 --- a/hw/msi.h +++ b/hw/pci/msi.h @@ -22,7 +22,7 @@ #define QEMU_MSI_H #include "qemu-common.h" -#include "pci.h" +#include "hw/pci/pci.h" struct MSIMessage { uint64_t address; @@ -32,6 +32,7 @@ struct MSIMessage { extern bool msi_supported; void msi_set_message(PCIDevice *dev, MSIMessage msg); +MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector); bool msi_enabled(const PCIDevice *dev); int msi_init(struct PCIDevice *dev, uint8_t offset, unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask); diff --git a/hw/msix.c b/hw/pci/msix.c index 800fc32f0b..9eee6570c2 100644 --- a/hw/msix.c +++ b/hw/pci/msix.c @@ -14,11 +14,11 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "msi.h" -#include "msix.h" -#include "pci.h" -#include "range.h" +#include "hw/hw.h" +#include "hw/pci/msi.h" +#include "hw/pci/msix.h" +#include "hw/pci/pci.h" +#include "qemu/range.h" #define MSIX_CAP_LENGTH 12 @@ -65,7 +65,7 @@ static int msix_is_pending(PCIDevice *dev, int vector) return *msix_pending_byte(dev, vector) & msix_pending_mask(vector); } -static void msix_set_pending(PCIDevice *dev, int vector) +void msix_set_pending(PCIDevice *dev, unsigned int vector) { *msix_pending_byte(dev, vector) |= msix_pending_mask(vector); } @@ -75,13 +75,13 @@ static void msix_clr_pending(PCIDevice *dev, int vector) *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector); } -static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmask) +static bool msix_vector_masked(PCIDevice *dev, unsigned int vector, bool fmask) { unsigned offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT; } -static bool msix_is_masked(PCIDevice *dev, int vector) +bool msix_is_masked(PCIDevice *dev, unsigned int vector) { return msix_vector_masked(dev, vector, dev->msix_function_masked); } @@ -157,7 +157,7 @@ void msix_write_config(PCIDevice *dev, uint32_t addr, } } -static uint64_t msix_table_mmio_read(void *opaque, target_phys_addr_t addr, +static uint64_t msix_table_mmio_read(void *opaque, hwaddr addr, unsigned size) { PCIDevice *dev = opaque; @@ -165,7 +165,7 @@ static uint64_t msix_table_mmio_read(void *opaque, target_phys_addr_t addr, return pci_get_long(dev->msix_table + addr); } -static void msix_table_mmio_write(void *opaque, target_phys_addr_t addr, +static void msix_table_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { PCIDevice *dev = opaque; @@ -180,26 +180,29 @@ static void msix_table_mmio_write(void *opaque, target_phys_addr_t addr, static const MemoryRegionOps msix_table_mmio_ops = { .read = msix_table_mmio_read, .write = msix_table_mmio_write, - /* TODO: MSIX should be LITTLE_ENDIAN. */ - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 4, .max_access_size = 4, }, }; -static uint64_t msix_pba_mmio_read(void *opaque, target_phys_addr_t addr, +static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr, unsigned size) { PCIDevice *dev = opaque; + if (dev->msix_vector_poll_notifier) { + unsigned vector_start = addr * 8; + unsigned vector_end = MIN(addr + size * 8, dev->msix_entries_nr); + dev->msix_vector_poll_notifier(dev, vector_start, vector_end); + } return pci_get_long(dev->msix_pba + addr); } static const MemoryRegionOps msix_pba_mmio_ops = { .read = msix_pba_mmio_read, - /* TODO: MSIX should be LITTLE_ENDIAN. */ - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 4, .max_access_size = 4, @@ -307,13 +310,9 @@ int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, return -EINVAL; } - if (asprintf(&name, "%s-msix", dev->name) == -1) { - return -ENOMEM; - } - + name = g_strdup_printf("%s-msix", dev->name); memory_region_init(&dev->msix_exclusive_bar, name, MSIX_EXCLUSIVE_BAR_SIZE); - - free(name); + g_free(name); ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr, MSIX_EXCLUSIVE_BAR_TABLE_OFFSET, &dev->msix_exclusive_bar, @@ -340,6 +339,15 @@ static void msix_free_irq_entries(PCIDevice *dev) } } +static void msix_clear_all_vectors(PCIDevice *dev) +{ + int vector; + + for (vector = 0; vector < dev->msix_entries_nr; ++vector) { + msix_clr_pending(dev, vector); + } +} + /* Clean up resources for the device. */ void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar) { @@ -361,7 +369,6 @@ void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar) g_free(dev->msix_entry_used); dev->msix_entry_used = NULL; dev->cap_present &= ~QEMU_PCI_CAP_MSIX; - return; } void msix_uninit_exclusive_bar(PCIDevice *dev) @@ -394,7 +401,7 @@ void msix_load(PCIDevice *dev, QEMUFile *f) return; } - msix_free_irq_entries(dev); + msix_clear_all_vectors(dev); qemu_get_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE); qemu_get_buffer(f, dev->msix_pba, (n + 7) / 8); msix_update_function_masked(dev); @@ -440,7 +447,7 @@ void msix_reset(PCIDevice *dev) if (!msix_present(dev)) { return; } - msix_free_irq_entries(dev); + msix_clear_all_vectors(dev); dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &= ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET]; memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE); @@ -511,7 +518,8 @@ static void msix_unset_notifier_for_vector(PCIDevice *dev, unsigned int vector) int msix_set_vector_notifiers(PCIDevice *dev, MSIVectorUseNotifier use_notifier, - MSIVectorReleaseNotifier release_notifier) + MSIVectorReleaseNotifier release_notifier, + MSIVectorPollNotifier poll_notifier) { int vector, ret; @@ -519,6 +527,7 @@ int msix_set_vector_notifiers(PCIDevice *dev, dev->msix_vector_use_notifier = use_notifier; dev->msix_vector_release_notifier = release_notifier; + dev->msix_vector_poll_notifier = poll_notifier; if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) { @@ -529,6 +538,9 @@ int msix_set_vector_notifiers(PCIDevice *dev, } } } + if (dev->msix_vector_poll_notifier) { + dev->msix_vector_poll_notifier(dev, 0, dev->msix_entries_nr); + } return 0; undo: @@ -555,4 +567,5 @@ void msix_unset_vector_notifiers(PCIDevice *dev) } dev->msix_vector_use_notifier = NULL; dev->msix_vector_release_notifier = NULL; + dev->msix_vector_poll_notifier = NULL; } diff --git a/hw/msix.h b/hw/pci/msix.h index 15211cb592..d0c4429843 100644 --- a/hw/msix.h +++ b/hw/pci/msix.h @@ -2,7 +2,7 @@ #define QEMU_MSIX_H #include "qemu-common.h" -#include "pci.h" +#include "hw/pci/pci.h" void msix_set_message(PCIDevice *dev, int vector, MSIMessage msg); int msix_init(PCIDevice *dev, unsigned short nentries, @@ -26,6 +26,9 @@ void msix_load(PCIDevice *dev, QEMUFile *f); int msix_enabled(PCIDevice *dev); int msix_present(PCIDevice *dev); +bool msix_is_masked(PCIDevice *dev, unsigned vector); +void msix_set_pending(PCIDevice *dev, unsigned vector); + int msix_vector_use(PCIDevice *dev, unsigned vector); void msix_vector_unuse(PCIDevice *dev, unsigned vector); void msix_unuse_all_vectors(PCIDevice *dev); @@ -36,6 +39,7 @@ void msix_reset(PCIDevice *dev); int msix_set_vector_notifiers(PCIDevice *dev, MSIVectorUseNotifier use_notifier, - MSIVectorReleaseNotifier release_notifier); + MSIVectorReleaseNotifier release_notifier, + MSIVectorPollNotifier poll_notifier); void msix_unset_vector_notifiers(PCIDevice *dev); #endif diff --git a/hw/pci-hotplug.c b/hw/pci/pci-hotplug.c index e7fb780a08..f38df30540 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci/pci-hotplug.c @@ -22,17 +22,17 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "boards.h" -#include "pci.h" -#include "net.h" -#include "pc.h" -#include "monitor.h" -#include "scsi.h" -#include "virtio-blk.h" -#include "qemu-config.h" -#include "blockdev.h" -#include "error.h" +#include "hw/hw.h" +#include "hw/boards.h" +#include "hw/pci/pci.h" +#include "net/net.h" +#include "hw/pc.h" +#include "monitor/monitor.h" +#include "hw/scsi.h" +#include "hw/virtio-blk.h" +#include "qemu/config-file.h" +#include "sysemu/blockdev.h" +#include "qapi/error.h" #if defined(TARGET_I386) static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, @@ -80,7 +80,13 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter, SCSIBus *scsibus; SCSIDevice *scsidev; - scsibus = SCSI_BUS(QLIST_FIRST(&adapter->child_bus)); + scsibus = (SCSIBus *) + object_dynamic_cast(OBJECT(QLIST_FIRST(&adapter->child_bus)), + TYPE_SCSI_BUS); + if (!scsibus) { + error_report("Device is not a SCSI adapter"); + return -1; + } /* * drive_init() tries to find a default for dinfo->unit. Doesn't @@ -105,15 +111,14 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter, return 0; } -int pci_drive_hot_add(Monitor *mon, const QDict *qdict, - DriveInfo *dinfo, int type) +int pci_drive_hot_add(Monitor *mon, const QDict *qdict, DriveInfo *dinfo) { int dom, pci_bus; unsigned slot; PCIDevice *dev; const char *pci_addr = qdict_get_str(qdict, "pci_addr"); - switch (type) { + switch (dinfo->type) { case IF_SCSI: if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) { goto err; @@ -129,7 +134,7 @@ int pci_drive_hot_add(Monitor *mon, const QDict *qdict, } break; default: - monitor_printf(mon, "Can't hot-add drive to type %d\n", type); + monitor_printf(mon, "Can't hot-add drive to type %d\n", dinfo->type); goto err; } diff --git a/hw/pci-stub.c b/hw/pci/pci-stub.c index 134c4484b6..1dda89b593 100644 --- a/hw/pci-stub.c +++ b/hw/pci/pci-stub.c @@ -18,9 +18,9 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "sysemu.h" -#include "monitor.h" -#include "pci.h" +#include "sysemu/sysemu.h" +#include "monitor/monitor.h" +#include "hw/pci/pci.h" #include "qmp-commands.h" PciInfoList *qmp_query_pci(Error **errp) diff --git a/hw/pci.c b/hw/pci/pci.c index 4d95984807..94840c4af7 100644 --- a/hw/pci.c +++ b/hw/pci/pci.c @@ -21,18 +21,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pci.h" -#include "pci_bridge.h" -#include "pci_internals.h" -#include "monitor.h" -#include "net.h" -#include "sysemu.h" -#include "loader.h" -#include "range.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_bus.h" +#include "monitor/monitor.h" +#include "net/net.h" +#include "sysemu/sysemu.h" +#include "hw/loader.h" +#include "qemu/range.h" #include "qmp-commands.h" -#include "msi.h" -#include "msix.h" +#include "hw/pci/msi.h" +#include "hw/pci/msix.h" +#include "exec/address-spaces.h" //#define DEBUG_PCI #ifdef DEBUG_PCI @@ -300,9 +301,9 @@ PCIBus *pci_bus_new(DeviceState *parent, const char *name, PCIBus *bus; bus = g_malloc0(sizeof(*bus)); - bus->qbus.glib_allocated = true; pci_bus_new_inplace(bus, parent, name, address_space_mem, address_space_io, devfn_min); + OBJECT(bus)->free = g_free; return bus; } @@ -366,6 +367,10 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) pci_update_mappings(s); + memory_region_set_enabled(&s->bus_master_enable_region, + pci_get_word(s->config + PCI_COMMAND) + & PCI_COMMAND_MASTER); + g_free(config); return 0; } @@ -439,7 +444,7 @@ const VMStateDescription vmstate_pci_device = { }; const VMStateDescription vmstate_pcie_device = { - .name = "PCIDevice", + .name = "PCIEDevice", .version_id = 2, .minimum_version_id = 1, .minimum_version_id_old = 1, @@ -777,6 +782,17 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, pci_dev->bus = bus; if (bus->dma_context_fn) { pci_dev->dma = bus->dma_context_fn(bus, bus->dma_context_opaque, devfn); + } else { + /* FIXME: Make dma_context_fn use MemoryRegions instead, so this path is + * taken unconditionally */ + /* FIXME: inherit memory region from bus creator */ + memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus master", + get_system_memory(), 0, + memory_region_size(get_system_memory())); + memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); + address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region); + pci_dev->dma = g_new(DMAContext, 1); + dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL, NULL, NULL); } pci_dev->devfn = devfn; pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); @@ -830,6 +846,13 @@ static void do_pci_unregister_device(PCIDevice *pci_dev) qemu_free_irqs(pci_dev->irq); pci_dev->bus->devices[pci_dev->devfn] = NULL; pci_config_free(pci_dev); + + if (!pci_dev->bus->dma_context_fn) { + address_space_destroy(&pci_dev->bus_master_as); + memory_region_destroy(&pci_dev->bus_master_enable_region); + g_free(pci_dev->dma); + pci_dev->dma = NULL; + } } static void pci_unregister_io_regions(PCIDevice *pci_dev) @@ -968,7 +991,7 @@ static pcibus_t pci_bar_address(PCIDevice *d, * to >4G. Check it. TODO: we might need to support * it in the future for e.g. PAE. */ - if (last_addr >= TARGET_PHYS_ADDR_MAX) { + if (last_addr >= HWADDR_MAX) { return PCI_BAR_UNMAPPED; } @@ -1051,8 +1074,12 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) range_covers_byte(addr, l, PCI_COMMAND)) pci_update_mappings(d); - if (range_covers_byte(addr, l, PCI_COMMAND)) + if (range_covers_byte(addr, l, PCI_COMMAND)) { pci_update_irq_disabled(d, was_irq_disabled); + memory_region_set_enabled(&d->bus_master_enable_region, + pci_get_word(d->config + PCI_COMMAND) + & PCI_COMMAND_MASTER); + } msi_write_config(d, addr, val, l); msix_write_config(d, addr, val, l); @@ -1094,10 +1121,21 @@ PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin) pin = bus->map_irq(dev, pin); dev = bus->parent_dev; } while (dev); - assert(bus->route_intx_to_irq); + + if (!bus->route_intx_to_irq) { + error_report("PCI: Bug - unimplemented PCI INTx routing (%s)\n", + object_get_typename(OBJECT(bus->qbus.parent))); + return (PCIINTxRoute) { PCI_INTX_DISABLED, -1 }; + } + return bus->route_intx_to_irq(bus->irq_opaque, pin); } +bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new) +{ + return old->mode != new->mode || old->irq != new->irq; +} + void pci_bus_fire_intx_routing_notifier(PCIBus *bus) { PCIDevice *dev; @@ -1121,6 +1159,24 @@ void pci_device_set_intx_routing_notifier(PCIDevice *dev, dev->intx_routing_notifier = notifier; } +/* + * PCI-to-PCI bridge specification + * 9.1: Interrupt routing. Table 9-1 + * + * the PCI Express Base Specification, Revision 2.1 + * 2.2.8.1: INTx interrutp signaling - Rules + * the Implementation Note + * Table 2-20 + */ +/* + * 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD + * 0-origin unlike PCI interrupt pin register. + */ +int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin) +{ + return (pin + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS; +} + /***********************************************************/ /* monitor info on PCI */ @@ -1185,6 +1241,7 @@ static const pci_class_desc pci_class_descriptions[] = { 0x0c02, "SSA controller", "ssa"}, { 0x0c03, "USB controller", "usb"}, { 0x0c04, "Fibre channel controller", "fibre-channel"}, + { 0x0c05, "SMBus"}, { 0, NULL} }; @@ -1474,6 +1531,24 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, return res; } +PCIDevice *pci_vga_init(PCIBus *bus) +{ + switch (vga_interface_type) { + case VGA_CIRRUS: + return pci_create_simple(bus, -1, "cirrus-vga"); + case VGA_QXL: + return pci_create_simple(bus, -1, "qxl-vga"); + case VGA_STD: + return pci_create_simple(bus, -1, "VGA"); + case VGA_VMWARE: + return pci_create_simple(bus, -1, "vmware-svga"); + case VGA_NONE: + default: /* Other non-PCI types. Checking for unsupported types is already + done in vl.c. */ + return NULL; + } +} + /* Whether a given bus number is in range of the secondary * bus of the given bridge device. */ static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num) @@ -1626,16 +1701,16 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) return pci_create_simple_multifunction(bus, devfn, false, name); } -static int pci_find_space(PCIDevice *pdev, uint8_t size) +static uint8_t pci_find_space(PCIDevice *pdev, uint8_t size) { - int config_size = pci_config_size(pdev); int offset = PCI_CONFIG_HEADER_SIZE; int i; - for (i = PCI_CONFIG_HEADER_SIZE; i < config_size; ++i) + for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i) { if (pdev->used[i]) offset = i + 1; else if (i - offset + 1 == size) return offset; + } return 0; } @@ -1854,7 +1929,7 @@ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST]; pdev->config[PCI_CAPABILITY_LIST] = offset; pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST; - memset(pdev->used + offset, 0xFF, size); + memset(pdev->used + offset, 0xFF, QEMU_ALIGN_UP(size, 4)); /* Make capability read-only by default */ memset(pdev->wmask + offset, 0, size); /* Check capability by default */ @@ -1874,7 +1949,7 @@ void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size) memset(pdev->w1cmask + offset, 0, size); /* Clear cmask as device-specific registers can't be checked */ memset(pdev->cmask + offset, 0, size); - memset(pdev->used + offset, 0, size); + memset(pdev->used + offset, 0, QEMU_ALIGN_UP(size, 4)); if (!pdev->config[PCI_CAPABILITY_LIST]) pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST; @@ -1962,7 +2037,7 @@ static char *pcibus_get_fw_dev_path(DeviceState *dev) PCI_SLOT(d->devfn)); if (PCI_FUNC(d->devfn)) snprintf(path + off, sizeof(path) + off, ",%x", PCI_FUNC(d->devfn)); - return strdup(path); + return g_strdup(path); } static char *pcibus_get_dev_path(DeviceState *dev) diff --git a/hw/pci.h b/hw/pci/pci.h index 4b6ab3d190..72927e3149 100644 --- a/hw/pci.h +++ b/hw/pci/pci.h @@ -3,14 +3,14 @@ #include "qemu-common.h" -#include "qdev.h" -#include "memory.h" -#include "dma.h" +#include "hw/qdev.h" +#include "exec/memory.h" +#include "sysemu/dma.h" /* PCI includes legacy ISA access. */ -#include "isa.h" +#include "hw/isa.h" -#include "pcie.h" +#include "hw/pci/pcie.h" /* PCI bus */ @@ -21,7 +21,7 @@ #define PCI_FUNC_MAX 8 /* Class, Vendor and Device IDs from Linux's pci_ids.h */ -#include "pci_ids.h" +#include "hw/pci/pci_ids.h" /* QEMU-specific Vendor and Device ID definitions */ @@ -76,6 +76,7 @@ #define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 #define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 #define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 +#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 #define FMT_PCIBUS PRIx64 @@ -99,7 +100,7 @@ typedef struct PCIIORegion { #define PCI_ROM_SLOT 6 #define PCI_NUM_REGIONS 7 -#include "pci_regs.h" +#include "hw/pci/pci_regs.h" /* PCI HEADER_TYPE */ #define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80 @@ -186,6 +187,9 @@ typedef void (*PCIINTxRoutingNotifier)(PCIDevice *dev); typedef int (*MSIVectorUseNotifier)(PCIDevice *dev, unsigned int vector, MSIMessage msg); typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned int vector); +typedef void (*MSIVectorPollNotifier)(PCIDevice *dev, + unsigned int vector_start, + unsigned int vector_end); struct PCIDevice { DeviceState qdev; @@ -211,6 +215,8 @@ struct PCIDevice { int32_t devfn; char name[64]; PCIIORegion io_regions[PCI_NUM_REGIONS]; + AddressSpace bus_master_as; + MemoryRegion bus_master_enable_region; DMAContext *dma; /* do not access the following fields */ @@ -268,6 +274,7 @@ struct PCIDevice { /* MSI-X notifiers */ MSIVectorUseNotifier msix_vector_use_notifier; MSIVectorReleaseNotifier msix_vector_release_notifier; + MSIVectorPollNotifier msix_vector_poll_notifier; }; void pci_register_bar(PCIDevice *pci_dev, int region_num, @@ -316,6 +323,8 @@ void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, int nirq); int pci_bus_get_irq_level(PCIBus *bus, int irq_num); void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev); +/* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */ +int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin); PCIBus *pci_register_bus(DeviceState *parent, const char *name, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, @@ -324,6 +333,7 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, uint8_t devfn_min, int nirq); void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn); PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin); +bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new); void pci_bus_fire_intx_routing_notifier(PCIBus *bus); void pci_device_set_intx_routing_notifier(PCIDevice *dev, PCIINTxRoutingNotifier notifier); @@ -334,6 +344,9 @@ PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, const char *default_devaddr); PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, const char *default_devaddr); + +PCIDevice *pci_vga_init(PCIBus *bus); + int pci_bus_num(PCIBus *s); void pci_for_each_device(PCIBus *bus, int bus_num, void (*fn)(PCIBus *bus, PCIDevice *d, void *opaque), diff --git a/hw/pci_bridge.c b/hw/pci/pci_bridge.c index 5c6455f6fa..995842a72d 100644 --- a/hw/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -29,9 +29,9 @@ * VA Linux Systems Japan K.K. */ -#include "pci_bridge.h" -#include "pci_internals.h" -#include "range.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_bus.h" +#include "qemu/range.h" /* PCI bridge subsystem vendor ID helper functions */ #define PCI_SSVID_SIZEOF 8 @@ -151,58 +151,63 @@ static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias, memory_region_add_subregion_overlap(parent_space, base, alias, 1); } -static void pci_bridge_cleanup_alias(MemoryRegion *alias, - MemoryRegion *parent_space) -{ - memory_region_del_subregion(parent_space, alias); - memory_region_destroy(alias); -} - -static void pci_bridge_region_init(PCIBridge *br) +static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br) { PCIBus *parent = br->dev.bus; + PCIBridgeWindows *w = g_new(PCIBridgeWindows, 1); uint16_t cmd = pci_get_word(br->dev.config + PCI_COMMAND); - pci_bridge_init_alias(br, &br->alias_pref_mem, + pci_bridge_init_alias(br, &w->alias_pref_mem, PCI_BASE_ADDRESS_MEM_PREFETCH, "pci_bridge_pref_mem", &br->address_space_mem, parent->address_space_mem, cmd & PCI_COMMAND_MEMORY); - pci_bridge_init_alias(br, &br->alias_mem, + pci_bridge_init_alias(br, &w->alias_mem, PCI_BASE_ADDRESS_SPACE_MEMORY, "pci_bridge_mem", &br->address_space_mem, parent->address_space_mem, cmd & PCI_COMMAND_MEMORY); - pci_bridge_init_alias(br, &br->alias_io, + pci_bridge_init_alias(br, &w->alias_io, PCI_BASE_ADDRESS_SPACE_IO, "pci_bridge_io", &br->address_space_io, parent->address_space_io, cmd & PCI_COMMAND_IO); /* TODO: optinal VGA and VGA palette snooping support. */ + + return w; } -static void pci_bridge_region_cleanup(PCIBridge *br) +static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *w) { PCIBus *parent = br->dev.bus; - pci_bridge_cleanup_alias(&br->alias_io, - parent->address_space_io); - pci_bridge_cleanup_alias(&br->alias_mem, - parent->address_space_mem); - pci_bridge_cleanup_alias(&br->alias_pref_mem, - parent->address_space_mem); + + memory_region_del_subregion(parent->address_space_io, &w->alias_io); + memory_region_del_subregion(parent->address_space_mem, &w->alias_mem); + memory_region_del_subregion(parent->address_space_mem, &w->alias_pref_mem); +} + +static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w) +{ + memory_region_destroy(&w->alias_io); + memory_region_destroy(&w->alias_mem); + memory_region_destroy(&w->alias_pref_mem); + g_free(w); } static void pci_bridge_update_mappings(PCIBridge *br) { + PCIBridgeWindows *w = br->windows; + /* Make updates atomic to: handle the case of one VCPU updating the bridge * while another accesses an unaffected region. */ memory_region_transaction_begin(); - pci_bridge_region_cleanup(br); - pci_bridge_region_init(br); + pci_bridge_region_del(br, br->windows); + br->windows = pci_bridge_region_init(br); memory_region_transaction_commit(); + pci_bridge_region_cleanup(br, w); } /* default write_config function for PCI-to-PCI bridge */ @@ -326,7 +331,7 @@ int pci_bridge_initfn(PCIDevice *dev) memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX); sec_bus->address_space_io = &br->address_space_io; memory_region_init(&br->address_space_io, "pci_bridge_io", 65536); - pci_bridge_region_init(br); + br->windows = pci_bridge_region_init(br); QLIST_INIT(&sec_bus->child); QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling); return 0; @@ -338,7 +343,8 @@ void pci_bridge_exitfn(PCIDevice *pci_dev) PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev); assert(QLIST_EMPTY(&s->sec_bus.child)); QLIST_REMOVE(&s->sec_bus, sibling); - pci_bridge_region_cleanup(s); + pci_bridge_region_del(s, s->windows); + pci_bridge_region_cleanup(s, s->windows); memory_region_destroy(&s->address_space_mem); memory_region_destroy(&s->address_space_io); /* qbus_free() is called automatically by qdev_free() */ diff --git a/hw/pci_bridge.h b/hw/pci/pci_bridge.h index a00accc172..455cb6677a 100644 --- a/hw/pci_bridge.h +++ b/hw/pci/pci_bridge.h @@ -26,7 +26,7 @@ #ifndef QEMU_PCI_BRIDGE_H #define QEMU_PCI_BRIDGE_H -#include "pci.h" +#include "hw/pci/pci.h" int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset, uint16_t svid, uint16_t ssid); diff --git a/hw/pci_internals.h b/hw/pci/pci_bus.h index c931b64b46..f905b9e11e 100644 --- a/hw/pci_internals.h +++ b/hw/pci/pci_bus.h @@ -1,15 +1,11 @@ -#ifndef QEMU_PCI_INTERNALS_H -#define QEMU_PCI_INTERNALS_H +#ifndef QEMU_PCI_BUS_H +#define QEMU_PCI_BUS_H /* - * This header files is private to pci.c and pci_bridge.c - * So following structures are opaque to others and shouldn't be - * accessed. + * PCI Bus and Bridge datastructures. * - * For pci-to-pci bridge needs to include this header file to embed - * PCIBridge in its structure or to get sizeof(PCIBridge), - * However, they shouldn't access those following members directly. - * Use accessor function in pci.h, pci_bridge.h + * Do not access the following members directly; + * use accessor functions in pci.h, pci_bridge.h */ #define TYPE_PCI_BUS "PCI" @@ -40,6 +36,19 @@ struct PCIBus { int *irq_count; }; +typedef struct PCIBridgeWindows PCIBridgeWindows; + +/* + * Aliases for each of the address space windows that the bridge + * can forward. Mapped into the bridge's parent's address space, + * as subregions. + */ +struct PCIBridgeWindows { + MemoryRegion alias_pref_mem; + MemoryRegion alias_mem; + MemoryRegion alias_io; +}; + struct PCIBridge { PCIDevice dev; @@ -55,16 +64,11 @@ struct PCIBridge { */ MemoryRegion address_space_mem; MemoryRegion address_space_io; - /* - * Aliases for each of the address space windows that the bridge - * can forward. Mapped into the bridge's parent's address space, - * as subregions. - */ - MemoryRegion alias_pref_mem; - MemoryRegion alias_mem; - MemoryRegion alias_io; + + PCIBridgeWindows *windows; + pci_map_irq_fn map_irq; const char *bus_name; }; -#endif /* QEMU_PCI_INTERNALS_H */ +#endif /* QEMU_PCI_BUS_H */ diff --git a/hw/pci_host.c b/hw/pci/pci_host.c index 804177891a..daca1c1ea0 100644 --- a/hw/pci_host.c +++ b/hw/pci/pci_host.c @@ -18,8 +18,8 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "pci.h" -#include "pci_host.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" /* debug PCI */ //#define DEBUG_PCI @@ -94,7 +94,7 @@ uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len) return val; } -static void pci_host_config_write(void *opaque, target_phys_addr_t addr, +static void pci_host_config_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) { PCIHostState *s = opaque; @@ -107,7 +107,7 @@ static void pci_host_config_write(void *opaque, target_phys_addr_t addr, s->config_reg = val; } -static uint64_t pci_host_config_read(void *opaque, target_phys_addr_t addr, +static uint64_t pci_host_config_read(void *opaque, hwaddr addr, unsigned len) { PCIHostState *s = opaque; @@ -118,7 +118,7 @@ static uint64_t pci_host_config_read(void *opaque, target_phys_addr_t addr, return val; } -static void pci_host_data_write(void *opaque, target_phys_addr_t addr, +static void pci_host_data_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) { PCIHostState *s = opaque; @@ -129,7 +129,7 @@ static void pci_host_data_write(void *opaque, target_phys_addr_t addr, } static uint64_t pci_host_data_read(void *opaque, - target_phys_addr_t addr, unsigned len) + hwaddr addr, unsigned len) { PCIHostState *s = opaque; uint32_t val; @@ -165,4 +165,16 @@ const MemoryRegionOps pci_host_data_be_ops = { .endianness = DEVICE_BIG_ENDIAN, }; +static const TypeInfo pci_host_type_info = { + .name = TYPE_PCI_HOST_BRIDGE, + .parent = TYPE_SYS_BUS_DEVICE, + .abstract = true, + .instance_size = sizeof(PCIHostState), +}; + +static void pci_host_register_types(void) +{ + type_register_static(&pci_host_type_info); +} +type_init(pci_host_register_types) diff --git a/hw/pci_host.h b/hw/pci/pci_host.h index 359e38f63b..1845d4dfd5 100644 --- a/hw/pci_host.h +++ b/hw/pci/pci_host.h @@ -28,10 +28,15 @@ #ifndef PCI_HOST_H #define PCI_HOST_H -#include "sysbus.h" +#include "hw/sysbus.h" + +#define TYPE_PCI_HOST_BRIDGE "pci-host-bridge" +#define PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE) struct PCIHostState { SysBusDevice busdev; + MemoryRegion conf_mem; MemoryRegion data_mem; MemoryRegion mmcfg; diff --git a/hw/pci_ids.h b/hw/pci/pci_ids.h index 301bf1cd86..271d935bc7 100644 --- a/hw/pci_ids.h +++ b/hw/pci/pci_ids.h @@ -7,6 +7,8 @@ * * QEMU-specific definitions belong in pci.h */ +#ifndef HW_PCI_IDS_H +#define HW_PCI_IDS_H 1 /* Device classes and subclasses */ @@ -31,12 +33,15 @@ #define PCI_CLASS_SYSTEM_OTHER 0x0880 #define PCI_CLASS_SERIAL_USB 0x0c03 +#define PCI_CLASS_SERIAL_SMBUS 0x0c05 #define PCI_CLASS_BRIDGE_HOST 0x0600 #define PCI_CLASS_BRIDGE_ISA 0x0601 #define PCI_CLASS_BRIDGE_PCI 0x0604 +#define PCI_CLASS_BRDIGE_PCI_INF_SUB 0x01 #define PCI_CLASS_BRIDGE_OTHER 0x0680 +#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700 #define PCI_CLASS_COMMUNICATION_OTHER 0x0780 #define PCI_CLASS_PROCESSOR_CO 0x0b40 @@ -104,6 +109,7 @@ #define PCI_DEVICE_ID_INTEL_82378 0x0484 #define PCI_DEVICE_ID_INTEL_82441 0x1237 #define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415 +#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e #define PCI_DEVICE_ID_INTEL_82801D 0x24CD #define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab #define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 @@ -113,6 +119,17 @@ #define PCI_DEVICE_ID_INTEL_82371AB 0x7111 #define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 #define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 + +#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 +#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917 +#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912 +#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913 +#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914 +#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919 +#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 +#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916 +#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918 + #define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934 #define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935 #define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936 @@ -123,8 +140,12 @@ #define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c #define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed +#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0 + #define PCI_VENDOR_ID_XEN 0x5853 #define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 #define PCI_VENDOR_ID_NEC 0x1033 #define PCI_DEVICE_ID_NEC_UPD720200 0x0194 + +#endif diff --git a/hw/pci_regs.h b/hw/pci/pci_regs.h index 56a404be6e..56a404be6e 100644 --- a/hw/pci_regs.h +++ b/hw/pci/pci_regs.h diff --git a/hw/pcie.c b/hw/pci/pcie.c index 7c92f193e7..485c94c1b2 100644 --- a/hw/pcie.c +++ b/hw/pci/pcie.c @@ -19,13 +19,13 @@ */ #include "qemu-common.h" -#include "pci_bridge.h" -#include "pcie.h" -#include "msix.h" -#include "msi.h" -#include "pci_internals.h" -#include "pcie_regs.h" -#include "range.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pcie.h" +#include "hw/pci/msix.h" +#include "hw/pci/msi.h" +#include "hw/pci/pci_bus.h" +#include "hw/pci/pcie_regs.h" +#include "qemu/range.h" //#define DEBUG_PCIE #ifdef DEBUG_PCIE @@ -494,7 +494,7 @@ uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id) static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t next) { - uint16_t header = pci_get_long(dev->config + pos); + uint32_t header = pci_get_long(dev->config + pos); assert(!(next & (PCI_EXT_CAP_ALIGN - 1))); header = (header & ~PCI_EXT_CAP_NEXT_MASK) | ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK); diff --git a/hw/pcie.h b/hw/pci/pcie.h index b8ab0c7b4f..31604e2742 100644 --- a/hw/pcie.h +++ b/hw/pci/pcie.h @@ -21,10 +21,10 @@ #ifndef QEMU_PCIE_H #define QEMU_PCIE_H -#include "hw.h" -#include "pci_regs.h" -#include "pcie_regs.h" -#include "pcie_aer.h" +#include "hw/hw.h" +#include "hw/pci/pci_regs.h" +#include "hw/pci/pcie_regs.h" +#include "hw/pci/pcie_aer.h" typedef enum { /* for attention and power indicator */ @@ -133,7 +133,6 @@ extern const VMStateDescription vmstate_pcie_device; #define VMSTATE_PCIE_DEVICE(_field, _state) { \ .name = (stringify(_field)), \ - .version_id = 2, \ .size = sizeof(PCIDevice), \ .vmsd = &vmstate_pcie_device, \ .flags = VMS_STRUCT, \ diff --git a/hw/pcie_aer.c b/hw/pci/pcie_aer.c index 3b6981c7b7..1ce72ce944 100644 --- a/hw/pcie_aer.c +++ b/hw/pci/pcie_aer.c @@ -18,15 +18,15 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "sysemu.h" -#include "qemu-objects.h" -#include "monitor.h" -#include "pci_bridge.h" -#include "pcie.h" -#include "msix.h" -#include "msi.h" -#include "pci_internals.h" -#include "pcie_regs.h" +#include "sysemu/sysemu.h" +#include "qapi/qmp/types.h" +#include "monitor/monitor.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pcie.h" +#include "hw/pci/msix.h" +#include "hw/pci/msi.h" +#include "hw/pci/pci_bus.h" +#include "hw/pci/pcie_regs.h" //#define DEBUG_PCIE #ifdef DEBUG_PCIE @@ -738,6 +738,11 @@ void pcie_aer_root_init(PCIDevice *dev) PCI_ERR_ROOT_CMD_EN_MASK); pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS, PCI_ERR_ROOT_STATUS_REPORT_MASK); + /* PCI_ERR_ROOT_IRQ is RO but devices change it using a + * device-specific method. + */ + pci_set_long(dev->cmask + pos + PCI_ERR_ROOT_STATUS, + ~PCI_ERR_ROOT_IRQ); } void pcie_aer_root_reset(PCIDevice *dev) diff --git a/hw/pcie_aer.h b/hw/pci/pcie_aer.h index 7539500cd8..bcac80a7b0 100644 --- a/hw/pcie_aer.h +++ b/hw/pci/pcie_aer.h @@ -21,7 +21,7 @@ #ifndef QEMU_PCIE_AER_H #define QEMU_PCIE_AER_H -#include "hw.h" +#include "hw/hw.h" /* definitions which PCIExpressDevice uses */ diff --git a/hw/pcie_host.c b/hw/pci/pcie_host.c index 28bbe72b37..b2d942bce1 100644 --- a/hw/pcie_host.c +++ b/hw/pci/pcie_host.c @@ -19,10 +19,10 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "hw.h" -#include "pci.h" -#include "pcie_host.h" -#include "exec-memory.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/pci/pcie_host.h" +#include "exec/address-spaces.h" /* * PCI express mmcfig address @@ -53,7 +53,7 @@ static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s, PCIE_MMCFG_DEVFN(mmcfg_addr)); } -static void pcie_mmcfg_data_write(void *opaque, target_phys_addr_t mmcfg_addr, +static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr, uint64_t val, unsigned len) { PCIExpressHost *e = opaque; @@ -76,7 +76,7 @@ static void pcie_mmcfg_data_write(void *opaque, target_phys_addr_t mmcfg_addr, } static uint64_t pcie_mmcfg_data_read(void *opaque, - target_phys_addr_t mmcfg_addr, + hwaddr mmcfg_addr, unsigned len) { PCIExpressHost *e = opaque; @@ -105,16 +105,11 @@ static const MemoryRegionOps pcie_mmcfg_ops = { }; /* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */ -#define PCIE_BASE_ADDR_UNMAPPED ((target_phys_addr_t)-1ULL) +#define PCIE_BASE_ADDR_UNMAPPED ((hwaddr)-1ULL) -int pcie_host_init(PCIExpressHost *e, uint32_t size) +int pcie_host_init(PCIExpressHost *e) { - assert(!(size & (size - 1))); /* power of 2 */ - assert(size >= PCIE_MMCFG_SIZE_MIN); - assert(size <= PCIE_MMCFG_SIZE_MAX); e->base_addr = PCIE_BASE_ADDR_UNMAPPED; - e->size = size; - memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg", e->size); return 0; } @@ -123,22 +118,44 @@ void pcie_host_mmcfg_unmap(PCIExpressHost *e) { if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) { memory_region_del_subregion(get_system_memory(), &e->mmio); + memory_region_destroy(&e->mmio); e->base_addr = PCIE_BASE_ADDR_UNMAPPED; } } -void pcie_host_mmcfg_map(PCIExpressHost *e, target_phys_addr_t addr) +void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, + uint32_t size) { + assert(!(size & (size - 1))); /* power of 2 */ + assert(size >= PCIE_MMCFG_SIZE_MIN); + assert(size <= PCIE_MMCFG_SIZE_MAX); + e->size = size; + memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg", e->size); e->base_addr = addr; memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio); } void pcie_host_mmcfg_update(PCIExpressHost *e, int enable, - target_phys_addr_t addr) + hwaddr addr, + uint32_t size) { pcie_host_mmcfg_unmap(e); if (enable) { - pcie_host_mmcfg_map(e, addr); + pcie_host_mmcfg_map(e, addr, size); } } + +static const TypeInfo pcie_host_type_info = { + .name = TYPE_PCIE_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, + .abstract = true, + .instance_size = sizeof(PCIExpressHost), +}; + +static void pcie_host_register_types(void) +{ + type_register_static(&pcie_host_type_info); +} + +type_init(pcie_host_register_types) diff --git a/hw/pcie_host.h b/hw/pci/pcie_host.h index 0074508b43..1228e36cb2 100644 --- a/hw/pcie_host.h +++ b/hw/pci/pcie_host.h @@ -21,8 +21,12 @@ #ifndef PCIE_HOST_H #define PCIE_HOST_H -#include "pci_host.h" -#include "memory.h" +#include "hw/pci/pci_host.h" +#include "exec/memory.h" + +#define TYPE_PCIE_HOST_BRIDGE "pcie-host-bridge" +#define PCIE_HOST_BRIDGE(obj) \ + OBJECT_CHECK(PCIExpressHost, (obj), TYPE_PCIE_HOST_BRIDGE) struct PCIExpressHost { PCIHostState pci; @@ -30,20 +34,21 @@ struct PCIExpressHost { /* express part */ /* base address where MMCONFIG area is mapped. */ - target_phys_addr_t base_addr; + hwaddr base_addr; /* the size of MMCONFIG area. It's host bridge dependent */ - target_phys_addr_t size; + hwaddr size; /* MMCONFIG mmio area */ MemoryRegion mmio; }; -int pcie_host_init(PCIExpressHost *e, uint32_t size); +int pcie_host_init(PCIExpressHost *e); void pcie_host_mmcfg_unmap(PCIExpressHost *e); -void pcie_host_mmcfg_map(PCIExpressHost *e, target_phys_addr_t addr); +void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, uint32_t size); void pcie_host_mmcfg_update(PCIExpressHost *e, int enable, - target_phys_addr_t addr); + hwaddr addr, + uint32_t size); #endif /* PCIE_HOST_H */ diff --git a/hw/pcie_port.c b/hw/pci/pcie_port.c index d6350e5e73..33a6b0a08a 100644 --- a/hw/pcie_port.c +++ b/hw/pci/pcie_port.c @@ -18,7 +18,7 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "pcie_port.h" +#include "hw/pci/pcie_port.h" void pcie_port_init_reg(PCIDevice *d) { diff --git a/hw/pcie_port.h b/hw/pci/pcie_port.h index 3709583cc0..d89aa615c5 100644 --- a/hw/pcie_port.h +++ b/hw/pci/pcie_port.h @@ -21,8 +21,8 @@ #ifndef QEMU_PCIE_PORT_H #define QEMU_PCIE_PORT_H -#include "pci_bridge.h" -#include "pci_internals.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_bus.h" struct PCIEPort { PCIBridge br; diff --git a/hw/pcie_regs.h b/hw/pci/pcie_regs.h index 4d123d9fcc..4d123d9fcc 100644 --- a/hw/pcie_regs.h +++ b/hw/pci/pcie_regs.h diff --git a/hw/shpc.c b/hw/pci/shpc.c index 6b9884d544..f07266da66 100644 --- a/hw/shpc.c +++ b/hw/pci/shpc.c @@ -1,11 +1,11 @@ #include <strings.h> #include <stdint.h> -#include "range.h" -#include "range.h" -#include "shpc.h" -#include "pci.h" -#include "pci_internals.h" -#include "msi.h" +#include "qemu/range.h" +#include "qemu/range.h" +#include "hw/pci/shpc.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" +#include "hw/pci/msi.h" /* TODO: model power only and disabled slot states. */ /* TODO: handle SERR and wakeups */ @@ -253,7 +253,6 @@ static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot) ++devfn) { PCIDevice *affected_dev = shpc->sec_bus->devices[devfn]; if (affected_dev) { - object_unparent(OBJECT(affected_dev)); qdev_free(&affected_dev->qdev); } } @@ -467,13 +466,13 @@ static int shpc_cap_add_config(PCIDevice *d) return 0; } -static uint64_t shpc_mmio_read(void *opaque, target_phys_addr_t addr, +static uint64_t shpc_mmio_read(void *opaque, hwaddr addr, unsigned size) { return shpc_read(opaque, addr, size); } -static void shpc_mmio_write(void *opaque, target_phys_addr_t addr, +static void shpc_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { shpc_write(opaque, addr, val, size); diff --git a/hw/shpc.h b/hw/pci/shpc.h index 130b71df30..467911a558 100644 --- a/hw/shpc.h +++ b/hw/pci/shpc.h @@ -2,8 +2,8 @@ #define SHPC_H #include "qemu-common.h" -#include "memory.h" -#include "vmstate.h" +#include "exec/memory.h" +#include "migration/vmstate.h" struct SHPCDevice { /* Capability offset in device's config space */ diff --git a/hw/slotid_cap.c b/hw/pci/slotid_cap.c index 01064521a9..99a30f429d 100644 --- a/hw/slotid_cap.c +++ b/hw/pci/slotid_cap.c @@ -1,5 +1,5 @@ -#include "slotid_cap.h" -#include "pci.h" +#include "hw/pci/slotid_cap.h" +#include "hw/pci/pci.h" #define SLOTID_CAP_LENGTH 4 #define SLOTID_NSLOTS_SHIFT (ffs(PCI_SID_ESR_NSLOTS) - 1) diff --git a/hw/slotid_cap.h b/hw/pci/slotid_cap.h index 70db0470b0..70db0470b0 100644 --- a/hw/slotid_cap.h +++ b/hw/pci/slotid_cap.h diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c index f7063961a0..7818dcc350 100644 --- a/hw/pci_bridge_dev.c +++ b/hw/pci_bridge_dev.c @@ -19,13 +19,13 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "pci_bridge.h" -#include "pci_ids.h" -#include "msi.h" -#include "shpc.h" -#include "slotid_cap.h" -#include "memory.h" -#include "pci_internals.h" +#include "pci/pci_bridge.h" +#include "pci/pci_ids.h" +#include "pci/msi.h" +#include "pci/shpc.h" +#include "pci/slotid_cap.h" +#include "exec/memory.h" +#include "pci/pci_bus.h" #define REDHAT_PCI_VENDOR_ID 0x1b36 #define PCI_BRIDGE_DEV_VENDOR_ID REDHAT_PCI_VENDOR_ID diff --git a/hw/pckbd.c b/hw/pckbd.c index 69857bade9..6db7bbcc06 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -25,7 +25,7 @@ #include "isa.h" #include "pc.h" #include "ps2.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" /* debug PC keyboard */ //#define DEBUG_KBD @@ -139,7 +139,7 @@ typedef struct KBDState { qemu_irq irq_kbd; qemu_irq irq_mouse; qemu_irq *a20_out; - target_phys_addr_t mask; + hwaddr mask; } KBDState; /* update irq and KBD_STAT_[MOUSE_]OBF */ @@ -194,7 +194,8 @@ static void kbd_update_aux_irq(void *opaque, int level) kbd_update_irq(s); } -static uint32_t kbd_read_status(void *opaque, uint32_t addr) +static uint64_t kbd_read_status(void *opaque, hwaddr addr, + unsigned size) { KBDState *s = opaque; int val; @@ -223,7 +224,8 @@ static void outport_write(KBDState *s, uint32_t val) } } -static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) +static void kbd_write_command(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { KBDState *s = opaque; @@ -303,12 +305,13 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) /* ignore that */ break; default: - fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val); + fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", (int)val); break; } } -static uint32_t kbd_read_data(void *opaque, uint32_t addr) +static uint64_t kbd_read_data(void *opaque, hwaddr addr, + unsigned size) { KBDState *s = opaque; uint32_t val; @@ -322,7 +325,8 @@ static uint32_t kbd_read_data(void *opaque, uint32_t addr) return val; } -static void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) +static void kbd_write_data(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { KBDState *s = opaque; @@ -380,24 +384,24 @@ static const VMStateDescription vmstate_kbd = { }; /* Memory mapped interface */ -static uint32_t kbd_mm_readb (void *opaque, target_phys_addr_t addr) +static uint32_t kbd_mm_readb (void *opaque, hwaddr addr) { KBDState *s = opaque; if (addr & s->mask) - return kbd_read_status(s, 0) & 0xff; + return kbd_read_status(s, 0, 1) & 0xff; else - return kbd_read_data(s, 0) & 0xff; + return kbd_read_data(s, 0, 1) & 0xff; } -static void kbd_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +static void kbd_mm_writeb (void *opaque, hwaddr addr, uint32_t value) { KBDState *s = opaque; if (addr & s->mask) - kbd_write_command(s, 0, value & 0xff); + kbd_write_command(s, 0, value & 0xff, 1); else - kbd_write_data(s, 0, value & 0xff); + kbd_write_data(s, 0, value & 0xff, 1); } static const MemoryRegionOps i8042_mmio_ops = { @@ -410,7 +414,7 @@ static const MemoryRegionOps i8042_mmio_ops = { void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, MemoryRegion *region, ram_addr_t size, - target_phys_addr_t mask) + hwaddr mask) { KBDState *s = g_malloc0(sizeof(KBDState)); @@ -459,22 +463,24 @@ static const VMStateDescription vmstate_kbd_isa = { } }; -static const MemoryRegionPortio i8042_data_portio[] = { - { 0, 1, 1, .read = kbd_read_data, .write = kbd_write_data }, - PORTIO_END_OF_LIST() -}; - -static const MemoryRegionPortio i8042_cmd_portio[] = { - { 0, 1, 1, .read = kbd_read_status, .write = kbd_write_command }, - PORTIO_END_OF_LIST() -}; - static const MemoryRegionOps i8042_data_ops = { - .old_portio = i8042_data_portio + .read = kbd_read_data, + .write = kbd_write_data, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static const MemoryRegionOps i8042_cmd_ops = { - .old_portio = i8042_cmd_portio + .read = kbd_read_status, + .write = kbd_write_command, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static int i8042_initfn(ISADevice *dev) diff --git a/hw/pcmcia.h b/hw/pcmcia.h index 50648c973f..aac1d77cc7 100644 --- a/hw/pcmcia.h +++ b/hw/pcmcia.h @@ -1,3 +1,6 @@ +#ifndef HW_PCMCIA_H +#define HW_PCMCIA_H 1 + /* PCMCIA/Cardbus */ #include "qemu-common.h" @@ -49,3 +52,5 @@ struct PCMCIACardState { /* dscm1xxxx.c */ PCMCIACardState *dscm1xxxx_init(DriveInfo *bdrv); + +#endif diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index 48fd447996..40a0e6eda4 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -27,11 +27,11 @@ * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 */ -#include "pci.h" -#include "net.h" +#include "pci/pci.h" +#include "net/net.h" #include "loader.h" -#include "qemu-timer.h" -#include "dma.h" +#include "qemu/timer.h" +#include "sysemu/dma.h" #include "pcnet.h" @@ -71,7 +71,7 @@ static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr) return val; } -static uint64_t pcnet_ioport_read(void *opaque, target_phys_addr_t addr, +static uint64_t pcnet_ioport_read(void *opaque, hwaddr addr, unsigned size) { PCNetState *d = opaque; @@ -98,7 +98,7 @@ static uint64_t pcnet_ioport_read(void *opaque, target_phys_addr_t addr, return ((uint64_t)1 << (size * 8)) - 1; } -static void pcnet_ioport_write(void *opaque, target_phys_addr_t addr, +static void pcnet_ioport_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { PCNetState *d = opaque; @@ -130,7 +130,7 @@ static const MemoryRegionOps pcnet_io_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void pcnet_mmio_writeb(void *opaque, hwaddr addr, uint32_t val) { PCNetState *d = opaque; #ifdef PCNET_DEBUG_IO @@ -141,7 +141,7 @@ static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t va pcnet_aprom_writeb(d, addr & 0x0f, val); } -static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) +static uint32_t pcnet_mmio_readb(void *opaque, hwaddr addr) { PCNetState *d = opaque; uint32_t val = -1; @@ -154,7 +154,7 @@ static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) return val; } -static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +static void pcnet_mmio_writew(void *opaque, hwaddr addr, uint32_t val) { PCNetState *d = opaque; #ifdef PCNET_DEBUG_IO @@ -170,7 +170,7 @@ static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t va } } -static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) +static uint32_t pcnet_mmio_readw(void *opaque, hwaddr addr) { PCNetState *d = opaque; uint32_t val = -1; @@ -189,7 +189,7 @@ static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) return val; } -static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void pcnet_mmio_writel(void *opaque, hwaddr addr, uint32_t val) { PCNetState *d = opaque; #ifdef PCNET_DEBUG_IO @@ -207,7 +207,7 @@ static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t va } } -static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) +static uint32_t pcnet_mmio_readl(void *opaque, hwaddr addr) { PCNetState *d = opaque; uint32_t val; @@ -252,13 +252,13 @@ static const MemoryRegionOps pcnet_mmio_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr, +static void pci_physical_memory_write(void *dma_opaque, hwaddr addr, uint8_t *buf, int len, int do_bswap) { pci_dma_write(dma_opaque, addr, buf, len); } -static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, +static void pci_physical_memory_read(void *dma_opaque, hwaddr addr, uint8_t *buf, int len, int do_bswap) { pci_dma_read(dma_opaque, addr, buf, len); diff --git a/hw/pcnet.c b/hw/pcnet.c index 40820b3632..30f100007a 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -36,10 +36,10 @@ */ #include "qdev.h" -#include "net.h" -#include "qemu-timer.h" -#include "qemu_socket.h" -#include "sysemu.h" +#include "net/net.h" +#include "qemu/timer.h" +#include "qemu/sockets.h" +#include "sysemu/sysemu.h" #include "pcnet.h" @@ -293,7 +293,7 @@ struct pcnet_RMD { GET_FIELD((R)->msg_length, RMDM, ZEROS)) static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, - target_phys_addr_t addr) + hwaddr addr) { if (!BCR_SSIZE32(s)) { struct { @@ -323,7 +323,7 @@ static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, } static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd, - target_phys_addr_t addr) + hwaddr addr) { if (!BCR_SSIZE32(s)) { struct { @@ -359,7 +359,7 @@ static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd, } static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, - target_phys_addr_t addr) + hwaddr addr) { if (!BCR_SSIZE32(s)) { struct { @@ -389,7 +389,7 @@ static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, } static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, - target_phys_addr_t addr) + hwaddr addr) { if (!BCR_SSIZE32(s)) { struct { @@ -660,7 +660,7 @@ static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size) return 0; } -static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx) +static inline hwaddr pcnet_rdra_addr(PCNetState *s, int idx) { while (idx < 1) idx += CSR_RCVRL(s); return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8)); @@ -898,19 +898,19 @@ static void pcnet_rdte_poll(PCNetState *s) if (s->rdra) { int bad = 0; #if 1 - target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s)); - target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s)); - target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s)); + hwaddr crda = pcnet_rdra_addr(s, CSR_RCVRC(s)); + hwaddr nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s)); + hwaddr nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s)); #else - target_phys_addr_t crda = s->rdra + + hwaddr crda = s->rdra + (CSR_RCVRL(s) - CSR_RCVRC(s)) * (BCR_SWSTYLE(s) ? 16 : 8 ); int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1; - target_phys_addr_t nrda = s->rdra + + hwaddr nrda = s->rdra + (CSR_RCVRL(s) - nrdc) * (BCR_SWSTYLE(s) ? 16 : 8 ); int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1; - target_phys_addr_t nnrd = s->rdra + + hwaddr nnrd = s->rdra + (CSR_RCVRL(s) - nnrc) * (BCR_SWSTYLE(s) ? 16 : 8 ); #endif @@ -970,7 +970,7 @@ static int pcnet_tdte_poll(PCNetState *s) { s->csr[34] = s->csr[35] = 0; if (s->tdra) { - target_phys_addr_t cxda = s->tdra + + hwaddr cxda = s->tdra + (CSR_XMTRL(s) - CSR_XMTRC(s)) * (BCR_SWSTYLE(s) ? 16 : 8); int bad = 0; @@ -1050,7 +1050,7 @@ ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_) if (!(CSR_CRST(s) & 0x8000) && s->rdra) { struct pcnet_RMD rmd; int rcvrc = CSR_RCVRC(s)-1,i; - target_phys_addr_t nrda; + hwaddr nrda; for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) { if (rcvrc <= 1) rcvrc = CSR_RCVRL(s); @@ -1078,7 +1078,7 @@ ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_) CSR_MISSC(s)++; } else { uint8_t *src = s->buffer; - target_phys_addr_t crda = CSR_CRDA(s); + hwaddr crda = CSR_CRDA(s); struct pcnet_RMD rmd; int pktcount = 0; @@ -1118,7 +1118,7 @@ ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_) #define PCNET_RECV_STORE() do { \ int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),remaining); \ - target_phys_addr_t rbadr = PHYSADDR(s, rmd.rbadr); \ + hwaddr rbadr = PHYSADDR(s, rmd.rbadr); \ s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \ src += count; remaining -= count; \ SET_FIELD(&rmd.status, RMDS, OWN, 0); \ @@ -1129,7 +1129,7 @@ ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_) remaining = size; PCNET_RECV_STORE(); if ((remaining > 0) && CSR_NRDA(s)) { - target_phys_addr_t nrda = CSR_NRDA(s); + hwaddr nrda = CSR_NRDA(s); #ifdef PCNET_DEBUG_RMD PRINT_RMD(&rmd); #endif @@ -1206,7 +1206,7 @@ void pcnet_set_link_status(NetClientState *nc) static void pcnet_transmit(PCNetState *s) { - target_phys_addr_t xmit_cxda = 0; + hwaddr xmit_cxda = 0; int count = CSR_XMTRL(s)-1; int add_crc = 0; diff --git a/hw/pcnet.h b/hw/pcnet.h index d0af54a46a..9dee6f3e2c 100644 --- a/hw/pcnet.h +++ b/hw/pcnet.h @@ -1,10 +1,13 @@ +#ifndef HW_PCNET_H +#define HW_PCNET_H 1 + #define PCNET_IOPORT_SIZE 0x20 #define PCNET_PNPMMIO_SIZE 0x20 #define PCNET_LOOPTEST_CRC 1 #define PCNET_LOOPTEST_NOCRC 2 -#include "memory.h" +#include "exec/memory.h" /* BUS CONFIGURATION REGISTERS */ #define BCR_MSRDA 0 @@ -42,9 +45,9 @@ struct PCNetState_st { MemoryRegion mmio; uint8_t buffer[4096]; qemu_irq irq; - void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr, + void (*phys_mem_read)(void *dma_opaque, hwaddr addr, uint8_t *buf, int len, int do_bswap); - void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr, + void (*phys_mem_write)(void *dma_opaque, hwaddr addr, uint8_t *buf, int len, int do_bswap); void *dma_opaque; int tx_busy; @@ -63,3 +66,5 @@ void pcnet_set_link_status(NetClientState *nc); void pcnet_common_cleanup(PCNetState *d); int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info); extern const VMStateDescription vmstate_pcnet; + +#endif diff --git a/hw/pcspk.c b/hw/pcspk.c index e4303247d4..6d55ebe82f 100644 --- a/hw/pcspk.c +++ b/hw/pcspk.c @@ -26,7 +26,7 @@ #include "pc.h" #include "isa.h" #include "audio/audio.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "i8254.h" #include "pcspk.h" @@ -121,7 +121,7 @@ int pcspk_audio_init(ISABus *bus) return 0; } -static uint64_t pcspk_io_read(void *opaque, target_phys_addr_t addr, +static uint64_t pcspk_io_read(void *opaque, hwaddr addr, unsigned size) { PCSpkState *s = opaque; @@ -135,7 +135,7 @@ static uint64_t pcspk_io_read(void *opaque, target_phys_addr_t addr, (ch.out << 5); } -static void pcspk_io_write(void *opaque, target_phys_addr_t addr, uint64_t val, +static void pcspk_io_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { PCSpkState *s = opaque; diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c index dced648f45..1cfdb2f302 100644 --- a/hw/petalogix_ml605_mmu.c +++ b/hw/petalogix_ml605_mmu.c @@ -27,15 +27,16 @@ #include "sysbus.h" #include "hw.h" -#include "net.h" +#include "net/net.h" #include "flash.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "devices.h" #include "boards.h" #include "xilinx.h" -#include "blockdev.h" -#include "pc.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "serial.h" +#include "exec/address-spaces.h" +#include "ssi.h" #include "microblaze_boot.h" #include "microblaze_pic_cpu.h" @@ -47,6 +48,8 @@ #define BINARY_DEVICE_TREE_FILE "petalogix-ml605.dtb" +#define NUM_SPI_FLASHES 4 + #define MEMORY_BASEADDR 0x50000000 #define FLASH_BASEADDR 0x86000000 #define INTC_BASEADDR 0x81800000 @@ -70,19 +73,18 @@ static void machine_cpu_reset(MicroBlazeCPU *cpu) } static void -petalogix_ml605_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +petalogix_ml605_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; MemoryRegion *address_space_mem = get_system_memory(); DeviceState *dev, *dma, *eth0; MicroBlazeCPU *cpu; + SysBusDevice *busdev; CPUMBState *env; DriveInfo *dinfo; int i; - target_phys_addr_t ddr_base = MEMORY_BASEADDR; + hwaddr ddr_base = MEMORY_BASEADDR; MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1); MemoryRegion *phys_ram = g_new(MemoryRegion, 1); qemu_irq irq[32], *cpu_irq; @@ -139,6 +141,29 @@ petalogix_ml605_init(ram_addr_t ram_size, xilinx_axiethernetdma_init(dma, STREAM_SLAVE(eth0), 0x84600000, irq[1], irq[0], 100 * 1000000); + { + SSIBus *spi; + + dev = qdev_create(NULL, "xlnx.xps-spi"); + qdev_prop_set_uint8(dev, "num-ss-bits", NUM_SPI_FLASHES); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_mmio_map(busdev, 0, 0x40a00000); + sysbus_connect_irq(busdev, 0, irq[4]); + + spi = (SSIBus *)qdev_get_child_bus(dev, "spi"); + + for (i = 0; i < NUM_SPI_FLASHES; i++) { + qemu_irq cs_line; + + dev = ssi_create_slave_no_init(spi, "m25p80"); + qdev_prop_set_string(dev, "partname", "n25q128"); + qdev_init_nofail(dev); + cs_line = qdev_get_gpio_in(dev, 0); + sysbus_connect_irq(busdev, i+1, cs_line); + } + } + microblaze_load_kernel(cpu, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE, machine_cpu_reset); diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c index 2cf68828ed..27ecfe7752 100644 --- a/hw/petalogix_s3adsp1800_mmu.c +++ b/hw/petalogix_s3adsp1800_mmu.c @@ -25,14 +25,14 @@ #include "sysbus.h" #include "hw.h" -#include "net.h" +#include "net/net.h" #include "flash.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "devices.h" #include "boards.h" #include "xilinx.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" #include "microblaze_boot.h" #include "microblaze_pic_cpu.h" @@ -57,18 +57,16 @@ static void machine_cpu_reset(MicroBlazeCPU *cpu) } static void -petalogix_s3adsp1800_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +petalogix_s3adsp1800_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; DeviceState *dev; MicroBlazeCPU *cpu; CPUMBState *env; DriveInfo *dinfo; int i; - target_phys_addr_t ddr_base = MEMORY_BASEADDR; + hwaddr ddr_base = MEMORY_BASEADDR; MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1); MemoryRegion *phys_ram = g_new(MemoryRegion, 1); qemu_irq irq[32], *cpu_irq; diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index d1c742379b..aadedefb25 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -38,44 +38,51 @@ #include "hw.h" #include "flash.h" -#include "block.h" -#include "qemu-timer.h" -#include "exec-memory.h" +#include "block/block.h" +#include "qemu/timer.h" +#include "exec/address-spaces.h" +#include "qemu/host-utils.h" +#include "sysbus.h" #define PFLASH_BUG(fmt, ...) \ do { \ - printf("PFLASH: Possible BUG - " fmt, ## __VA_ARGS__); \ + fprintf(stderr, "PFLASH: Possible BUG - " fmt, ## __VA_ARGS__); \ exit(1); \ } while(0) /* #define PFLASH_DEBUG */ #ifdef PFLASH_DEBUG -#define DPRINTF(fmt, ...) \ -do { \ - printf("PFLASH: " fmt , ## __VA_ARGS__); \ +#define DPRINTF(fmt, ...) \ +do { \ + fprintf(stderr, "PFLASH: " fmt , ## __VA_ARGS__); \ } while (0) #else #define DPRINTF(fmt, ...) do { } while (0) #endif struct pflash_t { + SysBusDevice busdev; BlockDriverState *bs; - target_phys_addr_t base; - target_phys_addr_t sector_len; - target_phys_addr_t total_len; - int width; + uint32_t nb_blocs; + uint64_t sector_len; + uint8_t width; + uint8_t be; int wcycle; /* if 0, the flash is read normally */ int bypass; int ro; uint8_t cmd; uint8_t status; - uint16_t ident[4]; + uint16_t ident0; + uint16_t ident1; + uint16_t ident2; + uint16_t ident3; uint8_t cfi_len; uint8_t cfi_table[0x52]; - target_phys_addr_t counter; + hwaddr counter; unsigned int writeblock_size; QEMUTimer *timer; MemoryRegion mem; + char *name; void *storage; }; @@ -95,10 +102,10 @@ static void pflash_timer (void *opaque) pfl->cmd = 0; } -static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset, +static uint32_t pflash_read (pflash_t *pfl, hwaddr offset, int width, int be) { - target_phys_addr_t boff; + hwaddr boff; uint32_t ret; uint8_t *p; @@ -167,15 +174,16 @@ static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset, case 0x90: switch (boff) { case 0: - ret = pfl->ident[0] << 8 | pfl->ident[1]; + ret = pfl->ident0 << 8 | pfl->ident1; DPRINTF("%s: Manufacturer Code %04x\n", __func__, ret); break; case 1: - ret = pfl->ident[2] << 8 | pfl->ident[3]; + ret = pfl->ident2 << 8 | pfl->ident3; DPRINTF("%s: Device ID Code %04x\n", __func__, ret); break; default: - DPRINTF("%s: Read Device Information boff=%x\n", __func__, boff); + DPRINTF("%s: Read Device Information boff=%x\n", __func__, + (unsigned)boff); ret = 0; break; } @@ -210,7 +218,7 @@ static void pflash_update(pflash_t *pfl, int offset, } } -static inline void pflash_data_write(pflash_t *pfl, target_phys_addr_t offset, +static inline void pflash_data_write(pflash_t *pfl, hwaddr offset, uint32_t value, int width, int be) { uint8_t *p = pfl->storage; @@ -248,7 +256,7 @@ static inline void pflash_data_write(pflash_t *pfl, target_phys_addr_t offset, } -static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, +static void pflash_write(pflash_t *pfl, hwaddr offset, uint32_t value, int width, int be) { uint8_t *p; @@ -278,9 +286,8 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, p = pfl->storage; offset &= ~(pfl->sector_len - 1); - DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes " - TARGET_FMT_plx "\n", - __func__, offset, pfl->sector_len); + DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes %x\n", + __func__, offset, (unsigned)pfl->sector_len); if (!pfl->ro) { memset(p + offset, 0xff, pfl->sector_len); @@ -312,6 +319,9 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, DPRINTF("%s: Write to buffer\n", __func__); pfl->status |= 0x80; /* Ready! */ break; + case 0xf0: /* Probe for AMD flash */ + DPRINTF("%s: Probe for AMD flash\n", __func__); + goto reset_flash; case 0xff: /* Read array mode */ DPRINTF("%s: Read array mode\n", __func__); goto reset_flash; @@ -320,7 +330,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, } pfl->wcycle++; pfl->cmd = cmd; - return; + break; case 1: switch (pfl->cmd) { case 0x10: /* Single Byte Program */ @@ -375,7 +385,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, default: goto error_flash; } - return; + break; case 2: switch (pfl->cmd) { case 0xe8: /* Block write */ @@ -388,7 +398,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, pfl->status |= 0x80; if (!pfl->counter) { - target_phys_addr_t mask = pfl->writeblock_size - 1; + hwaddr mask = pfl->writeblock_size - 1; mask = ~mask; DPRINTF("%s: block write finished\n", __func__); @@ -406,7 +416,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, default: goto error_flash; } - return; + break; case 3: /* Confirm mode */ switch (pfl->cmd) { case 0xe8: /* Block write */ @@ -422,7 +432,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, default: goto error_flash; } - return; + break; default: /* Should never happen */ DPRINTF("%s: invalid write state\n", __func__); @@ -431,9 +441,9 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, return; error_flash: - printf("%s: Unimplemented flash cmd sequence " - "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)\n", - __func__, offset, pfl->wcycle, pfl->cmd, value); + qemu_log_mask(LOG_UNIMP, "%s: Unimplemented flash cmd sequence " + "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)" + "\n", __func__, offset, pfl->wcycle, pfl->cmd, value); reset_flash: memory_region_rom_device_set_readable(&pfl->mem, true); @@ -441,61 +451,60 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, pfl->bypass = 0; pfl->wcycle = 0; pfl->cmd = 0; - return; } -static uint32_t pflash_readb_be(void *opaque, target_phys_addr_t addr) +static uint32_t pflash_readb_be(void *opaque, hwaddr addr) { return pflash_read(opaque, addr, 1, 1); } -static uint32_t pflash_readb_le(void *opaque, target_phys_addr_t addr) +static uint32_t pflash_readb_le(void *opaque, hwaddr addr) { return pflash_read(opaque, addr, 1, 0); } -static uint32_t pflash_readw_be(void *opaque, target_phys_addr_t addr) +static uint32_t pflash_readw_be(void *opaque, hwaddr addr) { pflash_t *pfl = opaque; return pflash_read(pfl, addr, 2, 1); } -static uint32_t pflash_readw_le(void *opaque, target_phys_addr_t addr) +static uint32_t pflash_readw_le(void *opaque, hwaddr addr) { pflash_t *pfl = opaque; return pflash_read(pfl, addr, 2, 0); } -static uint32_t pflash_readl_be(void *opaque, target_phys_addr_t addr) +static uint32_t pflash_readl_be(void *opaque, hwaddr addr) { pflash_t *pfl = opaque; return pflash_read(pfl, addr, 4, 1); } -static uint32_t pflash_readl_le(void *opaque, target_phys_addr_t addr) +static uint32_t pflash_readl_le(void *opaque, hwaddr addr) { pflash_t *pfl = opaque; return pflash_read(pfl, addr, 4, 0); } -static void pflash_writeb_be(void *opaque, target_phys_addr_t addr, +static void pflash_writeb_be(void *opaque, hwaddr addr, uint32_t value) { pflash_write(opaque, addr, value, 1, 1); } -static void pflash_writeb_le(void *opaque, target_phys_addr_t addr, +static void pflash_writeb_le(void *opaque, hwaddr addr, uint32_t value) { pflash_write(opaque, addr, value, 1, 0); } -static void pflash_writew_be(void *opaque, target_phys_addr_t addr, +static void pflash_writew_be(void *opaque, hwaddr addr, uint32_t value) { pflash_t *pfl = opaque; @@ -503,7 +512,7 @@ static void pflash_writew_be(void *opaque, target_phys_addr_t addr, pflash_write(pfl, addr, value, 2, 1); } -static void pflash_writew_le(void *opaque, target_phys_addr_t addr, +static void pflash_writew_le(void *opaque, hwaddr addr, uint32_t value) { pflash_t *pfl = opaque; @@ -511,7 +520,7 @@ static void pflash_writew_le(void *opaque, target_phys_addr_t addr, pflash_write(pfl, addr, value, 2, 0); } -static void pflash_writel_be(void *opaque, target_phys_addr_t addr, +static void pflash_writel_be(void *opaque, hwaddr addr, uint32_t value) { pflash_t *pfl = opaque; @@ -519,7 +528,7 @@ static void pflash_writel_be(void *opaque, target_phys_addr_t addr, pflash_write(pfl, addr, value, 4, 1); } -static void pflash_writel_le(void *opaque, target_phys_addr_t addr, +static void pflash_writel_le(void *opaque, hwaddr addr, uint32_t value) { pflash_t *pfl = opaque; @@ -543,55 +552,13 @@ static const MemoryRegionOps pflash_cfi01_ops_le = { .endianness = DEVICE_NATIVE_ENDIAN, }; -/* Count trailing zeroes of a 32 bits quantity */ -static int ctz32 (uint32_t n) -{ - int ret; - - ret = 0; - if (!(n & 0xFFFF)) { - ret += 16; - n = n >> 16; - } - if (!(n & 0xFF)) { - ret += 8; - n = n >> 8; - } - if (!(n & 0xF)) { - ret += 4; - n = n >> 4; - } - if (!(n & 0x3)) { - ret += 2; - n = n >> 2; - } - if (!(n & 0x1)) { - ret++; -#if 0 /* This is not necessary as n is never 0 */ - n = n >> 1; -#endif - } -#if 0 /* This is not necessary as n is never 0 */ - if (!n) - ret++; -#endif - - return ret; -} - -pflash_t *pflash_cfi01_register(target_phys_addr_t base, - DeviceState *qdev, const char *name, - target_phys_addr_t size, - BlockDriverState *bs, uint32_t sector_len, - int nb_blocs, int width, - uint16_t id0, uint16_t id1, - uint16_t id2, uint16_t id3, int be) +static int pflash_cfi01_init(SysBusDevice *dev) { - pflash_t *pfl; - target_phys_addr_t total_len; + pflash_t *pfl = FROM_SYSBUS(typeof(*pfl), dev); + uint64_t total_len; int ret; - total_len = sector_len * nb_blocs; + total_len = pfl->sector_len * pfl->nb_blocs; /* XXX: to be fixed */ #if 0 @@ -600,27 +567,22 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, return NULL; #endif - pfl = g_malloc0(sizeof(pflash_t)); - memory_region_init_rom_device( - &pfl->mem, be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl, - name, size); - vmstate_register_ram(&pfl->mem, qdev); + &pfl->mem, pfl->be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl, + pfl->name, total_len); + vmstate_register_ram(&pfl->mem, DEVICE(pfl)); pfl->storage = memory_region_get_ram_ptr(&pfl->mem); - memory_region_add_subregion(get_system_memory(), base, &pfl->mem); + sysbus_init_mmio(dev, &pfl->mem); - pfl->bs = bs; if (pfl->bs) { /* read the initial flash content */ ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9); + if (ret < 0) { - memory_region_del_subregion(get_system_memory(), &pfl->mem); - vmstate_unregister_ram(&pfl->mem, qdev); + vmstate_unregister_ram(&pfl->mem, DEVICE(pfl)); memory_region_destroy(&pfl->mem); - g_free(pfl); - return NULL; + return 1; } - bdrv_attach_dev_nofail(pfl->bs, pfl); } if (pfl->bs) { @@ -630,17 +592,9 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, } pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl); - pfl->base = base; - pfl->sector_len = sector_len; - pfl->total_len = total_len; - pfl->width = width; pfl->wcycle = 0; pfl->cmd = 0; pfl->status = 0; - pfl->ident[0] = id0; - pfl->ident[1] = id1; - pfl->ident[2] = id2; - pfl->ident[3] = id3; /* Hardcoded CFI table */ pfl->cfi_len = 0x52; /* Standard "QRY" string */ @@ -689,7 +643,7 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, pfl->cfi_table[0x28] = 0x02; pfl->cfi_table[0x29] = 0x00; /* Max number of bytes in multi-bytes write */ - if (width == 1) { + if (pfl->width == 1) { pfl->cfi_table[0x2A] = 0x08; } else { pfl->cfi_table[0x2A] = 0x0B; @@ -700,10 +654,10 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, /* Number of erase block regions (uniform) */ pfl->cfi_table[0x2C] = 0x01; /* Erase block region 1 */ - pfl->cfi_table[0x2D] = nb_blocs - 1; - pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8; - pfl->cfi_table[0x2F] = sector_len >> 8; - pfl->cfi_table[0x30] = sector_len >> 16; + pfl->cfi_table[0x2D] = pfl->nb_blocs - 1; + pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8; + pfl->cfi_table[0x2F] = pfl->sector_len >> 8; + pfl->cfi_table[0x30] = pfl->sector_len >> 16; /* Extended */ pfl->cfi_table[0x31] = 'P'; @@ -711,7 +665,7 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, pfl->cfi_table[0x33] = 'I'; pfl->cfi_table[0x34] = '1'; - pfl->cfi_table[0x35] = '1'; + pfl->cfi_table[0x35] = '0'; pfl->cfi_table[0x36] = 0x00; pfl->cfi_table[0x37] = 0x00; @@ -723,6 +677,77 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, pfl->cfi_table[0x3b] = 0x00; pfl->cfi_table[0x3c] = 0x00; + pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */ + + return 0; +} + +static Property pflash_cfi01_properties[] = { + DEFINE_PROP_DRIVE("drive", struct pflash_t, bs), + DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0), + DEFINE_PROP_UINT64("sector-length", struct pflash_t, sector_len, 0), + DEFINE_PROP_UINT8("width", struct pflash_t, width, 0), + DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0), + DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0), + DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0), + DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0), + DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0), + DEFINE_PROP_STRING("name", struct pflash_t, name), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pflash_cfi01_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pflash_cfi01_init; + dc->props = pflash_cfi01_properties; +} + + +static const TypeInfo pflash_cfi01_info = { + .name = "cfi.pflash01", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct pflash_t), + .class_init = pflash_cfi01_class_init, +}; + +static void pflash_cfi01_register_types(void) +{ + type_register_static(&pflash_cfi01_info); +} + +type_init(pflash_cfi01_register_types) + +pflash_t *pflash_cfi01_register(hwaddr base, + DeviceState *qdev, const char *name, + hwaddr size, + BlockDriverState *bs, + uint32_t sector_len, int nb_blocs, int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3, int be) +{ + DeviceState *dev = qdev_create(NULL, "cfi.pflash01"); + SysBusDevice *busdev = sysbus_from_qdev(dev); + pflash_t *pfl = (pflash_t *)object_dynamic_cast(OBJECT(dev), + "cfi.pflash01"); + + if (bs && qdev_prop_set_drive(dev, "drive", bs)) { + abort(); + } + qdev_prop_set_uint32(dev, "num-blocks", nb_blocs); + qdev_prop_set_uint64(dev, "sector-length", sector_len); + qdev_prop_set_uint8(dev, "width", width); + qdev_prop_set_uint8(dev, "big-endian", !!be); + qdev_prop_set_uint16(dev, "id0", id0); + qdev_prop_set_uint16(dev, "id1", id1); + qdev_prop_set_uint16(dev, "id2", id2); + qdev_prop_set_uint16(dev, "id3", id3); + qdev_prop_set_string(dev, "name", name); + qdev_init_nofail(dev); + + sysbus_mmio_map(busdev, 0, base); return pfl; } diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 3e2002e4b3..cfb91cb143 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -37,15 +37,17 @@ #include "hw.h" #include "flash.h" -#include "qemu-timer.h" -#include "block.h" -#include "exec-memory.h" +#include "qemu/timer.h" +#include "block/block.h" +#include "exec/address-spaces.h" +#include "qemu/host-utils.h" +#include "sysbus.h" //#define PFLASH_DEBUG #ifdef PFLASH_DEBUG -#define DPRINTF(fmt, ...) \ -do { \ - printf("PFLASH: " fmt , ## __VA_ARGS__); \ +#define DPRINTF(fmt, ...) \ +do { \ + fprintf(stderr "PFLASH: " fmt , ## __VA_ARGS__); \ } while (0) #else #define DPRINTF(fmt, ...) do { } while (0) @@ -54,19 +56,26 @@ do { \ #define PFLASH_LAZY_ROMD_THRESHOLD 42 struct pflash_t { + SysBusDevice busdev; BlockDriverState *bs; - target_phys_addr_t base; uint32_t sector_len; + uint32_t nb_blocs; uint32_t chip_len; - int mappings; - int width; + uint8_t mappings; + uint8_t width; + uint8_t be; int wcycle; /* if 0, the flash is read normally */ int bypass; int ro; uint8_t cmd; uint8_t status; - uint16_t ident[4]; - uint16_t unlock_addr[2]; + /* FIXME: implement array device properties */ + uint16_t ident0; + uint16_t ident1; + uint16_t ident2; + uint16_t ident3; + uint16_t unlock_addr0; + uint16_t unlock_addr1; uint8_t cfi_len; uint8_t cfi_table[0x52]; QEMUTimer *timer; @@ -79,6 +88,7 @@ struct pflash_t { MemoryRegion orig_mem; int rom_mode; int read_counter; /* used for lazy switch-back to rom mode */ + char *name; void *storage; }; @@ -88,7 +98,7 @@ struct pflash_t { static void pflash_setup_mappings(pflash_t *pfl) { unsigned i; - target_phys_addr_t size = memory_region_size(&pfl->orig_mem); + hwaddr size = memory_region_size(&pfl->orig_mem); memory_region_init(&pfl->mem, "pflash", pfl->mappings * size); pfl->mem_mappings = g_new(MemoryRegion, pfl->mappings); @@ -121,10 +131,10 @@ static void pflash_timer (void *opaque) pfl->cmd = 0; } -static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset, +static uint32_t pflash_read (pflash_t *pfl, hwaddr offset, int width, int be) { - target_phys_addr_t boff; + hwaddr boff; uint32_t ret; uint8_t *p; @@ -189,16 +199,17 @@ static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset, switch (boff) { case 0x00: case 0x01: - ret = pfl->ident[boff & 0x01]; + ret = boff & 0x01 ? pfl->ident1 : pfl->ident0; break; case 0x02: ret = 0x00; /* Pretend all sectors are unprotected */ break; case 0x0E: case 0x0F: - if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1) + ret = boff & 0x01 ? pfl->ident3 : pfl->ident2; + if (ret == (uint8_t)-1) { goto flash_read; - ret = pfl->ident[2 + (boff & 0x01)]; + } break; default: goto flash_read; @@ -241,10 +252,10 @@ static void pflash_update(pflash_t *pfl, int offset, } } -static void pflash_write (pflash_t *pfl, target_phys_addr_t offset, +static void pflash_write (pflash_t *pfl, hwaddr offset, uint32_t value, int width, int be) { - target_phys_addr_t boff; + hwaddr boff; uint8_t *p; uint8_t cmd; @@ -282,9 +293,9 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset, pfl->cmd = 0x98; return; } - if (boff != pfl->unlock_addr[0] || cmd != 0xAA) { + if (boff != pfl->unlock_addr0 || cmd != 0xAA) { DPRINTF("%s: unlock0 failed " TARGET_FMT_plx " %02x %04x\n", - __func__, boff, cmd, pfl->unlock_addr[0]); + __func__, boff, cmd, pfl->unlock_addr0); goto reset_flash; } DPRINTF("%s: unlock sequence started\n", __func__); @@ -292,7 +303,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset, case 1: /* We started an unlock sequence */ check_unlock1: - if (boff != pfl->unlock_addr[1] || cmd != 0x55) { + if (boff != pfl->unlock_addr1 || cmd != 0x55) { DPRINTF("%s: unlock1 failed " TARGET_FMT_plx " %02x\n", __func__, boff, cmd); goto reset_flash; @@ -301,7 +312,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset, break; case 2: /* We finished an unlock sequence */ - if (!pfl->bypass && boff != pfl->unlock_addr[0]) { + if (!pfl->bypass && boff != pfl->unlock_addr0) { DPRINTF("%s: command failed " TARGET_FMT_plx " %02x\n", __func__, boff, cmd); goto reset_flash; @@ -399,7 +410,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset, case 5: switch (cmd) { case 0x10: - if (boff != pfl->unlock_addr[0]) { + if (boff != pfl->unlock_addr0) { DPRINTF("%s: chip erase: invalid address " TARGET_FMT_plx "\n", __func__, offset); goto reset_flash; @@ -473,61 +484,60 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset, do_bypass: pfl->wcycle = 2; pfl->cmd = 0; - return; } -static uint32_t pflash_readb_be(void *opaque, target_phys_addr_t addr) +static uint32_t pflash_readb_be(void *opaque, hwaddr addr) { return pflash_read(opaque, addr, 1, 1); } -static uint32_t pflash_readb_le(void *opaque, target_phys_addr_t addr) +static uint32_t pflash_readb_le(void *opaque, hwaddr addr) { return pflash_read(opaque, addr, 1, 0); } -static uint32_t pflash_readw_be(void *opaque, target_phys_addr_t addr) +static uint32_t pflash_readw_be(void *opaque, hwaddr addr) { pflash_t *pfl = opaque; return pflash_read(pfl, addr, 2, 1); } -static uint32_t pflash_readw_le(void *opaque, target_phys_addr_t addr) +static uint32_t pflash_readw_le(void *opaque, hwaddr addr) { pflash_t *pfl = opaque; return pflash_read(pfl, addr, 2, 0); } -static uint32_t pflash_readl_be(void *opaque, target_phys_addr_t addr) +static uint32_t pflash_readl_be(void *opaque, hwaddr addr) { pflash_t *pfl = opaque; return pflash_read(pfl, addr, 4, 1); } -static uint32_t pflash_readl_le(void *opaque, target_phys_addr_t addr) +static uint32_t pflash_readl_le(void *opaque, hwaddr addr) { pflash_t *pfl = opaque; return pflash_read(pfl, addr, 4, 0); } -static void pflash_writeb_be(void *opaque, target_phys_addr_t addr, +static void pflash_writeb_be(void *opaque, hwaddr addr, uint32_t value) { pflash_write(opaque, addr, value, 1, 1); } -static void pflash_writeb_le(void *opaque, target_phys_addr_t addr, +static void pflash_writeb_le(void *opaque, hwaddr addr, uint32_t value) { pflash_write(opaque, addr, value, 1, 0); } -static void pflash_writew_be(void *opaque, target_phys_addr_t addr, +static void pflash_writew_be(void *opaque, hwaddr addr, uint32_t value) { pflash_t *pfl = opaque; @@ -535,7 +545,7 @@ static void pflash_writew_be(void *opaque, target_phys_addr_t addr, pflash_write(pfl, addr, value, 2, 1); } -static void pflash_writew_le(void *opaque, target_phys_addr_t addr, +static void pflash_writew_le(void *opaque, hwaddr addr, uint32_t value) { pflash_t *pfl = opaque; @@ -543,7 +553,7 @@ static void pflash_writew_le(void *opaque, target_phys_addr_t addr, pflash_write(pfl, addr, value, 2, 0); } -static void pflash_writel_be(void *opaque, target_phys_addr_t addr, +static void pflash_writel_be(void *opaque, hwaddr addr, uint32_t value) { pflash_t *pfl = opaque; @@ -551,7 +561,7 @@ static void pflash_writel_be(void *opaque, target_phys_addr_t addr, pflash_write(pfl, addr, value, 4, 1); } -static void pflash_writel_le(void *opaque, target_phys_addr_t addr, +static void pflash_writel_le(void *opaque, hwaddr addr, uint32_t value) { pflash_t *pfl = opaque; @@ -575,86 +585,38 @@ static const MemoryRegionOps pflash_cfi02_ops_le = { .endianness = DEVICE_NATIVE_ENDIAN, }; -/* Count trailing zeroes of a 32 bits quantity */ -static int ctz32 (uint32_t n) +static int pflash_cfi02_init(SysBusDevice *dev) { + pflash_t *pfl = FROM_SYSBUS(typeof(*pfl), dev); + uint32_t chip_len; int ret; - ret = 0; - if (!(n & 0xFFFF)) { - ret += 16; - n = n >> 16; - } - if (!(n & 0xFF)) { - ret += 8; - n = n >> 8; - } - if (!(n & 0xF)) { - ret += 4; - n = n >> 4; - } - if (!(n & 0x3)) { - ret += 2; - n = n >> 2; - } - if (!(n & 0x1)) { - ret++; -#if 0 /* This is not necessary as n is never 0 */ - n = n >> 1; -#endif - } -#if 0 /* This is not necessary as n is never 0 */ - if (!n) - ret++; -#endif - - return ret; -} - -pflash_t *pflash_cfi02_register(target_phys_addr_t base, - DeviceState *qdev, const char *name, - target_phys_addr_t size, - BlockDriverState *bs, uint32_t sector_len, - int nb_blocs, int nb_mappings, int width, - uint16_t id0, uint16_t id1, - uint16_t id2, uint16_t id3, - uint16_t unlock_addr0, uint16_t unlock_addr1, - int be) -{ - pflash_t *pfl; - int32_t chip_len; - int ret; - - chip_len = sector_len * nb_blocs; + chip_len = pfl->sector_len * pfl->nb_blocs; /* XXX: to be fixed */ #if 0 if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) && total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024)) return NULL; #endif - pfl = g_malloc0(sizeof(pflash_t)); - memory_region_init_rom_device( - &pfl->orig_mem, be ? &pflash_cfi02_ops_be : &pflash_cfi02_ops_le, pfl, - name, size); - vmstate_register_ram(&pfl->orig_mem, qdev); + + memory_region_init_rom_device(&pfl->orig_mem, pfl->be ? + &pflash_cfi02_ops_be : &pflash_cfi02_ops_le, + pfl, pfl->name, chip_len); + vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl)); pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem); - pfl->base = base; pfl->chip_len = chip_len; - pfl->mappings = nb_mappings; - pfl->bs = bs; if (pfl->bs) { /* read the initial flash content */ ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9); if (ret < 0) { g_free(pfl); - return NULL; + return 1; } - bdrv_attach_dev_nofail(pfl->bs, pfl); } pflash_setup_mappings(pfl); pfl->rom_mode = 1; - memory_region_add_subregion(get_system_memory(), pfl->base, &pfl->mem); + sysbus_init_mmio(dev, &pfl->mem); if (pfl->bs) { pfl->ro = bdrv_is_read_only(pfl->bs); @@ -663,17 +625,9 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, } pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl); - pfl->sector_len = sector_len; - pfl->width = width; pfl->wcycle = 0; pfl->cmd = 0; pfl->status = 0; - pfl->ident[0] = id0; - pfl->ident[1] = id1; - pfl->ident[2] = id2; - pfl->ident[3] = id3; - pfl->unlock_addr[0] = unlock_addr0; - pfl->unlock_addr[1] = unlock_addr1; /* Hardcoded CFI table (mostly from SG29 Spansion flash) */ pfl->cfi_len = 0x52; /* Standard "QRY" string */ @@ -729,10 +683,10 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, /* Number of erase block regions (uniform) */ pfl->cfi_table[0x2C] = 0x01; /* Erase block region 1 */ - pfl->cfi_table[0x2D] = nb_blocs - 1; - pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8; - pfl->cfi_table[0x2F] = sector_len >> 8; - pfl->cfi_table[0x30] = sector_len >> 16; + pfl->cfi_table[0x2D] = pfl->nb_blocs - 1; + pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8; + pfl->cfi_table[0x2F] = pfl->sector_len >> 8; + pfl->cfi_table[0x30] = pfl->sector_len >> 16; /* Extended */ pfl->cfi_table[0x31] = 'P'; @@ -752,5 +706,81 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, pfl->cfi_table[0x3b] = 0x00; pfl->cfi_table[0x3c] = 0x00; + return 0; +} + +static Property pflash_cfi02_properties[] = { + DEFINE_PROP_DRIVE("drive", struct pflash_t, bs), + DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0), + DEFINE_PROP_UINT32("sector-length", struct pflash_t, sector_len, 0), + DEFINE_PROP_UINT8("width", struct pflash_t, width, 0), + DEFINE_PROP_UINT8("mappings", struct pflash_t, mappings, 0), + DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0), + DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0), + DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0), + DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0), + DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0), + DEFINE_PROP_UINT16("unlock-addr0", struct pflash_t, unlock_addr0, 0), + DEFINE_PROP_UINT16("unlock-addr1", struct pflash_t, unlock_addr1, 0), + DEFINE_PROP_STRING("name", struct pflash_t, name), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pflash_cfi02_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pflash_cfi02_init; + dc->props = pflash_cfi02_properties; +} + +static const TypeInfo pflash_cfi02_info = { + .name = "cfi.pflash02", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct pflash_t), + .class_init = pflash_cfi02_class_init, +}; + +static void pflash_cfi02_register_types(void) +{ + type_register_static(&pflash_cfi02_info); +} + +type_init(pflash_cfi02_register_types) + +pflash_t *pflash_cfi02_register(hwaddr base, + DeviceState *qdev, const char *name, + hwaddr size, + BlockDriverState *bs, uint32_t sector_len, + int nb_blocs, int nb_mappings, int width, + uint16_t id0, uint16_t id1, + uint16_t id2, uint16_t id3, + uint16_t unlock_addr0, uint16_t unlock_addr1, + int be) +{ + DeviceState *dev = qdev_create(NULL, "cfi.pflash02"); + SysBusDevice *busdev = sysbus_from_qdev(dev); + pflash_t *pfl = (pflash_t *)object_dynamic_cast(OBJECT(dev), + "cfi.pflash02"); + + if (bs && qdev_prop_set_drive(dev, "drive", bs)) { + abort(); + } + qdev_prop_set_uint32(dev, "num-blocks", nb_blocs); + qdev_prop_set_uint32(dev, "sector-length", sector_len); + qdev_prop_set_uint8(dev, "width", width); + qdev_prop_set_uint8(dev, "mappings", nb_mappings); + qdev_prop_set_uint8(dev, "big-endian", !!be); + qdev_prop_set_uint16(dev, "id0", id0); + qdev_prop_set_uint16(dev, "id1", id1); + qdev_prop_set_uint16(dev, "id2", id2); + qdev_prop_set_uint16(dev, "id3", id3); + qdev_prop_set_uint16(dev, "unlock-addr0", unlock_addr0); + qdev_prop_set_uint16(dev, "unlock-addr1", unlock_addr1); + qdev_prop_set_string(dev, "name", name); + qdev_init_nofail(dev); + + sysbus_mmio_map(busdev, 0, base); return pfl; } diff --git a/hw/piix4.c b/hw/piix4.c index ce4eb0d1ae..799ed1729c 100644 --- a/hw/piix4.c +++ b/hw/piix4.c @@ -24,7 +24,7 @@ #include "hw.h" #include "pc.h" -#include "pci.h" +#include "pci/pci.h" #include "isa.h" #include "sysbus.h" diff --git a/hw/piix_pci.c b/hw/piix_pci.c index c497a014af..3d79c73fda 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -24,19 +24,22 @@ #include "hw.h" #include "pc.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" #include "isa.h" #include "sysbus.h" -#include "range.h" +#include "qemu/range.h" #include "xen.h" +#include "pam.h" /* * I440FX chipset data sheet. * http://download.intel.com/design/chipsets/datashts/29054901.pdf */ -typedef PCIHostState I440FXState; +typedef struct I440FXState { + PCIHostState parent_obj; +} I440FXState; #define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */ #define PIIX_NUM_PIRQS 4ULL /* PIRQ[A-D] */ @@ -66,11 +69,6 @@ typedef struct PIIX3State { int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS]; } PIIX3State; -typedef struct PAMMemoryRegion { - MemoryRegion mem; - bool initialized; -} PAMMemoryRegion; - struct PCII440FXState { PCIDevice dev; MemoryRegion *system_memory; @@ -103,56 +101,16 @@ static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx) return (pci_intx + slot_addend) & 3; } -static void update_pam(PCII440FXState *d, uint32_t start, uint32_t end, int r, - PAMMemoryRegion *mem) -{ - if (mem->initialized) { - memory_region_del_subregion(d->system_memory, &mem->mem); - memory_region_destroy(&mem->mem); - } - - // printf("ISA mapping %08x-0x%08x: %d\n", start, end, r); - switch(r) { - case 3: - /* RAM */ - memory_region_init_alias(&mem->mem, "pam-ram", d->ram_memory, - start, end - start); - break; - case 1: - /* ROM (XXX: not quite correct) */ - memory_region_init_alias(&mem->mem, "pam-rom", d->ram_memory, - start, end - start); - memory_region_set_readonly(&mem->mem, true); - break; - case 2: - case 0: - /* XXX: should distinguish read/write cases */ - memory_region_init_alias(&mem->mem, "pam-pci", d->pci_address_space, - start, end - start); - break; - } - memory_region_add_subregion_overlap(d->system_memory, - start, &mem->mem, 1); - mem->initialized = true; -} - static void i440fx_update_memory_mappings(PCII440FXState *d) { - int i, r; - uint32_t smram; - bool smram_enabled; + int i; memory_region_transaction_begin(); - update_pam(d, 0xf0000, 0x100000, (d->dev.config[I440FX_PAM] >> 4) & 3, - &d->pam_regions[0]); - for(i = 0; i < 12; i++) { - r = (d->dev.config[(i >> 1) + (I440FX_PAM + 1)] >> ((i & 1) * 4)) & 3; - update_pam(d, 0xc0000 + 0x4000 * i, 0xc0000 + 0x4000 * (i + 1), r, - &d->pam_regions[i+1]); + for (i = 0; i < 13; i++) { + pam_update(&d->pam_regions[i], i, + d->dev.config[I440FX_PAM + ((i + 1) / 2)]); } - smram = d->dev.config[I440FX_SMRAM]; - smram_enabled = (d->smm_enabled && (smram & 0x08)) || (smram & 0x40); - memory_region_set_enabled(&d->smram_region, !smram_enabled); + smram_update(&d->smram_region, d->dev.config[I440FX_SMRAM], d->smm_enabled); memory_region_transaction_commit(); } @@ -160,11 +118,10 @@ static void i440fx_set_smm(int val, void *arg) { PCII440FXState *d = arg; - val = (val != 0); - if (d->smm_enabled != val) { - d->smm_enabled = val; - i440fx_update_memory_mappings(d); - } + memory_region_transaction_begin(); + smram_set_smm(&d->smm_enabled, val, d->dev.config[I440FX_SMRAM], + &d->smram_region); + memory_region_transaction_commit(); } @@ -225,7 +182,7 @@ static const VMStateDescription vmstate_i440fx = { static int i440fx_pcihost_initfn(SysBusDevice *dev) { - I440FXState *s = FROM_SYSBUS(I440FXState, dev); + PCIHostState *s = PCI_HOST_BRIDGE(dev); memory_region_init_io(&s->conf_mem, &pci_host_conf_le_ops, s, "pci-conf-idx", 4); @@ -257,24 +214,25 @@ static PCIBus *i440fx_common_init(const char *device_name, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, ram_addr_t ram_size, - target_phys_addr_t pci_hole_start, - target_phys_addr_t pci_hole_size, - target_phys_addr_t pci_hole64_start, - target_phys_addr_t pci_hole64_size, + hwaddr pci_hole_start, + hwaddr pci_hole_size, + hwaddr pci_hole64_start, + hwaddr pci_hole64_size, MemoryRegion *pci_address_space, MemoryRegion *ram_memory) { DeviceState *dev; PCIBus *b; PCIDevice *d; - I440FXState *s; + PCIHostState *s; PIIX3State *piix3; PCII440FXState *f; + unsigned i; dev = qdev_create(NULL, "i440FX-pcihost"); - s = FROM_SYSBUS(I440FXState, sysbus_from_qdev(dev)); + s = PCI_HOST_BRIDGE(dev); s->address_space = address_space_mem; - b = pci_bus_new(&s->busdev.qdev, NULL, pci_address_space, + b = pci_bus_new(dev, NULL, pci_address_space, address_space_io, 0); s->bus = b; object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL); @@ -301,6 +259,13 @@ static PCIBus *i440fx_common_init(const char *device_name, memory_region_add_subregion_overlap(f->system_memory, 0xa0000, &f->smram_region, 1); memory_region_set_enabled(&f->smram_region, false); + init_pam(f->ram_memory, f->system_memory, f->pci_address_space, + &f->pam_regions[0], PAM_BIOS_BASE, PAM_BIOS_SIZE); + for (i = 0; i < 12; ++i) { + init_pam(f->ram_memory, f->system_memory, f->pci_address_space, + &f->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, + PAM_EXPAN_SIZE); + } /* Xen supports additional interrupt routes from the PCI devices to * the IOAPIC: the four pins of each PCI device on the bus are also @@ -339,10 +304,10 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, ram_addr_t ram_size, - target_phys_addr_t pci_hole_start, - target_phys_addr_t pci_hole_size, - target_phys_addr_t pci_hole64_start, - target_phys_addr_t pci_hole64_size, + hwaddr pci_hole_start, + hwaddr pci_hole_size, + hwaddr pci_hole64_start, + hwaddr pci_hole64_size, MemoryRegion *pci_memory, MemoryRegion *ram_memory) { @@ -537,7 +502,7 @@ static void piix3_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_ISA; } -static TypeInfo piix3_info = { +static const TypeInfo piix3_info = { .name = "PIIX3", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PIIX3State), @@ -560,7 +525,7 @@ static void piix3_xen_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_ISA; }; -static TypeInfo piix3_xen_info = { +static const TypeInfo piix3_xen_info = { .name = "PIIX3-xen", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PIIX3State), @@ -584,7 +549,7 @@ static void i440fx_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_i440fx; } -static TypeInfo i440fx_info = { +static const TypeInfo i440fx_info = { .name = "i440FX", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCII440FXState), @@ -601,9 +566,9 @@ static void i440fx_pcihost_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo i440fx_pcihost_info = { +static const TypeInfo i440fx_pcihost_info = { .name = "i440FX-pcihost", - .parent = TYPE_SYS_BUS_DEVICE, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(I440FXState), .class_init = i440fx_pcihost_class_init, }; diff --git a/hw/pixel_ops.h b/hw/pixel_ops.h deleted file mode 100644 index d390adfd1b..0000000000 --- a/hw/pixel_ops.h +++ /dev/null @@ -1,53 +0,0 @@ -static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, - unsigned int b) -{ - return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); -} - -static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, - unsigned int b) -{ - return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); -} - -static inline unsigned int rgb_to_pixel15bgr(unsigned int r, unsigned int g, - unsigned int b) -{ - return ((b >> 3) << 10) | ((g >> 3) << 5) | (r >> 3); -} - -static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, - unsigned int b) -{ - return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); -} - -static inline unsigned int rgb_to_pixel16bgr(unsigned int r, unsigned int g, - unsigned int b) -{ - return ((b >> 3) << 11) | ((g >> 2) << 5) | (r >> 3); -} - -static inline unsigned int rgb_to_pixel24(unsigned int r, unsigned int g, - unsigned int b) -{ - return (r << 16) | (g << 8) | b; -} - -static inline unsigned int rgb_to_pixel24bgr(unsigned int r, unsigned int g, - unsigned int b) -{ - return (b << 16) | (g << 8) | r; -} - -static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, - unsigned int b) -{ - return (r << 16) | (g << 8) | b; -} - -static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, - unsigned int b) -{ - return (b << 16) | (g << 8) | r; -} diff --git a/hw/pl011.c b/hw/pl011.c index 3245702df0..35835f36c0 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -8,7 +8,7 @@ */ #include "sysbus.h" -#include "qemu-char.h" +#include "char/char.h" typedef struct { SysBusDevice busdev; @@ -54,7 +54,7 @@ static void pl011_update(pl011_state *s) qemu_set_irq(s->irq, flags != 0); } -static uint64_t pl011_read(void *opaque, target_phys_addr_t offset, +static uint64_t pl011_read(void *opaque, hwaddr offset, unsigned size) { pl011_state *s = (pl011_state *)opaque; @@ -107,7 +107,8 @@ static uint64_t pl011_read(void *opaque, target_phys_addr_t offset, case 18: /* UARTDMACR */ return s->dmacr; default: - hw_error("pl011_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl011_read: Bad offset %x\n", (int)offset); return 0; } } @@ -126,7 +127,7 @@ static void pl011_set_read_trigger(pl011_state *s) s->read_trigger = 1; } -static void pl011_write(void *opaque, target_phys_addr_t offset, +static void pl011_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { pl011_state *s = (pl011_state *)opaque; @@ -178,11 +179,13 @@ static void pl011_write(void *opaque, target_phys_addr_t offset, break; case 18: /* UARTDMACR */ s->dmacr = value; - if (value & 3) - hw_error("PL011: DMA not implemented\n"); + if (value & 3) { + qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n"); + } break; default: - hw_error("pl011_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl011_write: Bad offset %x\n", (int)offset); } } diff --git a/hw/pl022.c b/hw/pl022.c index 60e35daeb5..fbd7ded0cf 100644 --- a/hw/pl022.c +++ b/hw/pl022.c @@ -130,7 +130,7 @@ static void pl022_xfer(pl022_state *s) pl022_update(s); } -static uint64_t pl022_read(void *opaque, target_phys_addr_t offset, +static uint64_t pl022_read(void *opaque, hwaddr offset, unsigned size) { pl022_state *s = (pl022_state *)opaque; @@ -168,12 +168,13 @@ static uint64_t pl022_read(void *opaque, target_phys_addr_t offset, /* Not implemented. */ return 0; default: - hw_error("pl022_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl022_read: Bad offset %x\n", (int)offset); return 0; } } -static void pl022_write(void *opaque, target_phys_addr_t offset, +static void pl022_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { pl022_state *s = (pl022_state *)opaque; @@ -211,11 +212,12 @@ static void pl022_write(void *opaque, target_phys_addr_t offset, break; case 0x20: /* DMACR */ if (value) { - hw_error("pl022: DMA not implemented\n"); + qemu_log_mask(LOG_UNIMP, "pl022: DMA not implemented\n"); } break; default: - hw_error("pl022_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl022_write: Bad offset %x\n", (int)offset); } } diff --git a/hw/pl031.c b/hw/pl031.c index 9602664da6..3a23ecde48 100644 --- a/hw/pl031.c +++ b/hw/pl031.c @@ -12,8 +12,8 @@ */ #include "sysbus.h" -#include "qemu-timer.h" -#include "sysemu.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" //#define DEBUG_PL031 @@ -95,7 +95,7 @@ static void pl031_set_alarm(pl031_state *s) } } -static uint64_t pl031_read(void *opaque, target_phys_addr_t offset, +static uint64_t pl031_read(void *opaque, hwaddr offset, unsigned size) { pl031_state *s = (pl031_state *)opaque; @@ -120,18 +120,20 @@ static uint64_t pl031_read(void *opaque, target_phys_addr_t offset, case RTC_MIS: return s->is & s->im; case RTC_ICR: - fprintf(stderr, "qemu: pl031_read: Unexpected offset 0x%x\n", - (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl031: read of write-only register at offset 0x%x\n", + (int)offset); break; default: - hw_error("pl031_read: Bad offset 0x%x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl031_read: Bad offset 0x%x\n", (int)offset); break; } return 0; } -static void pl031_write(void * opaque, target_phys_addr_t offset, +static void pl031_write(void * opaque, hwaddr offset, uint64_t value, unsigned size) { pl031_state *s = (pl031_state *)opaque; @@ -167,12 +169,14 @@ static void pl031_write(void * opaque, target_phys_addr_t offset, case RTC_DR: case RTC_MIS: case RTC_RIS: - fprintf(stderr, "qemu: pl031_write: Unexpected offset 0x%x\n", - (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl031: write to read-only register at offset 0x%x\n", + (int)offset); break; default: - hw_error("pl031_write: Bad offset 0x%x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl031_write: Bad offset 0x%x\n", (int)offset); break; } } diff --git a/hw/pl041.c b/hw/pl041.c index b6723be0a9..4436d97c50 100644 --- a/hw/pl041.c +++ b/hw/pl041.c @@ -97,7 +97,7 @@ static const char *pl041_regs_name[] = { #if defined(PL041_DEBUG_LEVEL) -static const char *get_reg_name(target_phys_addr_t offset) +static const char *get_reg_name(hwaddr offset) { if (offset <= PL041_dr1_7) { return pl041_regs_name[offset >> 2]; @@ -327,7 +327,7 @@ static void pl041_request_data(void *opaque) pl041_isr1_update(s); } -static uint64_t pl041_read(void *opaque, target_phys_addr_t offset, +static uint64_t pl041_read(void *opaque, hwaddr offset, unsigned size) { pl041_state *s = (pl041_state *)opaque; @@ -361,7 +361,7 @@ static uint64_t pl041_read(void *opaque, target_phys_addr_t offset, return value; } -static void pl041_write(void *opaque, target_phys_addr_t offset, +static void pl041_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { pl041_state *s = (pl041_state *)opaque; @@ -536,8 +536,9 @@ static int pl041_init(SysBusDevice *dev) default: /* NC FIFO depth of 16 is not allowed because its id bits in AACIPERIPHID3 overlap with the id for the default NC FIFO depth */ - fprintf(stderr, "pl041: unsupported non-compact fifo depth [%i]\n", - s->fifo_depth); + qemu_log_mask(LOG_UNIMP, + "pl041: unsupported non-compact fifo depth [%i]\n", + s->fifo_depth); return -1; } diff --git a/hw/pl050.c b/hw/pl050.c index b13924a160..47032f1260 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -58,7 +58,7 @@ static void pl050_update(void *opaque, int level) qemu_set_irq(s->irq, raise); } -static uint64_t pl050_read(void *opaque, target_phys_addr_t offset, +static uint64_t pl050_read(void *opaque, hwaddr offset, unsigned size) { pl050_state *s = (pl050_state *)opaque; @@ -95,12 +95,13 @@ static uint64_t pl050_read(void *opaque, target_phys_addr_t offset, case 4: /* KMIIR */ return s->pending | 2; default: - hw_error("pl050_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl050_read: Bad offset %x\n", (int)offset); return 0; } } -static void pl050_write(void *opaque, target_phys_addr_t offset, +static void pl050_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { pl050_state *s = (pl050_state *)opaque; @@ -123,7 +124,8 @@ static void pl050_write(void *opaque, target_phys_addr_t offset, s->clk = value; return; default: - hw_error("pl050_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl050_write: Bad offset %x\n", (int)offset); } } static const MemoryRegionOps pl050_ops = { diff --git a/hw/pl061.c b/hw/pl061.c index 2aac7e8e9e..f1ed5ced1d 100644 --- a/hw/pl061.c +++ b/hw/pl061.c @@ -113,7 +113,7 @@ static void pl061_update(pl061_state *s) /* FIXME: Implement input interrupts. */ } -static uint64_t pl061_read(void *opaque, target_phys_addr_t offset, +static uint64_t pl061_read(void *opaque, hwaddr offset, unsigned size) { pl061_state *s = (pl061_state *)opaque; @@ -164,12 +164,13 @@ static uint64_t pl061_read(void *opaque, target_phys_addr_t offset, case 0x528: /* Analog mode select */ return s->amsel; default: - hw_error("pl061_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl061_read: Bad offset %x\n", (int)offset); return 0; } } -static void pl061_write(void *opaque, target_phys_addr_t offset, +static void pl061_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { pl061_state *s = (pl061_state *)opaque; @@ -239,7 +240,8 @@ static void pl061_write(void *opaque, target_phys_addr_t offset, s->amsel = value & 0xff; break; default: - hw_error("pl061_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl061_write: Bad offset %x\n", (int)offset); } pl061_update(s); } diff --git a/hw/pl080.c b/hw/pl080.c index b3cf651ab7..26150af757 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -218,7 +218,7 @@ again: } } -static uint64_t pl080_read(void *opaque, target_phys_addr_t offset, +static uint64_t pl080_read(void *opaque, hwaddr offset, unsigned size) { pl080_state *s = (pl080_state *)opaque; @@ -281,12 +281,13 @@ static uint64_t pl080_read(void *opaque, target_phys_addr_t offset, return s->sync; default: bad_offset: - hw_error("pl080_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl080_read: Bad offset %x\n", (int)offset); return 0; } } -static void pl080_write(void *opaque, target_phys_addr_t offset, +static void pl080_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { pl080_state *s = (pl080_state *)opaque; @@ -327,12 +328,13 @@ static void pl080_write(void *opaque, target_phys_addr_t offset, case 10: /* SoftLBReq */ case 11: /* SoftLSReq */ /* ??? Implement these. */ - hw_error("pl080_write: Soft DMA not implemented\n"); + qemu_log_mask(LOG_UNIMP, "pl080_write: Soft DMA not implemented\n"); break; case 12: /* Configuration */ s->conf = value; if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) { - hw_error("pl080_write: Big-endian DMA not implemented\n"); + qemu_log_mask(LOG_UNIMP, + "pl080_write: Big-endian DMA not implemented\n"); } pl080_run(s); break; @@ -341,7 +343,8 @@ static void pl080_write(void *opaque, target_phys_addr_t offset, break; default: bad_offset: - hw_error("pl080_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl080_write: Bad offset %x\n", (int)offset); } pl080_update(s); } diff --git a/hw/pl110.c b/hw/pl110.c index f94608cb62..098e335aea 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -8,8 +8,9 @@ */ #include "sysbus.h" -#include "console.h" +#include "ui/console.h" #include "framebuffer.h" +#include "ui/pixel_ops.h" #define PL110_CR_EN 0x001 #define PL110_CR_BGR 0x100 @@ -55,8 +56,8 @@ typedef struct { enum pl110_bppmode bpp; int invalidate; uint32_t mux_ctrl; - uint32_t pallette[256]; - uint32_t raw_pallette[128]; + uint32_t palette[256]; + uint32_t raw_palette[128]; qemu_irq irq; } pl110_state; @@ -79,8 +80,8 @@ static const VMStateDescription vmstate_pl110 = { VMSTATE_INT32(rows, pl110_state), VMSTATE_UINT32(bpp, pl110_state), VMSTATE_INT32(invalidate, pl110_state), - VMSTATE_UINT32_ARRAY(pallette, pl110_state, 256), - VMSTATE_UINT32_ARRAY(raw_pallette, pl110_state, 128), + VMSTATE_UINT32_ARRAY(palette, pl110_state, 256), + VMSTATE_UINT32_ARRAY(raw_palette, pl110_state, 128), VMSTATE_UINT32_V(mux_ctrl, pl110_state, 2), VMSTATE_END_OF_LIST() } @@ -109,8 +110,6 @@ static const unsigned char *idregs[] = { pl111_id }; -#include "pixel_ops.h" - #define BITS 8 #include "pl110_template.h" #define BITS 15 @@ -236,10 +235,10 @@ static void pl110_update_display(void *opaque) s->upbase, s->cols, s->rows, src_width, dest_width, 0, s->invalidate, - fn, s->pallette, + fn, s->palette, &first, &last); if (first >= 0) { - dpy_update(s->ds, 0, first, s->cols, last - first + 1); + dpy_gfx_update(s->ds, 0, first, s->cols, last - first + 1); } s->invalidate = 0; } @@ -253,13 +252,13 @@ static void pl110_invalidate_display(void * opaque) } } -static void pl110_update_pallette(pl110_state *s, int n) +static void pl110_update_palette(pl110_state *s, int n) { int i; uint32_t raw; unsigned int r, g, b; - raw = s->raw_pallette[n]; + raw = s->raw_palette[n]; n <<= 1; for (i = 0; i < 2; i++) { r = (raw & 0x1f) << 3; @@ -271,17 +270,17 @@ static void pl110_update_pallette(pl110_state *s, int n) raw >>= 6; switch (ds_get_bits_per_pixel(s->ds)) { case 8: - s->pallette[n] = rgb_to_pixel8(r, g, b); + s->palette[n] = rgb_to_pixel8(r, g, b); break; case 15: - s->pallette[n] = rgb_to_pixel15(r, g, b); + s->palette[n] = rgb_to_pixel15(r, g, b); break; case 16: - s->pallette[n] = rgb_to_pixel16(r, g, b); + s->palette[n] = rgb_to_pixel16(r, g, b); break; case 24: case 32: - s->pallette[n] = rgb_to_pixel32(r, g, b); + s->palette[n] = rgb_to_pixel32(r, g, b); break; } n++; @@ -305,7 +304,7 @@ static void pl110_update(pl110_state *s) /* TODO: Implement interrupts. */ } -static uint64_t pl110_read(void *opaque, target_phys_addr_t offset, +static uint64_t pl110_read(void *opaque, hwaddr offset, unsigned size) { pl110_state *s = (pl110_state *)opaque; @@ -314,7 +313,7 @@ static uint64_t pl110_read(void *opaque, target_phys_addr_t offset, return idregs[s->version][(offset - 0xfe0) >> 2]; } if (offset >= 0x200 && offset < 0x400) { - return s->raw_pallette[(offset - 0x200) >> 2]; + return s->raw_palette[(offset - 0x200) >> 2]; } switch (offset >> 2) { case 0: /* LCDTiming0 */ @@ -349,12 +348,13 @@ static uint64_t pl110_read(void *opaque, target_phys_addr_t offset, case 12: /* LCDLPCURR */ return s->lpbase; default: - hw_error("pl110_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl110_read: Bad offset %x\n", (int)offset); return 0; } } -static void pl110_write(void *opaque, target_phys_addr_t offset, +static void pl110_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { pl110_state *s = (pl110_state *)opaque; @@ -364,10 +364,10 @@ static void pl110_write(void *opaque, target_phys_addr_t offset, is written to. */ s->invalidate = 1; if (offset >= 0x200 && offset < 0x400) { - /* Pallette. */ + /* Palette. */ n = (offset - 0x200) >> 2; - s->raw_pallette[(offset - 0x200) >> 2] = val; - pl110_update_pallette(s, n); + s->raw_palette[(offset - 0x200) >> 2] = val; + pl110_update_palette(s, n); return; } switch (offset >> 2) { @@ -417,7 +417,8 @@ static void pl110_write(void *opaque, target_phys_addr_t offset, pl110_update(s); break; default: - hw_error("pl110_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl110_write: Bad offset %x\n", (int)offset); } } diff --git a/hw/pl110_template.h b/hw/pl110_template.h index 1dce32a0c3..e738e4a241 100644 --- a/hw/pl110_template.h +++ b/hw/pl110_template.h @@ -129,14 +129,14 @@ static drawfn glue(pl110_draw_fn_,BITS)[48] = static void glue(pl110_draw_line1_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { - uint32_t *pallette = opaque; + uint32_t *palette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; #ifdef SWAP_PIXELS -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 7 - (x))) & 1]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 7 - (x))) & 1]); #else -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x) + y)) & 1]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x) + y)) & 1]); #endif #ifdef SWAP_WORDS FN_8(24) @@ -157,14 +157,14 @@ static void glue(pl110_draw_line1_,NAME)(void *opaque, uint8_t *d, const uint8_t static void glue(pl110_draw_line2_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { - uint32_t *pallette = opaque; + uint32_t *palette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; #ifdef SWAP_PIXELS -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 6 - (x)*2)) & 3]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 6 - (x)*2)) & 3]); #else -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*2 + y)) & 3]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x)*2 + y)) & 3]); #endif #ifdef SWAP_WORDS FN_4(0, 24) @@ -185,14 +185,14 @@ static void glue(pl110_draw_line2_,NAME)(void *opaque, uint8_t *d, const uint8_t static void glue(pl110_draw_line4_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { - uint32_t *pallette = opaque; + uint32_t *palette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; #ifdef SWAP_PIXELS -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 4 - (x)*4)) & 0xf]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 4 - (x)*4)) & 0xf]); #else -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*4 + y)) & 0xf]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x)*4 + y)) & 0xf]); #endif #ifdef SWAP_WORDS FN_2(0, 24) @@ -213,11 +213,11 @@ static void glue(pl110_draw_line4_,NAME)(void *opaque, uint8_t *d, const uint8_t static void glue(pl110_draw_line8_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { - uint32_t *pallette = opaque; + uint32_t *palette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; -#define FN(x) COPY_PIXEL(d, pallette[(data >> (x)) & 0xff]); +#define FN(x) COPY_PIXEL(d, palette[(data >> (x)) & 0xff]); #ifdef SWAP_WORDS FN(24) FN(16) diff --git a/hw/pl181.c b/hw/pl181.c index 7d91fbba1d..cbddb741ce 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -7,7 +7,7 @@ * This code is licensed under the GPL. */ -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "sysbus.h" #include "sd.h" @@ -285,7 +285,7 @@ static void pl181_fifo_run(pl181_state *s) } } -static uint64_t pl181_read(void *opaque, target_phys_addr_t offset, +static uint64_t pl181_read(void *opaque, hwaddr offset, unsigned size) { pl181_state *s = (pl181_state *)opaque; @@ -352,7 +352,7 @@ static uint64_t pl181_read(void *opaque, target_phys_addr_t offset, case 0xa0: case 0xa4: case 0xa8: case 0xac: case 0xb0: case 0xb4: case 0xb8: case 0xbc: if (s->fifo_len == 0) { - fprintf(stderr, "pl181: Unexpected FIFO read\n"); + qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO read\n"); return 0; } else { uint32_t value; @@ -363,12 +363,13 @@ static uint64_t pl181_read(void *opaque, target_phys_addr_t offset, return value; } default: - hw_error("pl181_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl181_read: Bad offset %x\n", (int)offset); return 0; } } -static void pl181_write(void *opaque, target_phys_addr_t offset, +static void pl181_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { pl181_state *s = (pl181_state *)opaque; @@ -387,11 +388,11 @@ static void pl181_write(void *opaque, target_phys_addr_t offset, s->cmd = value; if (s->cmd & PL181_CMD_ENABLE) { if (s->cmd & PL181_CMD_INTERRUPT) { - fprintf(stderr, "pl181: Interrupt mode not implemented\n"); - abort(); + qemu_log_mask(LOG_UNIMP, + "pl181: Interrupt mode not implemented\n"); } if (s->cmd & PL181_CMD_PENDING) { - fprintf(stderr, "pl181: Pending commands not implemented\n"); - abort(); + qemu_log_mask(LOG_UNIMP, + "pl181: Pending commands not implemented\n"); } else { pl181_send_command(s); pl181_fifo_run(s); @@ -427,14 +428,15 @@ static void pl181_write(void *opaque, target_phys_addr_t offset, case 0xa0: case 0xa4: case 0xa8: case 0xac: case 0xb0: case 0xb4: case 0xb8: case 0xbc: if (s->datacnt == 0) { - fprintf(stderr, "pl181: Unexpected FIFO write\n"); + qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO write\n"); } else { pl181_fifo_push(s, value); pl181_fifo_run(s); } break; default: - hw_error("pl181_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl181_write: Bad offset %x\n", (int)offset); } pl181_update(s); } diff --git a/hw/pl190.c b/hw/pl190.c index cb50afb9f4..40199302a9 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -85,7 +85,7 @@ static void pl190_update_vectors(pl190_state *s) pl190_update(s); } -static uint64_t pl190_read(void *opaque, target_phys_addr_t offset, +static uint64_t pl190_read(void *opaque, hwaddr offset, unsigned size) { pl190_state *s = (pl190_state *)opaque; @@ -117,12 +117,18 @@ static uint64_t pl190_read(void *opaque, target_phys_addr_t offset, return s->protected; case 12: /* VECTADDR */ /* Read vector address at the start of an ISR. Increases the - current priority level to that of the current interrupt. */ - for (i = 0; i < s->priority; i++) - { - if ((s->level | s->soft_level) & s->prio_mask[i]) - break; - } + * current priority level to that of the current interrupt. + * + * Since an enabled interrupt X at priority P causes prio_mask[Y] + * to have bit X set for all Y > P, this loop will stop with + * i == the priority of the highest priority set interrupt. + */ + for (i = 0; i < s->priority; i++) { + if ((s->level | s->soft_level) & s->prio_mask[i + 1]) { + break; + } + } + /* Reading this value with no pending interrupts is undefined. We return the default address. */ if (i == PL190_NUM_PRIO) @@ -137,12 +143,13 @@ static uint64_t pl190_read(void *opaque, target_phys_addr_t offset, case 13: /* DEFVECTADDR */ return s->vect_addr[16]; default: - hw_error("pl190_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl190_read: Bad offset %x\n", (int)offset); return 0; } } -static void pl190_write(void *opaque, target_phys_addr_t offset, +static void pl190_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { pl190_state *s = (pl190_state *)opaque; @@ -192,11 +199,12 @@ static void pl190_write(void *opaque, target_phys_addr_t offset, break; case 0xc0: /* ITCR */ if (val) { - hw_error("pl190: Test mode not implemented\n"); + qemu_log_mask(LOG_UNIMP, "pl190: Test mode not implemented\n"); } break; default: - hw_error("pl190_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl190_write: Bad offset %x\n", (int)offset); return; } pl190_update(s); diff --git a/hw/pm_smbus.c b/hw/pm_smbus.c index 5d6046de5a..ea1380ca68 100644 --- a/hw/pm_smbus.c +++ b/hw/pm_smbus.c @@ -94,10 +94,11 @@ static void smb_transaction(PMSMBus *s) s->smb_stat |= 0x04; } -void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) +static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, + unsigned width) { PMSMBus *s = opaque; - addr &= 0x3f; + SMBUS_DPRINTF("SMB writeb port=0x%04x val=0x%02x\n", addr, val); switch(addr) { case SMBHSTSTS: @@ -131,12 +132,11 @@ void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) } } -uint32_t smb_ioport_readb(void *opaque, uint32_t addr) +static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width) { PMSMBus *s = opaque; uint32_t val; - addr &= 0x3f; switch(addr) { case SMBHSTSTS: val = s->smb_stat; @@ -170,7 +170,16 @@ uint32_t smb_ioport_readb(void *opaque, uint32_t addr) return val; } +static const MemoryRegionOps pm_smbus_ops = { + .read = smb_ioport_readb, + .write = smb_ioport_writeb, + .valid.min_access_size = 1, + .valid.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + void pm_smbus_init(DeviceState *parent, PMSMBus *smb) { smb->smbus = i2c_init_bus(parent, "i2c"); + memory_region_init_io(&smb->io, &pm_smbus_ops, smb, "pm-smbus", 64); } diff --git a/hw/pm_smbus.h b/hw/pm_smbus.h index 4750a409f9..e3069bf7d4 100644 --- a/hw/pm_smbus.h +++ b/hw/pm_smbus.h @@ -3,6 +3,7 @@ typedef struct PMSMBus { i2c_bus *smbus; + MemoryRegion io; uint8_t smb_stat; uint8_t smb_ctl; @@ -15,7 +16,5 @@ typedef struct PMSMBus { } PMSMBus; void pm_smbus_init(DeviceState *parent, PMSMBus *smb); -void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val); -uint32_t smb_ioport_readb(void *opaque, uint32_t addr); #endif /* !PM_SMBUS_H */ @@ -23,12 +23,12 @@ */ #include "hw.h" #include "ppc.h" -#include "qemu-timer.h" -#include "sysemu.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" #include "nvram.h" -#include "qemu-log.h" +#include "qemu/log.h" #include "loader.h" -#include "kvm.h" +#include "sysemu/kvm.h" #include "kvm_ppc.h" //#define PPC_DEBUG_IRQ @@ -50,8 +50,9 @@ static void cpu_ppc_tb_stop (CPUPPCState *env); static void cpu_ppc_tb_start (CPUPPCState *env); -void ppc_set_irq(CPUPPCState *env, int n_IRQ, int level) +void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) { + CPUPPCState *env = &cpu->env; unsigned int old_pending = env->pending_interrupts; if (level) { @@ -65,7 +66,7 @@ void ppc_set_irq(CPUPPCState *env, int n_IRQ, int level) if (old_pending != env->pending_interrupts) { #ifdef CONFIG_KVM - kvmppc_set_interrupt(env, n_IRQ, level); + kvmppc_set_interrupt(cpu, n_IRQ, level); #endif } @@ -75,9 +76,10 @@ void ppc_set_irq(CPUPPCState *env, int n_IRQ, int level) } /* PowerPC 6xx / 7xx internal IRQ controller */ -static void ppc6xx_set_irq (void *opaque, int pin, int level) +static void ppc6xx_set_irq(void *opaque, int pin, int level) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; int cur_level; LOG_IRQ("%s: env %p pin %d level %d\n", __func__, @@ -99,13 +101,13 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) /* Level sensitive - active high */ LOG_IRQ("%s: set the external IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); break; case PPC6xx_INPUT_SMI: /* Level sensitive - active high */ LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_SMI, level); + ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level); break; case PPC6xx_INPUT_MCP: /* Negative edge sensitive */ @@ -115,7 +117,7 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) if (cur_level == 1 && level == 0) { LOG_IRQ("%s: raise machine check state\n", __func__); - ppc_set_irq(env, PPC_INTERRUPT_MCK, 1); + ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); } break; case PPC6xx_INPUT_CKSTP_IN: @@ -137,7 +139,7 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) case PPC6xx_INPUT_SRESET: LOG_IRQ("%s: set the RESET IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_RESET, level); + ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); break; default: /* Unknown pin - do nothing */ @@ -151,17 +153,20 @@ static void ppc6xx_set_irq (void *opaque, int pin, int level) } } -void ppc6xx_irq_init (CPUPPCState *env) +void ppc6xx_irq_init(CPUPPCState *env) { - env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu, PPC6xx_INPUT_NB); } #if defined(TARGET_PPC64) /* PowerPC 970 internal IRQ controller */ -static void ppc970_set_irq (void *opaque, int pin, int level) +static void ppc970_set_irq(void *opaque, int pin, int level) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; int cur_level; LOG_IRQ("%s: env %p pin %d level %d\n", __func__, @@ -174,13 +179,13 @@ static void ppc970_set_irq (void *opaque, int pin, int level) /* Level sensitive - active high */ LOG_IRQ("%s: set the external IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); break; case PPC970_INPUT_THINT: /* Level sensitive - active high */ LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_THERM, level); + ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level); break; case PPC970_INPUT_MCP: /* Negative edge sensitive */ @@ -190,7 +195,7 @@ static void ppc970_set_irq (void *opaque, int pin, int level) if (cur_level == 1 && level == 0) { LOG_IRQ("%s: raise machine check state\n", __func__); - ppc_set_irq(env, PPC_INTERRUPT_MCK, 1); + ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); } break; case PPC970_INPUT_CKSTP: @@ -202,7 +207,7 @@ static void ppc970_set_irq (void *opaque, int pin, int level) } else { LOG_IRQ("%s: restart the CPU\n", __func__); env->halted = 0; - qemu_cpu_kick(env); + qemu_cpu_kick(CPU(cpu)); } break; case PPC970_INPUT_HRESET: @@ -214,7 +219,7 @@ static void ppc970_set_irq (void *opaque, int pin, int level) case PPC970_INPUT_SRESET: LOG_IRQ("%s: set the RESET IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_RESET, level); + ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); break; case PPC970_INPUT_TBEN: LOG_IRQ("%s: set the TBEN state to %d\n", __func__, @@ -233,16 +238,19 @@ static void ppc970_set_irq (void *opaque, int pin, int level) } } -void ppc970_irq_init (CPUPPCState *env) +void ppc970_irq_init(CPUPPCState *env) { - env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env, + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu, PPC970_INPUT_NB); } /* POWER7 internal IRQ controller */ -static void power7_set_irq (void *opaque, int pin, int level) +static void power7_set_irq(void *opaque, int pin, int level) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; LOG_IRQ("%s: env %p pin %d level %d\n", __func__, env, pin, level); @@ -252,7 +260,7 @@ static void power7_set_irq (void *opaque, int pin, int level) /* Level sensitive - active high */ LOG_IRQ("%s: set the external IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); break; default: /* Unknown pin - do nothing */ @@ -266,17 +274,20 @@ static void power7_set_irq (void *opaque, int pin, int level) } } -void ppcPOWER7_irq_init (CPUPPCState *env) +void ppcPOWER7_irq_init(CPUPPCState *env) { - env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, env, + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu, POWER7_INPUT_NB); } #endif /* defined(TARGET_PPC64) */ /* PowerPC 40x internal IRQ controller */ -static void ppc40x_set_irq (void *opaque, int pin, int level) +static void ppc40x_set_irq(void *opaque, int pin, int level) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; int cur_level; LOG_IRQ("%s: env %p pin %d level %d\n", __func__, @@ -309,13 +320,13 @@ static void ppc40x_set_irq (void *opaque, int pin, int level) /* Level sensitive - active high */ LOG_IRQ("%s: set the critical IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_CEXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); break; case PPC40x_INPUT_INT: /* Level sensitive - active high */ LOG_IRQ("%s: set the external IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); break; case PPC40x_INPUT_HALT: /* Level sensitive - active low */ @@ -325,14 +336,14 @@ static void ppc40x_set_irq (void *opaque, int pin, int level) } else { LOG_IRQ("%s: restart the CPU\n", __func__); env->halted = 0; - qemu_cpu_kick(env); + qemu_cpu_kick(CPU(cpu)); } break; case PPC40x_INPUT_DEBUG: /* Level sensitive - active high */ LOG_IRQ("%s: set the debug pin state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level); + ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); break; default: /* Unknown pin - do nothing */ @@ -346,16 +357,19 @@ static void ppc40x_set_irq (void *opaque, int pin, int level) } } -void ppc40x_irq_init (CPUPPCState *env) +void ppc40x_irq_init(CPUPPCState *env) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq, - env, PPC40x_INPUT_NB); + cpu, PPC40x_INPUT_NB); } /* PowerPC E500 internal IRQ controller */ -static void ppce500_set_irq (void *opaque, int pin, int level) +static void ppce500_set_irq(void *opaque, int pin, int level) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; int cur_level; LOG_IRQ("%s: env %p pin %d level %d\n", __func__, @@ -374,26 +388,26 @@ static void ppce500_set_irq (void *opaque, int pin, int level) case PPCE500_INPUT_RESET_CORE: if (level) { LOG_IRQ("%s: reset the PowerPC core\n", __func__); - ppc_set_irq(env, PPC_INTERRUPT_MCK, level); + ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level); } break; case PPCE500_INPUT_CINT: /* Level sensitive - active high */ LOG_IRQ("%s: set the critical IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_CEXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); break; case PPCE500_INPUT_INT: /* Level sensitive - active high */ LOG_IRQ("%s: set the core IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); break; case PPCE500_INPUT_DEBUG: /* Level sensitive - active high */ LOG_IRQ("%s: set the debug pin state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level); + ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); break; default: /* Unknown pin - do nothing */ @@ -407,10 +421,12 @@ static void ppce500_set_irq (void *opaque, int pin, int level) } } -void ppce500_irq_init (CPUPPCState *env) +void ppce500_irq_init(CPUPPCState *env) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq, - env, PPCE500_INPUT_NB); + cpu, PPCE500_INPUT_NB); } /*****************************************************************************/ /* PowerPC time base and decrementer emulation */ @@ -628,26 +644,27 @@ uint64_t cpu_ppc_load_purr (CPUPPCState *env) /* When decrementer expires, * all we need to do is generate or queue a CPU exception */ -static inline void cpu_ppc_decr_excp(CPUPPCState *env) +static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu) { /* Raise it */ LOG_TB("raise decrementer exception\n"); - ppc_set_irq(env, PPC_INTERRUPT_DECR, 1); + ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1); } -static inline void cpu_ppc_hdecr_excp(CPUPPCState *env) +static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) { /* Raise it */ LOG_TB("raise decrementer exception\n"); - ppc_set_irq(env, PPC_INTERRUPT_HDECR, 1); + ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); } -static void __cpu_ppc_store_decr (CPUPPCState *env, uint64_t *nextp, - struct QEMUTimer *timer, - void (*raise_excp)(CPUPPCState *), - uint32_t decr, uint32_t value, - int is_excp) +static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, + struct QEMUTimer *timer, + void (*raise_excp)(PowerPCCPU *), + uint32_t decr, uint32_t value, + int is_excp) { + CPUPPCState *env = &cpu->env; ppc_tb_t *tb_env = env->tb_env; uint64_t now, next; @@ -677,53 +694,61 @@ static void __cpu_ppc_store_decr (CPUPPCState *env, uint64_t *nextp, if ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && (value & 0x80000000) && !(decr & 0x80000000)) { - (*raise_excp)(env); + (*raise_excp)(cpu); } } -static inline void _cpu_ppc_store_decr(CPUPPCState *env, uint32_t decr, +static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr, uint32_t value, int is_excp) { - ppc_tb_t *tb_env = env->tb_env; + ppc_tb_t *tb_env = cpu->env.tb_env; - __cpu_ppc_store_decr(env, &tb_env->decr_next, tb_env->decr_timer, + __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer, &cpu_ppc_decr_excp, decr, value, is_excp); } void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value) { - _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0); + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, 0); } -static void cpu_ppc_decr_cb (void *opaque) +static void cpu_ppc_decr_cb(void *opaque) { - _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1); + PowerPCCPU *cpu = opaque; + + _cpu_ppc_store_decr(cpu, 0x00000000, 0xFFFFFFFF, 1); } -static inline void _cpu_ppc_store_hdecr(CPUPPCState *env, uint32_t hdecr, +static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr, uint32_t value, int is_excp) { - ppc_tb_t *tb_env = env->tb_env; + ppc_tb_t *tb_env = cpu->env.tb_env; if (tb_env->hdecr_timer != NULL) { - __cpu_ppc_store_decr(env, &tb_env->hdecr_next, tb_env->hdecr_timer, + __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer, &cpu_ppc_hdecr_excp, hdecr, value, is_excp); } } void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value) { - _cpu_ppc_store_hdecr(env, cpu_ppc_load_hdecr(env), value, 0); + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 0); } -static void cpu_ppc_hdecr_cb (void *opaque) +static void cpu_ppc_hdecr_cb(void *opaque) { - _cpu_ppc_store_hdecr(opaque, 0x00000000, 0xFFFFFFFF, 1); + PowerPCCPU *cpu = opaque; + + _cpu_ppc_store_hdecr(cpu, 0x00000000, 0xFFFFFFFF, 1); } -void cpu_ppc_store_purr (CPUPPCState *env, uint64_t value) +static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value) { - ppc_tb_t *tb_env = env->tb_env; + ppc_tb_t *tb_env = cpu->env.tb_env; tb_env->purr_load = value; tb_env->purr_start = qemu_get_clock_ns(vm_clock); @@ -732,6 +757,7 @@ void cpu_ppc_store_purr (CPUPPCState *env, uint64_t value) static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) { CPUPPCState *env = opaque; + PowerPCCPU *cpu = ppc_env_get_cpu(env); ppc_tb_t *tb_env = env->tb_env; tb_env->tb_freq = freq; @@ -740,25 +766,27 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) * if a decrementer exception is pending when it enables msr_ee at startup, * it's not ready to handle it... */ - _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); - _cpu_ppc_store_hdecr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); - cpu_ppc_store_purr(env, 0x0000000000000000ULL); + _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0); + _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0); + cpu_ppc_store_purr(cpu, 0x0000000000000000ULL); } /* Set up (once) timebase frequency (in Hz) */ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); ppc_tb_t *tb_env; tb_env = g_malloc0(sizeof(ppc_tb_t)); env->tb_env = tb_env; tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; /* Create new timer */ - tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, env); + tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, cpu); if (0) { /* XXX: find a suitable condition to enable the hypervisor decrementer */ - tb_env->hdecr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_hdecr_cb, env); + tb_env->hdecr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_hdecr_cb, + cpu); } else { tb_env->hdecr_timer = NULL; } @@ -814,12 +842,14 @@ struct ppc40x_timer_t { /* Fixed interval timer */ static void cpu_4xx_fit_cb (void *opaque) { + PowerPCCPU *cpu; CPUPPCState *env; ppc_tb_t *tb_env; ppc40x_timer_t *ppc40x_timer; uint64_t now, next; env = opaque; + cpu = ppc_env_get_cpu(env); tb_env = env->tb_env; ppc40x_timer = tb_env->opaque; now = qemu_get_clock_ns(vm_clock); @@ -845,8 +875,9 @@ static void cpu_4xx_fit_cb (void *opaque) next++; qemu_mod_timer(ppc40x_timer->fit_timer, next); env->spr[SPR_40x_TSR] |= 1 << 26; - if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) - ppc_set_irq(env, PPC_INTERRUPT_FIT, 1); + if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { + ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1); + } LOG_TB("%s: ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__, (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); @@ -882,16 +913,19 @@ static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) static void cpu_4xx_pit_cb (void *opaque) { + PowerPCCPU *cpu; CPUPPCState *env; ppc_tb_t *tb_env; ppc40x_timer_t *ppc40x_timer; env = opaque; + cpu = ppc_env_get_cpu(env); tb_env = env->tb_env; ppc40x_timer = tb_env->opaque; env->spr[SPR_40x_TSR] |= 1 << 27; - if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) - ppc_set_irq(env, ppc40x_timer->decr_excp, 1); + if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) { + ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1); + } start_stop_pit(env, tb_env, 1); LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " " "%016" PRIx64 "\n", __func__, @@ -904,12 +938,14 @@ static void cpu_4xx_pit_cb (void *opaque) /* Watchdog timer */ static void cpu_4xx_wdt_cb (void *opaque) { + PowerPCCPU *cpu; CPUPPCState *env; ppc_tb_t *tb_env; ppc40x_timer_t *ppc40x_timer; uint64_t now, next; env = opaque; + cpu = ppc_env_get_cpu(env); tb_env = env->tb_env; ppc40x_timer = tb_env->opaque; now = qemu_get_clock_ns(vm_clock); @@ -946,8 +982,9 @@ static void cpu_4xx_wdt_cb (void *opaque) qemu_mod_timer(ppc40x_timer->wdt_timer, next); ppc40x_timer->wdt_next = next; env->spr[SPR_40x_TSR] |= 1 << 30; - if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) - ppc_set_irq(env, PPC_INTERRUPT_WDT, 1); + if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) { + ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1); + } break; case 0x3: env->spr[SPR_40x_TSR] &= ~0x30000000; @@ -1152,23 +1189,23 @@ static inline void nvram_write (nvram_t *nvram, uint32_t addr, uint32_t val) (*nvram->write_fn)(nvram->opaque, addr, val); } -void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value) +static void NVRAM_set_byte(nvram_t *nvram, uint32_t addr, uint8_t value) { nvram_write(nvram, addr, value); } -uint8_t NVRAM_get_byte (nvram_t *nvram, uint32_t addr) +static uint8_t NVRAM_get_byte(nvram_t *nvram, uint32_t addr) { return nvram_read(nvram, addr); } -void NVRAM_set_word (nvram_t *nvram, uint32_t addr, uint16_t value) +static void NVRAM_set_word(nvram_t *nvram, uint32_t addr, uint16_t value) { nvram_write(nvram, addr, value >> 8); nvram_write(nvram, addr + 1, value & 0xFF); } -uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr) +static uint16_t NVRAM_get_word(nvram_t *nvram, uint32_t addr) { uint16_t tmp; @@ -1178,7 +1215,7 @@ uint16_t NVRAM_get_word (nvram_t *nvram, uint32_t addr) return tmp; } -void NVRAM_set_lword (nvram_t *nvram, uint32_t addr, uint32_t value) +static void NVRAM_set_lword(nvram_t *nvram, uint32_t addr, uint32_t value) { nvram_write(nvram, addr, value >> 24); nvram_write(nvram, addr + 1, (value >> 16) & 0xFF); @@ -1198,8 +1235,8 @@ uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr) return tmp; } -void NVRAM_set_string (nvram_t *nvram, uint32_t addr, - const char *str, uint32_t max) +static void NVRAM_set_string(nvram_t *nvram, uint32_t addr, const char *str, + uint32_t max) { int i; @@ -1,4 +1,7 @@ -void ppc_set_irq (CPUPPCState *env, int n_IRQ, int level); +#ifndef HW_PPC_H +#define HW_PPC_H 1 + +void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level); /* PowerPC hardware exceptions management helpers */ typedef void (*clk_setup_cb)(void *opaque, uint32_t freq); @@ -89,4 +92,6 @@ enum { #define PPC_SERIAL_MM_BAUDBASE 399193 /* ppc_booke.c */ -void ppc_booke_timers_init(CPUPPCState *env, uint32_t freq, uint32_t flags); +void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags); + +#endif diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index aa4bbeb664..afdcc0e531 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -10,12 +10,13 @@ obj-y += ppc_newworld.o # IBM pSeries (sPAPR) obj-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o -obj-$(CONFIG_PSERIES) += spapr_pci.o pci-hotplug.o spapr_iommu.o +obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o spapr_iommu.o +obj-$(CONFIG_PSERIES) += spapr_events.o spapr_nvram.o # PowerPC 4xx boards obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o obj-y += ppc440_bamboo.o # PowerPC E500 boards -obj-$(CONFIG_FDT) += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o +obj-$(CONFIG_FDT) += mpc8544_guts.o ppce500_spin.o # PowerPC 440 Xilinx ML507 reference board. obj-y += virtex_ml507.o # PowerPC OpenPIC @@ -26,3 +27,5 @@ obj-$(CONFIG_FDT) += ../device_tree.o obj-y += xilinx_ethlite.o obj-y := $(addprefix ../,$(obj-y)) + +obj-$(CONFIG_FDT) += e500.o mpc8544ds.o e500plat.o diff --git a/hw/ppc/e500-ccsr.h b/hw/ppc/e500-ccsr.h new file mode 100644 index 0000000000..f20f51bcd2 --- /dev/null +++ b/hw/ppc/e500-ccsr.h @@ -0,0 +1,17 @@ +#ifndef E500_CCSR_H +#define E500_CCSR_H + +#include "../sysbus.h" + +typedef struct PPCE500CCSRState { + /*< private >*/ + SysBusDevice parent; + /*< public >*/ + + MemoryRegion ccsr_space; +} PPCE500CCSRState; + +#define TYPE_CCSR "e500-ccsr" +#define CCSR(obj) OBJECT_CHECK(PPCE500CCSRState, (obj), TYPE_CCSR) + +#endif /* E500_CCSR_H */ diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppc/e500.c index 8b9fd83ce1..b262f31e5a 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppc/e500.c @@ -1,5 +1,5 @@ /* - * QEMU PowerPC MPC8544DS board emulation + * QEMU PowerPC e500-based platforms * * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved. * @@ -16,42 +16,49 @@ #include "config.h" #include "qemu-common.h" -#include "net.h" -#include "hw.h" -#include "pc.h" -#include "pci.h" -#include "boards.h" -#include "sysemu.h" -#include "kvm.h" +#include "e500.h" +#include "e500-ccsr.h" +#include "net/net.h" +#include "qemu/config-file.h" +#include "hw/hw.h" +#include "hw/serial.h" +#include "hw/pci/pci.h" +#include "hw/boards.h" +#include "sysemu/sysemu.h" +#include "sysemu/kvm.h" #include "kvm_ppc.h" -#include "device_tree.h" -#include "openpic.h" -#include "ppc.h" -#include "loader.h" +#include "sysemu/device_tree.h" +#include "hw/openpic.h" +#include "hw/ppc.h" +#include "hw/loader.h" #include "elf.h" -#include "sysbus.h" -#include "exec-memory.h" -#include "host-utils.h" +#include "hw/sysbus.h" +#include "exec/address-spaces.h" +#include "qemu/host-utils.h" +#include "hw/ppce500_pci.h" #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" #define UIMAGE_LOAD_BASE 0 -#define DTC_LOAD_PAD 0x500000 +#define DTC_LOAD_PAD 0x1800000 #define DTC_PAD_MASK 0xFFFFF #define INITRD_LOAD_PAD 0x2000000 #define INITRD_PAD_MASK 0xFFFFFF #define RAM_SIZES_ALIGN (64UL << 20) +/* TODO: parameterize */ #define MPC8544_CCSRBAR_BASE 0xE0000000ULL #define MPC8544_CCSRBAR_SIZE 0x00100000ULL -#define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000ULL) -#define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500ULL) -#define MPC8544_SERIAL1_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4600ULL) -#define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x8000ULL) +#define MPC8544_MPIC_REGS_OFFSET 0x40000ULL +#define MPC8544_MSI_REGS_OFFSET 0x41600ULL +#define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL +#define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL +#define MPC8544_PCI_REGS_OFFSET 0x8000ULL +#define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + \ + MPC8544_PCI_REGS_OFFSET) #define MPC8544_PCI_REGS_SIZE 0x1000ULL #define MPC8544_PCI_IO 0xE1000000ULL -#define MPC8544_PCI_IOLEN 0x10000ULL -#define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000ULL) +#define MPC8544_UTIL_OFFSET 0xe0000ULL #define MPC8544_SPIN_BASE 0xEF000000ULL struct boot_info @@ -61,25 +68,35 @@ struct boot_info uint32_t entry; }; -static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic) +static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot, + int nr_slots, int *len) { - int i; - const uint32_t tmp[] = { - /* IDSEL 0x11 J17 Slot 1 */ - 0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1, 0x0, 0x0, - 0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1, 0x0, 0x0, - 0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1, 0x0, 0x0, - 0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0, - - /* IDSEL 0x12 J16 Slot 2 */ - 0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1, 0x0, 0x0, - 0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1, 0x0, 0x0, - 0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1, 0x0, 0x0, - 0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0, - }; - for (i = 0; i < ARRAY_SIZE(tmp); i++) { - pci_map[i] = cpu_to_be32(tmp[i]); + int i = 0; + int slot; + int pci_irq; + int host_irq; + int last_slot = first_slot + nr_slots; + uint32_t *pci_map; + + *len = nr_slots * 4 * 7 * sizeof(uint32_t); + pci_map = g_malloc(*len); + + for (slot = first_slot; slot < last_slot; slot++) { + for (pci_irq = 0; pci_irq < 4; pci_irq++) { + pci_map[i++] = cpu_to_be32(slot << 11); + pci_map[i++] = cpu_to_be32(0x0); + pci_map[i++] = cpu_to_be32(0x0); + pci_map[i++] = cpu_to_be32(pci_irq + 1); + pci_map[i++] = cpu_to_be32(mpic); + host_irq = ppce500_pci_map_irq_slot(slot, pci_irq); + pci_map[i++] = cpu_to_be32(host_irq + 1); + pci_map[i++] = cpu_to_be32(0x1); + } } + + assert((i * sizeof(uint32_t)) == *len); + + return pci_map; } static void dt_serial_create(void *fdt, unsigned long long offset, @@ -95,7 +112,7 @@ static void dt_serial_create(void *fdt, unsigned long long offset, qemu_devtree_setprop_cells(fdt, ser, "reg", offset, 0x100); qemu_devtree_setprop_cell(fdt, ser, "cell-index", idx); qemu_devtree_setprop_cell(fdt, ser, "clock-frequency", 0); - qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2, 0, 0); + qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2); qemu_devtree_setprop_phandle(fdt, ser, "interrupt-parent", mpic); qemu_devtree_setprop_string(fdt, "/aliases", alias, ser); @@ -104,31 +121,31 @@ static void dt_serial_create(void *fdt, unsigned long long offset, } } -static int mpc8544_load_device_tree(CPUPPCState *env, - target_phys_addr_t addr, - target_phys_addr_t ramsize, - target_phys_addr_t initrd_base, - target_phys_addr_t initrd_size, - const char *kernel_cmdline) +static int ppce500_load_device_tree(CPUPPCState *env, + PPCE500Params *params, + hwaddr addr, + hwaddr initrd_base, + hwaddr initrd_size) { int ret = -1; - uint64_t mem_reg_property[] = { 0, cpu_to_be64(ramsize) }; + uint64_t mem_reg_property[] = { 0, cpu_to_be64(params->ram_size) }; int fdt_size; void *fdt; uint8_t hypercall[16]; uint32_t clock_freq = 400000000; uint32_t tb_freq = 400000000; int i; - const char *compatible = "MPC8544DS\0MPC85xxDS"; - int compatible_len = sizeof("MPC8544DS\0MPC85xxDS"); + const char *toplevel_compat = NULL; /* user override */ char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus"; - char model[] = "MPC8544DS"; char soc[128]; char mpic[128]; uint32_t mpic_ph; + uint32_t msi_ph; char gutil[128]; char pci[128]; - uint32_t pci_map[9 * 8]; + char msi[128]; + uint32_t *pci_map = NULL; + int len; uint32_t pci_ranges[14] = { 0x2000000, 0x0, 0xc0000000, @@ -140,19 +157,12 @@ static int mpc8544_load_device_tree(CPUPPCState *env, 0x0, 0x10000, }; QemuOpts *machine_opts; - const char *dumpdtb = NULL; const char *dtb_file = NULL; machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); if (machine_opts) { - const char *tmp; - dumpdtb = qemu_opt_get(machine_opts, "dumpdtb"); dtb_file = qemu_opt_get(machine_opts, "dtb"); - tmp = qemu_opt_get(machine_opts, "dt_compatible"); - if (tmp) { - compatible = tmp; - compatible_len = strlen(compatible) + 1; - } + toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible"); } if (dtb_file) { @@ -175,8 +185,6 @@ static int mpc8544_load_device_tree(CPUPPCState *env, } /* Manipulate device tree in memory. */ - qemu_devtree_setprop_string(fdt, "/", "model", model); - qemu_devtree_setprop(fdt, "/", "compatible", compatible, compatible_len); qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2); qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2); @@ -201,7 +209,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env, } ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", - kernel_cmdline); + params->kernel_cmdline); if (ret < 0) fprintf(stderr, "couldn't set /chosen/bootargs\n"); @@ -278,41 +286,55 @@ static int mpc8544_load_device_tree(CPUPPCState *env, /* XXX should contain a reasonable value */ qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0); - snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, - MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE); + snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET); qemu_devtree_add_subnode(fdt, mpic); qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic"); - qemu_devtree_setprop_string(fdt, mpic, "compatible", "fsl,mpic"); - qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE - - MPC8544_CCSRBAR_BASE, 0x40000); + qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic"); + qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET, + 0x40000); qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0); - qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 4); + qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2); mpic_ph = qemu_devtree_alloc_phandle(fdt); qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph); qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph); qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0); - qemu_devtree_setprop(fdt, mpic, "big-endian", NULL, 0); - qemu_devtree_setprop(fdt, mpic, "single-cpu-affinity", NULL, 0); - qemu_devtree_setprop_cell(fdt, mpic, "last-interrupt-source", 255); /* * We have to generate ser1 first, because Linux takes the first * device it finds in the dt as serial output device. And we generate * devices in reverse order to the dt. */ - dt_serial_create(fdt, MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE, + dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET, soc, mpic, "serial1", 1, false); - dt_serial_create(fdt, MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE, + dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET, soc, mpic, "serial0", 0, true); snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc, - MPC8544_UTIL_BASE - MPC8544_CCSRBAR_BASE); + MPC8544_UTIL_OFFSET); qemu_devtree_add_subnode(fdt, gutil); qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts"); - qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_BASE - - MPC8544_CCSRBAR_BASE, 0x1000); + qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000); qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0); + snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET); + qemu_devtree_add_subnode(fdt, msi); + qemu_devtree_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi"); + qemu_devtree_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200); + msi_ph = qemu_devtree_alloc_phandle(fdt); + qemu_devtree_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100); + qemu_devtree_setprop_phandle(fdt, msi, "interrupt-parent", mpic); + qemu_devtree_setprop_cells(fdt, msi, "interrupts", + 0xe0, 0x0, + 0xe1, 0x0, + 0xe2, 0x0, + 0xe3, 0x0, + 0xe4, 0x0, + 0xe5, 0x0, + 0xe6, 0x0, + 0xe7, 0x0); + qemu_devtree_setprop_cell(fdt, msi, "phandle", msi_ph); + qemu_devtree_setprop_cell(fdt, msi, "linux,phandle", msi_ph); + snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE); qemu_devtree_add_subnode(fdt, pci); qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0); @@ -320,14 +342,17 @@ static int mpc8544_load_device_tree(CPUPPCState *env, qemu_devtree_setprop_string(fdt, pci, "device_type", "pci"); qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0, 0x0, 0x7); - pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic)); - qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map)); + pci_map = pci_map_create(fdt, qemu_devtree_get_phandle(fdt, mpic), + params->pci_first_slot, params->pci_nr_slots, + &len); + qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, len); qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic); - qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2, 0, 0); + qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2); qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255); for (i = 0; i < 14; i++) { pci_ranges[i] = cpu_to_be32(pci_ranges[i]); } + qemu_devtree_setprop_cell(fdt, pci, "fsl,msi", msi_ph); qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32, MPC8544_PCI_REGS_BASE, 0, 0x1000); @@ -337,19 +362,15 @@ static int mpc8544_load_device_tree(CPUPPCState *env, qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3); qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci); -done: - if (dumpdtb) { - /* Dump the dtb to a file and quit */ - FILE *f = fopen(dumpdtb, "wb"); - size_t len; - len = fwrite(fdt, fdt_size, 1, f); - fclose(f); - if (len != fdt_size) { - exit(1); - } - exit(0); + params->fixup_devtree(params, fdt); + + if (toplevel_compat) { + qemu_devtree_setprop(fdt, "/", "compatible", toplevel_compat, + strlen(toplevel_compat) + 1); } +done: + qemu_devtree_dumpdtb(fdt, fdt_size); ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); if (ret < 0) { goto out; @@ -358,12 +379,13 @@ done: ret = fdt_size; out: + g_free(pci_map); return ret; } /* Create -kernel TLB entries for BookE. */ -static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size) +static inline hwaddr booke206_page_size_to_tlb(uint64_t size) { return 63 - clz64(size >> 10); } @@ -372,13 +394,17 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env) { struct boot_info *bi = env->load_info; ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); - target_phys_addr_t size, dt_end; + hwaddr size, dt_end; int ps; /* Our initial TLB entry needs to cover everything from 0 to the device tree top */ dt_end = bi->dt_base + bi->dt_size; ps = booke206_page_size_to_tlb(dt_end) + 1; + if (ps & 1) { + /* e500v2 can only do even TLB size bits */ + ps++; + } size = (ps << MAS1_TSIZE_SHIFT); tlb->mas1 = MAS1_VALID | size; tlb->mas2 = 0; @@ -388,7 +414,7 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env) env->tlb_dirty = true; } -static void mpc8544ds_cpu_reset_sec(void *opaque) +static void ppce500_cpu_reset_sec(void *opaque) { PowerPCCPU *cpu = opaque; CPUPPCState *env = &cpu->env; @@ -401,7 +427,7 @@ static void mpc8544ds_cpu_reset_sec(void *opaque) env->exception_index = EXCP_HLT; } -static void mpc8544ds_cpu_reset(void *opaque) +static void ppce500_cpu_reset(void *opaque) { PowerPCCPU *cpu = opaque; CPUPPCState *env = &cpu->env; @@ -417,12 +443,7 @@ static void mpc8544ds_cpu_reset(void *opaque) mmubooke_create_initial_mapping(env); } -static void mpc8544ds_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +void ppce500_init(PPCE500Params *params) { MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); @@ -430,21 +451,24 @@ static void mpc8544ds_init(ram_addr_t ram_size, CPUPPCState *env = NULL; uint64_t elf_entry; uint64_t elf_lowaddr; - target_phys_addr_t entry=0; - target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE; + hwaddr entry=0; + hwaddr loadaddr=UIMAGE_LOAD_BASE; target_long kernel_size=0; target_ulong dt_base = 0; target_ulong initrd_base = 0; target_long initrd_size=0; - int i=0; + int i = 0, j, k; unsigned int pci_irq_nrs[4] = {1, 2, 3, 4}; qemu_irq **irqs, *mpic; DeviceState *dev; CPUPPCState *firstenv = NULL; + MemoryRegion *ccsr_addr_space; + SysBusDevice *s; + PPCE500CCSRState *ccsr; /* Setup CPUs */ - if (cpu_model == NULL) { - cpu_model = "e500v2_v30"; + if (params->cpu_model == NULL) { + params->cpu_model = "e500v2_v30"; } irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *)); @@ -453,7 +477,7 @@ static void mpc8544ds_init(ram_addr_t ram_size, PowerPCCPU *cpu; qemu_irq *input; - cpu = cpu_ppc_init(cpu_model); + cpu = cpu_ppc_init(params->cpu_model); if (cpu == NULL) { fprintf(stderr, "Unable to initialize CPU!\n"); exit(1); @@ -469,20 +493,21 @@ static void mpc8544ds_init(ram_addr_t ram_size, irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; env->spr[SPR_BOOKE_PIR] = env->cpu_index = i; - env->mpic_cpu_base = MPC8544_MPIC_REGS_BASE + 0x20000; + env->mpic_cpu_base = MPC8544_CCSRBAR_BASE + + MPC8544_MPIC_REGS_OFFSET + 0x20000; - ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500); + ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); /* Register reset handler */ if (!i) { /* Primary CPU */ struct boot_info *boot_info; boot_info = g_malloc0(sizeof(struct boot_info)); - qemu_register_reset(mpc8544ds_cpu_reset, cpu); + qemu_register_reset(ppce500_cpu_reset, cpu); env->load_info = boot_info; } else { /* Secondary CPUs */ - qemu_register_reset(mpc8544ds_cpu_reset_sec, cpu); + qemu_register_reset(ppce500_cpu_reset_sec, cpu); } } @@ -496,40 +521,74 @@ static void mpc8544ds_init(ram_addr_t ram_size, vmstate_register_ram_global(ram); memory_region_add_subregion(address_space_mem, 0, ram); + dev = qdev_create(NULL, "e500-ccsr"); + object_property_add_child(qdev_get_machine(), "e500-ccsr", + OBJECT(dev), NULL); + qdev_init_nofail(dev); + ccsr = CCSR(dev); + ccsr_addr_space = &ccsr->ccsr_space; + memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE, + ccsr_addr_space); + /* MPIC */ - mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE, - smp_cpus, irqs, NULL); + mpic = g_new(qemu_irq, 256); + dev = qdev_create(NULL, "openpic"); + qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); + qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_FSL_MPIC_20); + qdev_init_nofail(dev); + s = sysbus_from_qdev(dev); + + k = 0; + for (i = 0; i < smp_cpus; i++) { + for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { + sysbus_connect_irq(s, k++, irqs[i][j]); + } + } - if (!mpic) { - cpu_abort(env, "MPIC failed to initialize\n"); + for (i = 0; i < 256; i++) { + mpic[i] = qdev_get_gpio_in(dev, i); } + memory_region_add_subregion(ccsr_addr_space, MPC8544_MPIC_REGS_OFFSET, + s->mmio[0].memory); + /* Serial */ if (serial_hds[0]) { - serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE, - 0, mpic[12+26], 399193, + serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET, + 0, mpic[42], 399193, serial_hds[0], DEVICE_BIG_ENDIAN); } if (serial_hds[1]) { - serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE, - 0, mpic[12+26], 399193, - serial_hds[0], DEVICE_BIG_ENDIAN); + serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET, + 0, mpic[42], 399193, + serial_hds[1], DEVICE_BIG_ENDIAN); } /* General Utility device */ - sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL); + dev = qdev_create(NULL, "mpc8544-guts"); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET, + sysbus_mmio_get_region(s, 0)); /* PCI */ - dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE, - mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]], - mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]], - NULL); + dev = qdev_create(NULL, "e500-pcihost"); + qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(s, 0, mpic[pci_irq_nrs[0]]); + sysbus_connect_irq(s, 1, mpic[pci_irq_nrs[1]]); + sysbus_connect_irq(s, 2, mpic[pci_irq_nrs[2]]); + sysbus_connect_irq(s, 3, mpic[pci_irq_nrs[3]]); + memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET, + sysbus_mmio_get_region(s, 0)); + pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); if (!pci_bus) printf("couldn't create PCI controller!\n"); - isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN); + sysbus_mmio_map(sysbus_from_qdev(dev), 1, MPC8544_PCI_IO); if (pci_bus) { /* Register network interfaces. */ @@ -542,43 +601,46 @@ static void mpc8544ds_init(ram_addr_t ram_size, sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL); /* Load kernel. */ - if (kernel_filename) { - kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL); + if (params->kernel_filename) { + kernel_size = load_uimage(params->kernel_filename, &entry, + &loadaddr, NULL); if (kernel_size < 0) { - kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry, - &elf_lowaddr, NULL, 1, ELF_MACHINE, 0); + kernel_size = load_elf(params->kernel_filename, NULL, NULL, + &elf_entry, &elf_lowaddr, NULL, 1, + ELF_MACHINE, 0); entry = elf_entry; loadaddr = elf_lowaddr; } /* XXX try again as binary */ if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); + params->kernel_filename); exit(1); } } /* Load initrd. */ - if (initrd_filename) { - initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; - initrd_size = load_image_targphys(initrd_filename, initrd_base, + if (params->initrd_filename) { + initrd_base = (loadaddr + kernel_size + INITRD_LOAD_PAD) & + ~INITRD_PAD_MASK; + initrd_size = load_image_targphys(params->initrd_filename, initrd_base, ram_size - initrd_base); if (initrd_size < 0) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); + params->initrd_filename); exit(1); } } /* If we're loading a kernel directly, we must load the device tree too. */ - if (kernel_filename) { + if (params->kernel_filename) { struct boot_info *boot_info; int dt_size; dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; - dt_size = mpc8544_load_device_tree(env, dt_base, ram_size, initrd_base, - initrd_size, kernel_cmdline); + dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base, + initrd_size); if (dt_size < 0) { fprintf(stderr, "couldn't load device tree\n"); exit(1); @@ -595,16 +657,32 @@ static void mpc8544ds_init(ram_addr_t ram_size, } } -static QEMUMachine mpc8544ds_machine = { - .name = "mpc8544ds", - .desc = "mpc8544ds", - .init = mpc8544ds_init, - .max_cpus = 15, +static int e500_ccsr_initfn(SysBusDevice *dev) +{ + PPCE500CCSRState *ccsr; + + ccsr = CCSR(dev); + memory_region_init(&ccsr->ccsr_space, "e500-ccsr", + MPC8544_CCSRBAR_SIZE); + return 0; +} + +static void e500_ccsr_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = e500_ccsr_initfn; +} + +static const TypeInfo e500_ccsr_info = { + .name = TYPE_CCSR, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PPCE500CCSRState), + .class_init = e500_ccsr_class_init, }; -static void mpc8544ds_machine_init(void) +static void e500_register_types(void) { - qemu_register_machine(&mpc8544ds_machine); + type_register_static(&e500_ccsr_info); } -machine_init(mpc8544ds_machine_init); +type_init(e500_register_types) diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h new file mode 100644 index 0000000000..f5ff27385b --- /dev/null +++ b/hw/ppc/e500.h @@ -0,0 +1,23 @@ +#ifndef PPCE500_H +#define PPCE500_H + +typedef struct PPCE500Params { + /* Standard QEMU machine init params */ + ram_addr_t ram_size; + const char *boot_device; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; + const char *cpu_model; + int pci_first_slot; + int pci_nr_slots; + + /* e500-specific params */ + + /* required -- must at least add toplevel board compatible */ + void (*fixup_devtree)(struct PPCE500Params *params, void *fdt); +} PPCE500Params; + +void ppce500_init(PPCE500Params *params); + +#endif diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c new file mode 100644 index 0000000000..4deb02ac38 --- /dev/null +++ b/hw/ppc/e500plat.c @@ -0,0 +1,64 @@ +/* + * Generic device-tree-driven paravirt PPC e500 platform + * + * Copyright 2012 Freescale Semiconductor, Inc. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "config.h" +#include "qemu-common.h" +#include "e500.h" +#include "../boards.h" +#include "sysemu/device_tree.h" +#include "hw/pci/pci.h" + +static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt) +{ + const char model[] = "QEMU ppce500"; + const char compatible[] = "fsl,qemu-e500"; + + qemu_devtree_setprop(fdt, "/", "model", model, sizeof(model)); + qemu_devtree_setprop(fdt, "/", "compatible", compatible, + sizeof(compatible)); +} + +static void e500plat_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *boot_device = args->boot_device; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + PPCE500Params params = { + .ram_size = ram_size, + .boot_device = boot_device, + .kernel_filename = kernel_filename, + .kernel_cmdline = kernel_cmdline, + .initrd_filename = initrd_filename, + .cpu_model = cpu_model, + .pci_first_slot = 0x1, + .pci_nr_slots = PCI_SLOT_MAX - 1, + .fixup_devtree = e500plat_fixup_devtree, + }; + + ppce500_init(¶ms); +} + +static QEMUMachine e500plat_machine = { + .name = "ppce500", + .desc = "generic paravirt e500 platform", + .init = e500plat_init, + .max_cpus = 15, +}; + +static void e500plat_machine_init(void) +{ + qemu_register_machine(&e500plat_machine); +} + +machine_init(e500plat_machine_init); diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c new file mode 100644 index 0000000000..f9ae20f5a3 --- /dev/null +++ b/hw/ppc/mpc8544ds.c @@ -0,0 +1,64 @@ +/* + * Support for the PPC e500-based mpc8544ds board + * + * Copyright 2012 Freescale Semiconductor, Inc. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "config.h" +#include "qemu-common.h" +#include "e500.h" +#include "../boards.h" +#include "sysemu/device_tree.h" + +static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt) +{ + const char model[] = "MPC8544DS"; + const char compatible[] = "MPC8544DS\0MPC85xxDS"; + + qemu_devtree_setprop(fdt, "/", "model", model, sizeof(model)); + qemu_devtree_setprop(fdt, "/", "compatible", compatible, + sizeof(compatible)); +} + +static void mpc8544ds_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *boot_device = args->boot_device; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + PPCE500Params params = { + .ram_size = ram_size, + .boot_device = boot_device, + .kernel_filename = kernel_filename, + .kernel_cmdline = kernel_cmdline, + .initrd_filename = initrd_filename, + .cpu_model = cpu_model, + .pci_first_slot = 0x11, + .pci_nr_slots = 2, + .fixup_devtree = mpc8544ds_fixup_devtree, + }; + + ppce500_init(¶ms); +} + + +static QEMUMachine ppce500_machine = { + .name = "mpc8544ds", + .desc = "mpc8544ds", + .init = mpc8544ds_init, + .max_cpus = 15, +}; + +static void ppce500_machine_init(void) +{ + qemu_register_machine(&ppce500_machine); +} + +machine_init(ppce500_machine_init); diff --git a/hw/ppc405.h b/hw/ppc405.h index 1f5dc5fd36..535cbfb339 100644 --- a/hw/ppc405.h +++ b/hw/ppc405.h @@ -61,20 +61,20 @@ ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd, CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem, MemoryRegion ram_memories[4], - target_phys_addr_t ram_bases[4], - target_phys_addr_t ram_sizes[4], + hwaddr ram_bases[4], + hwaddr ram_sizes[4], uint32_t sysclk, qemu_irq **picp, int do_init); CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem, MemoryRegion ram_memories[2], - target_phys_addr_t ram_bases[2], - target_phys_addr_t ram_sizes[2], + hwaddr ram_bases[2], + hwaddr ram_sizes[2], uint32_t sysclk, qemu_irq **picp, int do_init); /* IBM STBxxx microcontrollers */ CPUPPCState *ppc_stb025_init (MemoryRegion ram_memories[2], - target_phys_addr_t ram_bases[2], - target_phys_addr_t ram_sizes[2], + hwaddr ram_bases[2], + hwaddr ram_sizes[2], uint32_t sysclk, qemu_irq **picp, ram_addr_t *offsetp); diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index 476775d05b..8f7f0d07d1 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -26,13 +26,13 @@ #include "ppc405.h" #include "nvram.h" #include "flash.h" -#include "sysemu.h" -#include "block.h" +#include "sysemu/sysemu.h" +#include "block/block.h" #include "boards.h" -#include "qemu-log.h" +#include "qemu/log.h" #include "loader.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" #define BIOS_FILENAME "ppc405_rom.bin" #define BIOS_SIZE (2048 * 1024) @@ -60,7 +60,7 @@ struct ref405ep_fpga_t { uint8_t reg1; }; -static uint32_t ref405ep_fpga_readb (void *opaque, target_phys_addr_t addr) +static uint32_t ref405ep_fpga_readb (void *opaque, hwaddr addr) { ref405ep_fpga_t *fpga; uint32_t ret; @@ -82,7 +82,7 @@ static uint32_t ref405ep_fpga_readb (void *opaque, target_phys_addr_t addr) } static void ref405ep_fpga_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { ref405ep_fpga_t *fpga; @@ -99,7 +99,7 @@ static void ref405ep_fpga_writeb (void *opaque, } } -static uint32_t ref405ep_fpga_readw (void *opaque, target_phys_addr_t addr) +static uint32_t ref405ep_fpga_readw (void *opaque, hwaddr addr) { uint32_t ret; @@ -110,13 +110,13 @@ static uint32_t ref405ep_fpga_readw (void *opaque, target_phys_addr_t addr) } static void ref405ep_fpga_writew (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { ref405ep_fpga_writeb(opaque, addr, (value >> 8) & 0xFF); ref405ep_fpga_writeb(opaque, addr + 1, value & 0xFF); } -static uint32_t ref405ep_fpga_readl (void *opaque, target_phys_addr_t addr) +static uint32_t ref405ep_fpga_readl (void *opaque, hwaddr addr) { uint32_t ret; @@ -129,7 +129,7 @@ static uint32_t ref405ep_fpga_readl (void *opaque, target_phys_addr_t addr) } static void ref405ep_fpga_writel (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { ref405ep_fpga_writeb(opaque, addr, (value >> 24) & 0xFF); ref405ep_fpga_writeb(opaque, addr + 1, (value >> 16) & 0xFF); @@ -158,7 +158,7 @@ static void ref405ep_fpga_reset (void *opaque) fpga->reg1 = 0x0F; } -static void ref405ep_fpga_init (MemoryRegion *sysmem, uint32_t base) +static void ref405ep_fpga_init(MemoryRegion *sysmem, uint32_t base) { ref405ep_fpga_t *fpga; MemoryRegion *fpga_memory = g_new(MemoryRegion, 1); @@ -170,13 +170,12 @@ static void ref405ep_fpga_init (MemoryRegion *sysmem, uint32_t base) qemu_register_reset(&ref405ep_fpga_reset, fpga); } -static void ref405ep_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void ref405ep_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; char *filename; ppc4xx_bd_info_t bd; CPUPPCState *env; @@ -185,7 +184,7 @@ static void ref405ep_init (ram_addr_t ram_size, MemoryRegion *sram = g_new(MemoryRegion, 1); ram_addr_t bdloc; MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories)); - target_phys_addr_t ram_bases[2], ram_sizes[2]; + hwaddr ram_bases[2], ram_sizes[2]; target_ulong sram_size; long bios_size; //int phy_addr = 0; @@ -390,7 +389,7 @@ struct taihu_cpld_t { uint8_t reg1; }; -static uint32_t taihu_cpld_readb (void *opaque, target_phys_addr_t addr) +static uint32_t taihu_cpld_readb (void *opaque, hwaddr addr) { taihu_cpld_t *cpld; uint32_t ret; @@ -412,7 +411,7 @@ static uint32_t taihu_cpld_readb (void *opaque, target_phys_addr_t addr) } static void taihu_cpld_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { taihu_cpld_t *cpld; @@ -429,7 +428,7 @@ static void taihu_cpld_writeb (void *opaque, } } -static uint32_t taihu_cpld_readw (void *opaque, target_phys_addr_t addr) +static uint32_t taihu_cpld_readw (void *opaque, hwaddr addr) { uint32_t ret; @@ -440,13 +439,13 @@ static uint32_t taihu_cpld_readw (void *opaque, target_phys_addr_t addr) } static void taihu_cpld_writew (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { taihu_cpld_writeb(opaque, addr, (value >> 8) & 0xFF); taihu_cpld_writeb(opaque, addr + 1, value & 0xFF); } -static uint32_t taihu_cpld_readl (void *opaque, target_phys_addr_t addr) +static uint32_t taihu_cpld_readl (void *opaque, hwaddr addr) { uint32_t ret; @@ -459,7 +458,7 @@ static uint32_t taihu_cpld_readl (void *opaque, target_phys_addr_t addr) } static void taihu_cpld_writel (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { taihu_cpld_writel(opaque, addr, (value >> 24) & 0xFF); taihu_cpld_writel(opaque, addr + 1, (value >> 16) & 0xFF); @@ -484,7 +483,7 @@ static void taihu_cpld_reset (void *opaque) cpld->reg1 = 0x80; } -static void taihu_cpld_init (MemoryRegion *sysmem, uint32_t base) +static void taihu_cpld_init(MemoryRegion *sysmem, uint32_t base) { taihu_cpld_t *cpld; MemoryRegion *cpld_memory = g_new(MemoryRegion, 1); @@ -495,19 +494,17 @@ static void taihu_cpld_init (MemoryRegion *sysmem, uint32_t base) qemu_register_reset(&taihu_cpld_reset, cpld); } -static void taihu_405ep_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void taihu_405ep_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *kernel_filename = args->kernel_filename; + const char *initrd_filename = args->initrd_filename; char *filename; qemu_irq *pic; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *bios; MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories)); - target_phys_addr_t ram_bases[2], ram_sizes[2]; + hwaddr ram_bases[2], ram_sizes[2]; long bios_size; target_ulong kernel_base, initrd_base; long kernel_size, initrd_size; diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 89e5013b57..c96d103d1c 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -24,11 +24,11 @@ #include "hw.h" #include "ppc.h" #include "ppc405.h" -#include "pc.h" -#include "qemu-timer.h" -#include "sysemu.h" -#include "qemu-log.h" -#include "exec-memory.h" +#include "serial.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" +#include "qemu/log.h" +#include "exec/address-spaces.h" #define DEBUG_OPBA #define DEBUG_SDRAM @@ -191,7 +191,8 @@ enum { typedef struct ppc4xx_pob_t ppc4xx_pob_t; struct ppc4xx_pob_t { uint32_t bear; - uint32_t besr[2]; + uint32_t besr0; + uint32_t besr1; }; static uint32_t dcr_read_pob (void *opaque, int dcrn) @@ -205,8 +206,10 @@ static uint32_t dcr_read_pob (void *opaque, int dcrn) ret = pob->bear; break; case POB0_BESR0: + ret = pob->besr0; + break; case POB0_BESR1: - ret = pob->besr[dcrn - POB0_BESR0]; + ret = pob->besr1; break; default: /* Avoid gcc warning */ @@ -227,9 +230,12 @@ static void dcr_write_pob (void *opaque, int dcrn, uint32_t val) /* Read only */ break; case POB0_BESR0: + /* Write-clear */ + pob->besr0 &= ~val; + break; case POB0_BESR1: /* Write-clear */ - pob->besr[dcrn - POB0_BESR0] &= ~val; + pob->besr1 &= ~val; break; } } @@ -241,8 +247,8 @@ static void ppc4xx_pob_reset (void *opaque) pob = opaque; /* No error */ pob->bear = 0x00000000; - pob->besr[0] = 0x0000000; - pob->besr[1] = 0x0000000; + pob->besr0 = 0x0000000; + pob->besr1 = 0x0000000; } static void ppc4xx_pob_init(CPUPPCState *env) @@ -265,7 +271,7 @@ struct ppc4xx_opba_t { uint8_t pr; }; -static uint32_t opba_readb (void *opaque, target_phys_addr_t addr) +static uint32_t opba_readb (void *opaque, hwaddr addr) { ppc4xx_opba_t *opba; uint32_t ret; @@ -290,7 +296,7 @@ static uint32_t opba_readb (void *opaque, target_phys_addr_t addr) } static void opba_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { ppc4xx_opba_t *opba; @@ -311,7 +317,7 @@ static void opba_writeb (void *opaque, } } -static uint32_t opba_readw (void *opaque, target_phys_addr_t addr) +static uint32_t opba_readw (void *opaque, hwaddr addr) { uint32_t ret; @@ -325,7 +331,7 @@ static uint32_t opba_readw (void *opaque, target_phys_addr_t addr) } static void opba_writew (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { #ifdef DEBUG_OPBA printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, @@ -335,7 +341,7 @@ static void opba_writew (void *opaque, opba_writeb(opaque, addr + 1, value); } -static uint32_t opba_readl (void *opaque, target_phys_addr_t addr) +static uint32_t opba_readl (void *opaque, hwaddr addr) { uint32_t ret; @@ -349,7 +355,7 @@ static uint32_t opba_readl (void *opaque, target_phys_addr_t addr) } static void opba_writel (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { #ifdef DEBUG_OPBA printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, @@ -376,7 +382,7 @@ static void ppc4xx_opba_reset (void *opaque) opba->pr = 0x11; } -static void ppc4xx_opba_init(target_phys_addr_t base) +static void ppc4xx_opba_init(hwaddr base) { ppc4xx_opba_t *opba; @@ -732,7 +738,7 @@ struct ppc405_gpio_t { uint32_t isr1l; }; -static uint32_t ppc405_gpio_readb (void *opaque, target_phys_addr_t addr) +static uint32_t ppc405_gpio_readb (void *opaque, hwaddr addr) { #ifdef DEBUG_GPIO printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); @@ -742,7 +748,7 @@ static uint32_t ppc405_gpio_readb (void *opaque, target_phys_addr_t addr) } static void ppc405_gpio_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { #ifdef DEBUG_GPIO printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, @@ -750,7 +756,7 @@ static void ppc405_gpio_writeb (void *opaque, #endif } -static uint32_t ppc405_gpio_readw (void *opaque, target_phys_addr_t addr) +static uint32_t ppc405_gpio_readw (void *opaque, hwaddr addr) { #ifdef DEBUG_GPIO printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); @@ -760,7 +766,7 @@ static uint32_t ppc405_gpio_readw (void *opaque, target_phys_addr_t addr) } static void ppc405_gpio_writew (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { #ifdef DEBUG_GPIO printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, @@ -768,7 +774,7 @@ static void ppc405_gpio_writew (void *opaque, #endif } -static uint32_t ppc405_gpio_readl (void *opaque, target_phys_addr_t addr) +static uint32_t ppc405_gpio_readl (void *opaque, hwaddr addr) { #ifdef DEBUG_GPIO printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); @@ -778,7 +784,7 @@ static uint32_t ppc405_gpio_readl (void *opaque, target_phys_addr_t addr) } static void ppc405_gpio_writel (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { #ifdef DEBUG_GPIO printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, @@ -798,7 +804,7 @@ static void ppc405_gpio_reset (void *opaque) { } -static void ppc405_gpio_init(target_phys_addr_t base) +static void ppc405_gpio_init(hwaddr base) { ppc405_gpio_t *gpio; @@ -1004,7 +1010,7 @@ struct ppc4xx_i2c_t { uint8_t directcntl; }; -static uint32_t ppc4xx_i2c_readb (void *opaque, target_phys_addr_t addr) +static uint32_t ppc4xx_i2c_readb (void *opaque, hwaddr addr) { ppc4xx_i2c_t *i2c; uint32_t ret; @@ -1072,7 +1078,7 @@ static uint32_t ppc4xx_i2c_readb (void *opaque, target_phys_addr_t addr) } static void ppc4xx_i2c_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { ppc4xx_i2c_t *i2c; @@ -1131,7 +1137,7 @@ static void ppc4xx_i2c_writeb (void *opaque, } } -static uint32_t ppc4xx_i2c_readw (void *opaque, target_phys_addr_t addr) +static uint32_t ppc4xx_i2c_readw (void *opaque, hwaddr addr) { uint32_t ret; @@ -1145,7 +1151,7 @@ static uint32_t ppc4xx_i2c_readw (void *opaque, target_phys_addr_t addr) } static void ppc4xx_i2c_writew (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { #ifdef DEBUG_I2C printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, @@ -1155,7 +1161,7 @@ static void ppc4xx_i2c_writew (void *opaque, ppc4xx_i2c_writeb(opaque, addr + 1, value); } -static uint32_t ppc4xx_i2c_readl (void *opaque, target_phys_addr_t addr) +static uint32_t ppc4xx_i2c_readl (void *opaque, hwaddr addr) { uint32_t ret; @@ -1171,7 +1177,7 @@ static uint32_t ppc4xx_i2c_readl (void *opaque, target_phys_addr_t addr) } static void ppc4xx_i2c_writel (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { #ifdef DEBUG_I2C printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, @@ -1207,7 +1213,7 @@ static void ppc4xx_i2c_reset (void *opaque) i2c->directcntl = 0x0F; } -static void ppc405_i2c_init(target_phys_addr_t base, qemu_irq irq) +static void ppc405_i2c_init(hwaddr base, qemu_irq irq) { ppc4xx_i2c_t *i2c; @@ -1239,7 +1245,7 @@ struct ppc4xx_gpt_t { uint32_t mask[5]; }; -static uint32_t ppc4xx_gpt_readb (void *opaque, target_phys_addr_t addr) +static uint32_t ppc4xx_gpt_readb (void *opaque, hwaddr addr) { #ifdef DEBUG_GPT printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); @@ -1249,7 +1255,7 @@ static uint32_t ppc4xx_gpt_readb (void *opaque, target_phys_addr_t addr) } static void ppc4xx_gpt_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { #ifdef DEBUG_I2C printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, @@ -1258,7 +1264,7 @@ static void ppc4xx_gpt_writeb (void *opaque, /* XXX: generate a bus fault */ } -static uint32_t ppc4xx_gpt_readw (void *opaque, target_phys_addr_t addr) +static uint32_t ppc4xx_gpt_readw (void *opaque, hwaddr addr) { #ifdef DEBUG_GPT printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); @@ -1268,7 +1274,7 @@ static uint32_t ppc4xx_gpt_readw (void *opaque, target_phys_addr_t addr) } static void ppc4xx_gpt_writew (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { #ifdef DEBUG_I2C printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, @@ -1329,7 +1335,7 @@ static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt) /* XXX: TODO */ } -static uint32_t ppc4xx_gpt_readl (void *opaque, target_phys_addr_t addr) +static uint32_t ppc4xx_gpt_readl (void *opaque, hwaddr addr) { ppc4xx_gpt_t *gpt; uint32_t ret; @@ -1385,7 +1391,7 @@ static uint32_t ppc4xx_gpt_readl (void *opaque, target_phys_addr_t addr) } static void ppc4xx_gpt_writel (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { ppc4xx_gpt_t *gpt; int idx; @@ -1482,7 +1488,7 @@ static void ppc4xx_gpt_reset (void *opaque) } } -static void ppc4xx_gpt_init(target_phys_addr_t base, qemu_irq irqs[5]) +static void ppc4xx_gpt_init(hwaddr base, qemu_irq irqs[5]) { ppc4xx_gpt_t *gpt; int i; @@ -2098,19 +2104,21 @@ static void ppc405cr_cpc_init (CPUPPCState *env, clk_setup_t clk_setup[7], CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem, MemoryRegion ram_memories[4], - target_phys_addr_t ram_bases[4], - target_phys_addr_t ram_sizes[4], + hwaddr ram_bases[4], + hwaddr ram_sizes[4], uint32_t sysclk, qemu_irq **picp, int do_init) { clk_setup_t clk_setup[PPC405CR_CLK_NB]; qemu_irq dma_irqs[4]; + PowerPCCPU *cpu; CPUPPCState *env; qemu_irq *pic, *irqs; memset(clk_setup, 0, sizeof(clk_setup)); - env = ppc4xx_init("405cr", &clk_setup[PPC405CR_CPU_CLK], + cpu = ppc4xx_init("405cr", &clk_setup[PPC405CR_CPU_CLK], &clk_setup[PPC405CR_TMR_CLK], sysclk); + env = &cpu->env; /* Memory mapped devices registers */ /* PLB arbitrer */ ppc4xx_plb_init(env); @@ -2447,20 +2455,22 @@ static void ppc405ep_cpc_init (CPUPPCState *env, clk_setup_t clk_setup[8], CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem, MemoryRegion ram_memories[2], - target_phys_addr_t ram_bases[2], - target_phys_addr_t ram_sizes[2], + hwaddr ram_bases[2], + hwaddr ram_sizes[2], uint32_t sysclk, qemu_irq **picp, int do_init) { clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup; qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4]; + PowerPCCPU *cpu; CPUPPCState *env; qemu_irq *pic, *irqs; memset(clk_setup, 0, sizeof(clk_setup)); /* init CPUs */ - env = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK], + cpu = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK], &tlb_clk_setup, sysclk); + env = &cpu->env; clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb; clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque; /* Internal devices init */ @@ -2472,7 +2482,7 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem, /* OBP arbitrer */ ppc4xx_opba_init(0xef600600); /* Initialize timers */ - ppc_booke_timers_init(env, sysclk, 0); + ppc_booke_timers_init(cpu, sysclk, 0); /* Universal interrupt controller */ irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); irqs[PPCUIC_OUTPUT_INT] = diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index 0dd4dab318..d1e4f0e811 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -13,20 +13,20 @@ #include "config.h" #include "qemu-common.h" -#include "net.h" +#include "net/net.h" #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "boards.h" -#include "kvm.h" +#include "sysemu/kvm.h" #include "kvm_ppc.h" -#include "device_tree.h" +#include "sysemu/device_tree.h" #include "loader.h" #include "elf.h" -#include "exec-memory.h" -#include "pc.h" +#include "exec/address-spaces.h" +#include "serial.h" #include "ppc.h" #include "ppc405.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "sysbus.h" #define BINARY_DEVICE_TREE_FILE "bamboo.dtb" @@ -49,17 +49,17 @@ static const unsigned int ppc440ep_sdram_bank_sizes[] = { 256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0 }; -static target_phys_addr_t entry; +static hwaddr entry; -static int bamboo_load_device_tree(target_phys_addr_t addr, +static int bamboo_load_device_tree(hwaddr addr, uint32_t ramsize, - target_phys_addr_t initrd_base, - target_phys_addr_t initrd_size, + hwaddr initrd_base, + hwaddr initrd_size, const char *kernel_cmdline) { int ret = -1; #ifdef CONFIG_FDT - uint32_t mem_reg_property[] = { 0, 0, ramsize }; + uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) }; char *filename; int fdt_size; void *fdt; @@ -123,7 +123,7 @@ out: /* Create reset TLB entries for BookE, spanning the 32bit addr space. */ static void mmubooke_create_initial_mapping(CPUPPCState *env, target_ulong va, - target_phys_addr_t pa) + hwaddr pa) { ppcemb_tlb_t *tlb = &env->tlb.tlbe[0]; @@ -157,19 +157,19 @@ static void main_cpu_reset(void *opaque) mmubooke_create_initial_mapping(env, 0, 0); } -static void bamboo_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void bamboo_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 }; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram_memories = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories)); - target_phys_addr_t ram_bases[PPC440EP_SDRAM_NR_BANKS]; - target_phys_addr_t ram_sizes[PPC440EP_SDRAM_NR_BANKS]; + hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS]; + hwaddr ram_sizes[PPC440EP_SDRAM_NR_BANKS]; qemu_irq *pic; qemu_irq *irqs; PCIBus *pcibus; @@ -177,7 +177,7 @@ static void bamboo_init(ram_addr_t ram_size, CPUPPCState *env; uint64_t elf_entry; uint64_t elf_lowaddr; - target_phys_addr_t loadaddr = 0; + hwaddr loadaddr = 0; target_long initrd_size = 0; DeviceState *dev; int success; @@ -195,7 +195,7 @@ static void bamboo_init(ram_addr_t ram_size, env = &cpu->env; qemu_register_reset(main_cpu_reset, cpu); - ppc_booke_timers_init(env, 400000000, 0); + ppc_booke_timers_init(cpu, 400000000, 0); ppc_dcr_init(env, NULL, NULL); /* interrupt controller */ @@ -216,7 +216,8 @@ static void bamboo_init(ram_addr_t ram_size, ram_bases, ram_sizes, 1); /* PCI */ - dev = sysbus_create_varargs("ppc4xx-pcihost", PPC440EP_PCI_CONFIG, + dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE, + PPC440EP_PCI_CONFIG, pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]], pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]], NULL); diff --git a/hw/ppc4xx.h b/hw/ppc4xx.h index b511020aeb..59dba9e292 100644 --- a/hw/ppc4xx.h +++ b/hw/ppc4xx.h @@ -25,12 +25,12 @@ #if !defined(PPC_4XX_H) #define PPC_4XX_H -#include "pci.h" +#include "pci/pci.h" /* PowerPC 4xx core initialization */ -CPUPPCState *ppc4xx_init (const char *cpu_model, - clk_setup_t *cpu_clk, clk_setup_t *tb_clk, - uint32_t sysclk); +PowerPCCPU *ppc4xx_init(const char *cpu_model, + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, + uint32_t sysclk); /* PowerPC 4xx universal interrupt controller */ enum { @@ -43,20 +43,22 @@ qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs, ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks, MemoryRegion ram_memories[], - target_phys_addr_t ram_bases[], - target_phys_addr_t ram_sizes[], + hwaddr ram_bases[], + hwaddr ram_sizes[], const unsigned int sdram_bank_sizes[]); void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, MemoryRegion ram_memories[], - target_phys_addr_t *ram_bases, - target_phys_addr_t *ram_sizes, + hwaddr *ram_bases, + hwaddr *ram_sizes, int do_init); +#define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost" + PCIBus *ppc4xx_pci_init(CPUPPCState *env, qemu_irq pci_irqs[4], - target_phys_addr_t config_space, - target_phys_addr_t int_ack, - target_phys_addr_t special_cycle, - target_phys_addr_t registers); + hwaddr config_space, + hwaddr int_ack, + hwaddr special_cycle, + hwaddr registers); #endif /* !defined(PPC_4XX_H) */ diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index 41163e607d..5e491bc0b4 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -24,8 +24,8 @@ #include "hw.h" #include "ppc.h" #include "ppc4xx.h" -#include "qemu-log.h" -#include "exec-memory.h" +#include "qemu/log.h" +#include "exec/address-spaces.h" //#define DEBUG_MMIO //#define DEBUG_UNASSIGNED @@ -47,9 +47,9 @@ static void ppc4xx_reset(void *opaque) /*****************************************************************************/ /* Generic PowerPC 4xx processor instantiation */ -CPUPPCState *ppc4xx_init (const char *cpu_model, - clk_setup_t *cpu_clk, clk_setup_t *tb_clk, - uint32_t sysclk) +PowerPCCPU *ppc4xx_init(const char *cpu_model, + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, + uint32_t sysclk) { PowerPCCPU *cpu; CPUPPCState *env; @@ -72,7 +72,7 @@ CPUPPCState *ppc4xx_init (const char *cpu_model, /* Register qemu callbacks */ qemu_register_reset(ppc4xx_reset, cpu); - return env; + return cpu; } /*****************************************************************************/ @@ -326,8 +326,8 @@ struct ppc4xx_sdram_t { int nbanks; MemoryRegion containers[4]; /* used for clipping */ MemoryRegion *ram_memories; - target_phys_addr_t ram_bases[4]; - target_phys_addr_t ram_sizes[4]; + hwaddr ram_bases[4]; + hwaddr ram_sizes[4]; uint32_t besr0; uint32_t besr1; uint32_t bear; @@ -348,11 +348,11 @@ enum { }; /* XXX: TOFIX: some patches have made this code become inconsistent: - * there are type inconsistencies, mixing target_phys_addr_t, target_ulong + * there are type inconsistencies, mixing hwaddr, target_ulong * and uint32_t */ -static uint32_t sdram_bcr (target_phys_addr_t ram_base, - target_phys_addr_t ram_size) +static uint32_t sdram_bcr (hwaddr ram_base, + hwaddr ram_size) { uint32_t bcr; @@ -389,7 +389,7 @@ static uint32_t sdram_bcr (target_phys_addr_t ram_base, return bcr; } -static inline target_phys_addr_t sdram_base(uint32_t bcr) +static inline hwaddr sdram_base(uint32_t bcr) { return bcr & 0xFF800000; } @@ -646,8 +646,8 @@ static void sdram_reset (void *opaque) void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, MemoryRegion *ram_memories, - target_phys_addr_t *ram_bases, - target_phys_addr_t *ram_sizes, + hwaddr *ram_bases, + hwaddr *ram_sizes, int do_init) { ppc4xx_sdram_t *sdram; @@ -656,12 +656,12 @@ void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, sdram->irq = irq; sdram->nbanks = nbanks; sdram->ram_memories = ram_memories; - memset(sdram->ram_bases, 0, 4 * sizeof(target_phys_addr_t)); + memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr)); memcpy(sdram->ram_bases, ram_bases, - nbanks * sizeof(target_phys_addr_t)); - memset(sdram->ram_sizes, 0, 4 * sizeof(target_phys_addr_t)); + nbanks * sizeof(hwaddr)); + memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr)); memcpy(sdram->ram_sizes, ram_sizes, - nbanks * sizeof(target_phys_addr_t)); + nbanks * sizeof(hwaddr)); qemu_register_reset(&sdram_reset, sdram); ppc_dcr_register(env, SDRAM0_CFGADDR, sdram, &dcr_read_sdram, &dcr_write_sdram); @@ -680,8 +680,8 @@ void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, * sizes varies by SoC. */ ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks, MemoryRegion ram_memories[], - target_phys_addr_t ram_bases[], - target_phys_addr_t ram_sizes[], + hwaddr ram_bases[], + hwaddr ram_sizes[], const unsigned int sdram_bank_sizes[]) { ram_addr_t size_left = ram_size; diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c index 203c3cdc47..ba2d669b83 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -22,9 +22,9 @@ #include "hw.h" #include "ppc.h" #include "ppc4xx.h" -#include "pci.h" -#include "pci_host.h" -#include "exec-memory.h" +#include "pci/pci.h" +#include "pci/pci_host.h" +#include "exec/address-spaces.h" #undef DEBUG #ifdef DEBUG @@ -45,11 +45,14 @@ struct PCITargetMap { uint32_t la; }; +#define PPC4xx_PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(PPC4xxPCIState, (obj), TYPE_PPC4xx_PCI_HOST_BRIDGE) + #define PPC4xx_PCI_NR_PMMS 3 #define PPC4xx_PCI_NR_PTMS 2 struct PPC4xxPCIState { - PCIHostState pci_state; + PCIHostState parent_obj; struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS]; struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS]; @@ -89,20 +92,22 @@ typedef struct PPC4xxPCIState PPC4xxPCIState; #define PCI_ALL_SIZE (PCI_REG_BASE + PCI_REG_SIZE) -static uint64_t pci4xx_cfgaddr_read(void *opaque, target_phys_addr_t addr, +static uint64_t pci4xx_cfgaddr_read(void *opaque, hwaddr addr, unsigned size) { PPC4xxPCIState *ppc4xx_pci = opaque; + PCIHostState *phb = PCI_HOST_BRIDGE(ppc4xx_pci); - return ppc4xx_pci->pci_state.config_reg; + return phb->config_reg; } -static void pci4xx_cfgaddr_write(void *opaque, target_phys_addr_t addr, +static void pci4xx_cfgaddr_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { PPC4xxPCIState *ppc4xx_pci = opaque; + PCIHostState *phb = PCI_HOST_BRIDGE(ppc4xx_pci); - ppc4xx_pci->pci_state.config_reg = value & ~0x3; + phb->config_reg = value & ~0x3; } static const MemoryRegionOps pci4xx_cfgaddr_ops = { @@ -111,7 +116,7 @@ static const MemoryRegionOps pci4xx_cfgaddr_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static void ppc4xx_pci_reg_write4(void *opaque, target_phys_addr_t offset, +static void ppc4xx_pci_reg_write4(void *opaque, hwaddr offset, uint64_t value, unsigned size) { struct PPC4xxPCIState *pci = opaque; @@ -179,7 +184,7 @@ static void ppc4xx_pci_reg_write4(void *opaque, target_phys_addr_t offset, } } -static uint64_t ppc4xx_pci_reg_read4(void *opaque, target_phys_addr_t offset, +static uint64_t ppc4xx_pci_reg_read4(void *opaque, hwaddr offset, unsigned size) { struct PPC4xxPCIState *pci = opaque; @@ -335,17 +340,17 @@ static int ppc4xx_pcihost_initfn(SysBusDevice *dev) PCIBus *b; int i; - h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev)); - s = DO_UPCAST(PPC4xxPCIState, pci_state, h); + h = PCI_HOST_BRIDGE(dev); + s = PPC4xx_PCI_HOST_BRIDGE(dev); for (i = 0; i < ARRAY_SIZE(s->irq); i++) { sysbus_init_irq(dev, &s->irq[i]); } - b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, ppc4xx_pci_set_irq, + b = pci_register_bus(DEVICE(dev), NULL, ppc4xx_pci_set_irq, ppc4xx_pci_map_irq, s->irq, get_system_memory(), get_system_io(), 0, 4); - s->pci_state.bus = b; + h->bus = b; pci_create_simple(b, 0, "ppc4xx-host-bridge"); @@ -377,7 +382,7 @@ static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_OTHER; } -static TypeInfo ppc4xx_host_bridge_info = { +static const TypeInfo ppc4xx_host_bridge_info = { .name = "ppc4xx-host-bridge", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), @@ -393,9 +398,9 @@ static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_ppc4xx_pci; } -static TypeInfo ppc4xx_pcihost_info = { - .name = "ppc4xx-pcihost", - .parent = TYPE_SYS_BUS_DEVICE, +static const TypeInfo ppc4xx_pcihost_info = { + .name = TYPE_PPC4xx_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(PPC4xxPCIState), .class_init = ppc4xx_pcihost_class_init, }; diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c index d51e7fad67..4483b8d292 100644 --- a/hw/ppc_booke.c +++ b/hw/ppc_booke.c @@ -23,10 +23,10 @@ */ #include "hw.h" #include "ppc.h" -#include "qemu-timer.h" -#include "sysemu.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" #include "nvram.h" -#include "qemu-log.h" +#include "qemu/log.h" #include "loader.h" @@ -71,17 +71,19 @@ struct booke_timer_t { uint32_t flags; }; -static void booke_update_irq(CPUPPCState *env) +static void booke_update_irq(PowerPCCPU *cpu) { - ppc_set_irq(env, PPC_INTERRUPT_DECR, + CPUPPCState *env = &cpu->env; + + ppc_set_irq(cpu, PPC_INTERRUPT_DECR, (env->spr[SPR_BOOKE_TSR] & TSR_DIS && env->spr[SPR_BOOKE_TCR] & TCR_DIE)); - ppc_set_irq(env, PPC_INTERRUPT_WDT, + ppc_set_irq(cpu, PPC_INTERRUPT_WDT, (env->spr[SPR_BOOKE_TSR] & TSR_WIS && env->spr[SPR_BOOKE_TCR] & TCR_WIE)); - ppc_set_irq(env, PPC_INTERRUPT_FIT, + ppc_set_irq(cpu, PPC_INTERRUPT_FIT, (env->spr[SPR_BOOKE_TSR] & TSR_FIS && env->spr[SPR_BOOKE_TCR] & TCR_FIE)); } @@ -153,10 +155,11 @@ static void booke_update_fixed_timer(CPUPPCState *env, static void booke_decr_cb(void *opaque) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; env->spr[SPR_BOOKE_TSR] |= TSR_DIS; - booke_update_irq(env); + booke_update_irq(cpu); if (env->spr[SPR_BOOKE_TCR] & TCR_ARE) { /* Auto Reload */ @@ -166,16 +169,16 @@ static void booke_decr_cb(void *opaque) static void booke_fit_cb(void *opaque) { - CPUPPCState *env; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; ppc_tb_t *tb_env; booke_timer_t *booke_timer; - env = opaque; tb_env = env->tb_env; booke_timer = tb_env->opaque; env->spr[SPR_BOOKE_TSR] |= TSR_FIS; - booke_update_irq(env); + booke_update_irq(cpu); booke_update_fixed_timer(env, booke_get_fit_target(env, tb_env), @@ -185,17 +188,17 @@ static void booke_fit_cb(void *opaque) static void booke_wdt_cb(void *opaque) { - CPUPPCState *env; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; ppc_tb_t *tb_env; booke_timer_t *booke_timer; - env = opaque; tb_env = env->tb_env; booke_timer = tb_env->opaque; /* TODO: There's lots of complicated stuff to do here */ - booke_update_irq(env); + booke_update_irq(cpu); booke_update_fixed_timer(env, booke_get_wdt_target(env, tb_env), @@ -205,19 +208,22 @@ static void booke_wdt_cb(void *opaque) void store_booke_tsr(CPUPPCState *env, target_ulong val) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + env->spr[SPR_BOOKE_TSR] &= ~val; - booke_update_irq(env); + booke_update_irq(cpu); } void store_booke_tcr(CPUPPCState *env, target_ulong val) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); ppc_tb_t *tb_env = env->tb_env; booke_timer_t *booke_timer = tb_env->opaque; tb_env = env->tb_env; env->spr[SPR_BOOKE_TCR] = val; - booke_update_irq(env); + booke_update_irq(cpu); booke_update_fixed_timer(env, booke_get_fit_target(env, tb_env), @@ -231,7 +237,7 @@ void store_booke_tcr(CPUPPCState *env, target_ulong val) } -void ppc_booke_timers_init(CPUPPCState *env, uint32_t freq, uint32_t flags) +void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) { ppc_tb_t *tb_env; booke_timer_t *booke_timer; @@ -239,16 +245,16 @@ void ppc_booke_timers_init(CPUPPCState *env, uint32_t freq, uint32_t flags) tb_env = g_malloc0(sizeof(ppc_tb_t)); booke_timer = g_malloc0(sizeof(booke_timer_t)); - env->tb_env = tb_env; + cpu->env.tb_env = tb_env; tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED; tb_env->tb_freq = freq; tb_env->decr_freq = freq; tb_env->opaque = booke_timer; - tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &booke_decr_cb, env); + tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &booke_decr_cb, cpu); booke_timer->fit_timer = - qemu_new_timer_ns(vm_clock, &booke_fit_cb, env); + qemu_new_timer_ns(vm_clock, &booke_fit_cb, cpu); booke_timer->wdt_timer = - qemu_new_timer_ns(vm_clock, &booke_wdt_cb, env); + qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu); } diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h index af75e45cc2..89c7d66386 100644 --- a/hw/ppc_mac.h +++ b/hw/ppc_mac.h @@ -25,7 +25,7 @@ #if !defined(__PPC_MAC_H__) #define __PPC_MAC_H__ -#include "memory.h" +#include "exec/memory.h" /* SMP is not enabled, for now */ #define MAX_CPUS 1 @@ -55,6 +55,7 @@ qemu_irq *heathrow_pic_init(MemoryRegion **pmem, int nb_cpus, qemu_irq **irqs); /* Grackle PCI */ +#define TYPE_GRACKLE_PCI_HOST_BRIDGE "grackle-pcihost" PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic, MemoryRegion *address_space_mem, MemoryRegion *address_space_io); @@ -70,10 +71,10 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic, /* Mac NVRAM */ typedef struct MacIONVRAMState MacIONVRAMState; -MacIONVRAMState *macio_nvram_init (target_phys_addr_t size, +MacIONVRAMState *macio_nvram_init (hwaddr size, unsigned int it_shift); void macio_nvram_setup_bar(MacIONVRAMState *s, MemoryRegion *bar, - target_phys_addr_t mem_base); + hwaddr mem_base); void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len); uint32_t macio_nvram_read (void *opaque, uint32_t addr); void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val); diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index 4e2a6e691b..fabcc08b40 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -52,10 +52,9 @@ #include "adb.h" #include "mac_dbdma.h" #include "nvram.h" -#include "pc.h" -#include "pci.h" -#include "net.h" -#include "sysemu.h" +#include "pci/pci.h" +#include "net/net.h" +#include "sysemu/sysemu.h" #include "boards.h" #include "fw_cfg.h" #include "escc.h" @@ -63,11 +62,12 @@ #include "ide.h" #include "loader.h" #include "elf.h" -#include "kvm.h" +#include "sysemu/kvm.h" #include "kvm_ppc.h" #include "hw/usb.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" +#include "sysbus.h" #define MAX_IDE_BUS 2 #define CFG_ADDR 0xf0000510 @@ -83,13 +83,13 @@ #endif /* UniN device */ -static void unin_write(void *opaque, target_phys_addr_t addr, uint64_t value, +static void unin_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { UNIN_DPRINTF("write addr " TARGET_FMT_plx " val %"PRIx64"\n", addr, value); } -static uint64_t unin_read(void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t unin_read(void *opaque, hwaddr addr, unsigned size) { uint32_t value; @@ -116,7 +116,7 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR; } -static target_phys_addr_t round_page(target_phys_addr_t addr) +static hwaddr round_page(hwaddr addr) { return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; } @@ -129,21 +129,22 @@ static void ppc_core99_reset(void *opaque) } /* PowerPC Mac99 hardware initialisation */ -static void ppc_core99_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void ppc_core99_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; char *filename; qemu_irq *pic, **openpic_irqs; MemoryRegion *unin_memory = g_new(MemoryRegion, 1); - int linux_boot, i; + int linux_boot, i, j, k; MemoryRegion *ram = g_new(MemoryRegion, 1), *bios = g_new(MemoryRegion, 1); - target_phys_addr_t kernel_base, initrd_base, cmdline_base = 0; + hwaddr kernel_base, initrd_base, cmdline_base = 0; long kernel_size, initrd_size; PCIBus *pci_bus; MacIONVRAMState *nvr; @@ -156,6 +157,8 @@ static void ppc_core99_init (ram_addr_t ram_size, void *fw_cfg; void *dbdma; int machine_arch; + SysBusDevice *s; + DeviceState *dev; linux_boot = (kernel_filename != NULL); @@ -320,7 +323,25 @@ static void ppc_core99_init (ram_addr_t ram_size, exit(1); } } - pic = openpic_init(&pic_mem, smp_cpus, openpic_irqs, NULL); + + pic = g_new(qemu_irq, 64); + + dev = qdev_create(NULL, "openpic"); + qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_RAVEN); + qdev_init_nofail(dev); + s = sysbus_from_qdev(dev); + pic_mem = s->mmio[0].memory; + k = 0; + for (i = 0; i < smp_cpus; i++) { + for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { + sysbus_connect_irq(s, k++, openpic_irqs[i][j]); + } + } + + for (i = 0; i < 64; i++) { + pic[i] = qdev_get_gpio_in(dev, i); + } + if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) { /* 970 gets a U3 bus */ pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io()); @@ -348,10 +369,6 @@ static void ppc_core99_init (ram_addr_t ram_size, ide_mem[1] = pmac_ide_init(hd, pic[0x0d], dbdma, 0x16, pic[0x02]); ide_mem[2] = pmac_ide_init(&hd[MAX_IDE_DEVS], pic[0x0e], dbdma, 0x1a, pic[0x02]); - /* cuda also initialize ADB */ - if (machine_arch == ARCH_MAC99_U3) { - usb_enabled = 1; - } cuda_init(&cuda_mem, pic[0x19]); adb_kbd_init(&adb_bus); @@ -360,15 +377,14 @@ static void ppc_core99_init (ram_addr_t ram_size, macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem, dbdma_mem, cuda_mem, NULL, 3, ide_mem, escc_bar); - if (usb_enabled) { + if (usb_enabled(machine_arch == ARCH_MAC99_U3)) { pci_create_simple(pci_bus, -1, "pci-ohci"); - } - - /* 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"); + /* 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) diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index f2c6908534..fff5129ca9 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -29,21 +29,20 @@ #include "adb.h" #include "mac_dbdma.h" #include "nvram.h" -#include "pc.h" -#include "sysemu.h" -#include "net.h" +#include "sysemu/sysemu.h" +#include "net/net.h" #include "isa.h" -#include "pci.h" +#include "pci/pci.h" #include "boards.h" #include "fw_cfg.h" #include "escc.h" #include "ide.h" #include "loader.h" #include "elf.h" -#include "kvm.h" +#include "sysemu/kvm.h" #include "kvm_ppc.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" #define MAX_IDE_BUS 2 #define CFG_ADDR 0xf0000510 @@ -60,7 +59,7 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR; } -static target_phys_addr_t round_page(target_phys_addr_t addr) +static hwaddr round_page(hwaddr addr) { return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; } @@ -72,13 +71,14 @@ static void ppc_heathrow_reset(void *opaque) cpu_reset(CPU(cpu)); } -static void ppc_heathrow_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void ppc_heathrow_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; MemoryRegion *sysmem = get_system_memory(); PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; @@ -286,7 +286,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem, dbdma_mem, cuda_mem, nvr, 2, ide_mem, escc_bar); - if (usb_enabled) { + if (usb_enabled(false)) { pci_create_simple(pci_bus, -1, "pci-ohci"); } diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 59def908fd..417583a96d 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -24,22 +24,23 @@ #include "hw.h" #include "nvram.h" #include "pc.h" +#include "serial.h" #include "fdc.h" -#include "net.h" -#include "sysemu.h" +#include "net/net.h" +#include "sysemu/sysemu.h" #include "isa.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" #include "ppc.h" #include "boards.h" -#include "qemu-log.h" +#include "qemu/log.h" #include "ide.h" #include "loader.h" #include "mc146818rtc.h" #include "pc87312.h" -#include "blockdev.h" -#include "arch_init.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "sysemu/arch_init.h" +#include "exec/address-spaces.h" //#define HARD_DEBUG_PPC_IO //#define DEBUG_PPC_IO @@ -115,27 +116,27 @@ static struct { } XCSR; static void PPC_XCSR_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr, value); } static void PPC_XCSR_writew (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr, value); } static void PPC_XCSR_writel (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr, value); } -static uint32_t PPC_XCSR_readb (void *opaque, target_phys_addr_t addr) +static uint32_t PPC_XCSR_readb (void *opaque, hwaddr addr) { uint32_t retval = 0; @@ -145,7 +146,7 @@ static uint32_t PPC_XCSR_readb (void *opaque, target_phys_addr_t addr) return retval; } -static uint32_t PPC_XCSR_readw (void *opaque, target_phys_addr_t addr) +static uint32_t PPC_XCSR_readw (void *opaque, hwaddr addr) { uint32_t retval = 0; @@ -155,7 +156,7 @@ static uint32_t PPC_XCSR_readw (void *opaque, target_phys_addr_t addr) return retval; } -static uint32_t PPC_XCSR_readl (void *opaque, target_phys_addr_t addr) +static uint32_t PPC_XCSR_readl (void *opaque, hwaddr addr) { uint32_t retval = 0; @@ -324,8 +325,8 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) return retval; } -static inline target_phys_addr_t prep_IO_address(sysctrl_t *sysctrl, - target_phys_addr_t addr) +static inline hwaddr prep_IO_address(sysctrl_t *sysctrl, + hwaddr addr) { if (sysctrl->contiguous_map == 0) { /* 64 KB contiguous space for IOs */ @@ -338,7 +339,7 @@ static inline target_phys_addr_t prep_IO_address(sysctrl_t *sysctrl, return addr; } -static void PPC_prep_io_writeb (void *opaque, target_phys_addr_t addr, +static void PPC_prep_io_writeb (void *opaque, hwaddr addr, uint32_t value) { sysctrl_t *sysctrl = opaque; @@ -347,7 +348,7 @@ static void PPC_prep_io_writeb (void *opaque, target_phys_addr_t addr, cpu_outb(addr, value); } -static uint32_t PPC_prep_io_readb (void *opaque, target_phys_addr_t addr) +static uint32_t PPC_prep_io_readb (void *opaque, hwaddr addr) { sysctrl_t *sysctrl = opaque; uint32_t ret; @@ -358,7 +359,7 @@ static uint32_t PPC_prep_io_readb (void *opaque, target_phys_addr_t addr) return ret; } -static void PPC_prep_io_writew (void *opaque, target_phys_addr_t addr, +static void PPC_prep_io_writew (void *opaque, hwaddr addr, uint32_t value) { sysctrl_t *sysctrl = opaque; @@ -368,7 +369,7 @@ static void PPC_prep_io_writew (void *opaque, target_phys_addr_t addr, cpu_outw(addr, value); } -static uint32_t PPC_prep_io_readw (void *opaque, target_phys_addr_t addr) +static uint32_t PPC_prep_io_readw (void *opaque, hwaddr addr) { sysctrl_t *sysctrl = opaque; uint32_t ret; @@ -380,7 +381,7 @@ static uint32_t PPC_prep_io_readw (void *opaque, target_phys_addr_t addr) return ret; } -static void PPC_prep_io_writel (void *opaque, target_phys_addr_t addr, +static void PPC_prep_io_writel (void *opaque, hwaddr addr, uint32_t value) { sysctrl_t *sysctrl = opaque; @@ -390,7 +391,7 @@ static void PPC_prep_io_writel (void *opaque, target_phys_addr_t addr, cpu_outl(addr, value); } -static uint32_t PPC_prep_io_readl (void *opaque, target_phys_addr_t addr) +static uint32_t PPC_prep_io_readl (void *opaque, hwaddr addr) { sysctrl_t *sysctrl = opaque; uint32_t ret; @@ -429,13 +430,14 @@ static void ppc_prep_reset(void *opaque) } /* PowerPC PREP hardware initialisation */ -static void ppc_prep_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void ppc_prep_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; MemoryRegion *sysmem = get_system_memory(); PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; @@ -452,7 +454,6 @@ static void ppc_prep_init (ram_addr_t ram_size, uint32_t kernel_base, initrd_base; long kernel_size, initrd_size; DeviceState *dev; - SysBusDevice *sys; PCIHostState *pcihost; PCIBus *pci_bus; PCIDevice *pci; @@ -506,7 +507,7 @@ static void ppc_prep_init (ram_addr_t ram_size, bios_size = -1; } if (bios_size > 0 && bios_size <= BIOS_SIZE) { - target_phys_addr_t bios_addr; + hwaddr bios_addr; bios_size = (bios_size + 0xfff) & ~0xfff; bios_addr = (uint32_t)(-bios_size); bios_size = load_image_targphys(filename, bios_addr, bios_size); @@ -565,8 +566,7 @@ static void ppc_prep_init (ram_addr_t ram_size, } dev = qdev_create(NULL, "raven-pcihost"); - sys = sysbus_from_qdev(dev); - pcihost = DO_UPCAST(PCIHostState, busdev, sys); + pcihost = PCI_HOST_BRIDGE(dev); pcihost->address_space = get_system_memory(); object_property_add_child(qdev_get_machine(), "raven", OBJECT(dev), NULL); qdev_init_nofail(dev); @@ -636,7 +636,7 @@ static void ppc_prep_init (ram_addr_t ram_size, memory_region_add_subregion(sysmem, 0xFEFF0000, xcsr); #endif - if (usb_enabled) { + if (usb_enabled(false)) { pci_create_simple(pci_bus, -1, "pci-ohci"); } diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 0f60b24134..1e1ade3d2e 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -15,9 +15,11 @@ */ #include "hw.h" -#include "pci.h" -#include "pci_host.h" -#include "bswap.h" +#include "hw/ppc/e500-ccsr.h" +#include "pci/pci.h" +#include "pci/pci_host.h" +#include "qemu/bswap.h" +#include "ppce500_pci.h" #ifdef DEBUG_PCI #define pci_debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) @@ -31,6 +33,8 @@ #define PCIE500_ALL_SIZE 0x1000 #define PCIE500_REG_SIZE (PCIE500_ALL_SIZE - PCIE500_REG_BASE) +#define PCIE500_PCI_IOLEN 0x10000ULL + #define PPCE500_PCI_CONFIG_ADDR 0x0 #define PPCE500_PCI_CONFIG_DATA 0x4 #define PPCE500_PCI_INTACK 0x8 @@ -72,20 +76,41 @@ struct pci_inbound { uint32_t piwar; }; +#define TYPE_PPC_E500_PCI_HOST_BRIDGE "e500-pcihost" + +#define PPC_E500_PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(PPCE500PCIState, (obj), TYPE_PPC_E500_PCI_HOST_BRIDGE) + struct PPCE500PCIState { - PCIHostState pci_state; + PCIHostState parent_obj; + struct pci_outbound pob[PPCE500_PCI_NR_POBS]; struct pci_inbound pib[PPCE500_PCI_NR_PIBS]; uint32_t gasket_time; qemu_irq irq[4]; + uint32_t first_slot; /* mmio maps */ MemoryRegion container; MemoryRegion iomem; + MemoryRegion pio; }; +#define TYPE_PPC_E500_PCI_BRIDGE "e500-host-bridge" +#define PPC_E500_PCI_BRIDGE(obj) \ + OBJECT_CHECK(PPCE500PCIBridgeState, (obj), TYPE_PPC_E500_PCI_BRIDGE) + +struct PPCE500PCIBridgeState { + /*< private >*/ + PCIDevice parent; + /*< public >*/ + + MemoryRegion bar0; +}; + +typedef struct PPCE500PCIBridgeState PPCE500PCIBridgeState; typedef struct PPCE500PCIState PPCE500PCIState; -static uint64_t pci_reg_read4(void *opaque, target_phys_addr_t addr, +static uint64_t pci_reg_read4(void *opaque, hwaddr addr, unsigned size) { PPCE500PCIState *pci = opaque; @@ -154,7 +179,7 @@ static uint64_t pci_reg_read4(void *opaque, target_phys_addr_t addr, return value; } -static void pci_reg_write4(void *opaque, target_phys_addr_t addr, +static void pci_reg_write4(void *opaque, hwaddr addr, uint64_t value, unsigned size) { PPCE500PCIState *pci = opaque; @@ -229,17 +254,10 @@ static const MemoryRegionOps e500_pci_reg_ops = { static int mpc85xx_pci_map_irq(PCIDevice *pci_dev, int irq_num) { - int devno = pci_dev->devfn >> 3, ret = 0; + int devno = pci_dev->devfn >> 3; + int ret; - switch (devno) { - /* Two PCI slot */ - case 0x11: - case 0x12: - ret = (irq_num + devno - 0x10) % 4; - break; - default: - printf("Error:%s:unknown dev number\n", __func__); - } + ret = ppce500_pci_map_irq_slot(devno, irq_num); pci_debug("%s: devfn %x irq %d -> %d devno:%x\n", __func__, pci_dev->devfn, irq_num, ret, devno); @@ -299,7 +317,25 @@ static const VMStateDescription vmstate_ppce500_pci = { } }; -#include "exec-memory.h" +#include "exec/address-spaces.h" + +static int e500_pcihost_bridge_initfn(PCIDevice *d) +{ + PPCE500PCIBridgeState *b = PPC_E500_PCI_BRIDGE(d); + PPCE500CCSRState *ccsr = CCSR(container_get(qdev_get_machine(), + "/e500-ccsr")); + + pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI); + d->config[PCI_HEADER_TYPE] = + (d->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) | + PCI_HEADER_TYPE_BRIDGE; + + memory_region_init_alias(&b->bar0, "e500-pci-bar0", &ccsr->ccsr_space, + 0, int128_get64(ccsr->ccsr_space.size)); + pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &b->bar0); + + return 0; +} static int e500_pcihost_initfn(SysBusDevice *dev) { @@ -308,19 +344,20 @@ static int e500_pcihost_initfn(SysBusDevice *dev) PCIBus *b; int i; MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *address_space_io = get_system_io(); - h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev)); - s = DO_UPCAST(PPCE500PCIState, pci_state, h); + h = PCI_HOST_BRIDGE(dev); + s = PPC_E500_PCI_HOST_BRIDGE(dev); for (i = 0; i < ARRAY_SIZE(s->irq); i++) { sysbus_init_irq(dev, &s->irq[i]); } - b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, mpc85xx_pci_set_irq, + memory_region_init(&s->pio, "pci-pio", PCIE500_PCI_IOLEN); + + b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq, mpc85xx_pci_map_irq, s->irq, address_space_mem, - address_space_io, PCI_DEVFN(0x11, 0), 4); - s->pci_state.bus = b; + &s->pio, PCI_DEVFN(s->first_slot, 0), 4); + h->bus = b; pci_create_simple(b, 0, "e500-host-bridge"); @@ -335,6 +372,7 @@ static int e500_pcihost_initfn(SysBusDevice *dev) memory_region_add_subregion(&s->container, PCIE500_CFGDATA, &h->data_mem); memory_region_add_subregion(&s->container, PCIE500_REG_BASE, &s->iomem); sysbus_init_mmio(dev, &s->container); + sysbus_init_mmio(dev, &s->pio); return 0; } @@ -344,31 +382,38 @@ static void e500_host_bridge_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + k->init = e500_pcihost_bridge_initfn; k->vendor_id = PCI_VENDOR_ID_FREESCALE; k->device_id = PCI_DEVICE_ID_MPC8533E; k->class_id = PCI_CLASS_PROCESSOR_POWERPC; dc->desc = "Host bridge"; } -static TypeInfo e500_host_bridge_info = { +static const TypeInfo e500_host_bridge_info = { .name = "e500-host-bridge", .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), + .instance_size = sizeof(PPCE500PCIBridgeState), .class_init = e500_host_bridge_class_init, }; +static Property pcihost_properties[] = { + DEFINE_PROP_UINT32("first_slot", PPCE500PCIState, first_slot, 0x11), + DEFINE_PROP_END_OF_LIST(), +}; + static void e500_pcihost_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = e500_pcihost_initfn; + dc->props = pcihost_properties; dc->vmsd = &vmstate_ppce500_pci; } -static TypeInfo e500_pcihost_info = { - .name = "e500-pcihost", - .parent = TYPE_SYS_BUS_DEVICE, +static const TypeInfo e500_pcihost_info = { + .name = TYPE_PPC_E500_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(PPCE500PCIState), .class_init = e500_pcihost_class_init, }; diff --git a/hw/ppce500_pci.h b/hw/ppce500_pci.h new file mode 100644 index 0000000000..61f773ef30 --- /dev/null +++ b/hw/ppce500_pci.h @@ -0,0 +1,9 @@ +#ifndef PPCE500_PCI_H +#define PPCE500_PCI_H + +static inline int ppce500_pci_map_irq_slot(int devno, int irq_num) +{ + return (devno + irq_num) % 4; +} + +#endif diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c index c5b8e051ec..177aa2d122 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -28,9 +28,9 @@ */ #include "hw.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "sysbus.h" -#include "kvm.h" +#include "sysemu/kvm.h" #define MAX_CPUS 32 @@ -49,7 +49,7 @@ typedef struct spin_state { } SpinState; typedef struct spin_kick { - CPUPPCState *env; + PowerPCCPU *cpu; SpinInfo *spin; } SpinKick; @@ -68,18 +68,18 @@ static void spin_reset(void *opaque) } /* Create -kernel TLB entries for BookE, linearly spanning 256MB. */ -static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size) +static inline hwaddr booke206_page_size_to_tlb(uint64_t size) { return (ffs(size >> 10) - 1) >> 1; } static void mmubooke_create_initial_mapping(CPUPPCState *env, target_ulong va, - target_phys_addr_t pa, - target_phys_addr_t len) + hwaddr pa, + hwaddr len) { ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1); - target_phys_addr_t size; + hwaddr size; size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT); tlb->mas1 = MAS1_VALID | size; @@ -92,10 +92,11 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env, static void spin_kick(void *data) { SpinKick *kick = data; - CPUPPCState *env = kick->env; + CPUState *cpu = CPU(kick->cpu); + CPUPPCState *env = &kick->cpu->env; SpinInfo *curspin = kick->spin; - target_phys_addr_t map_size = 64 * 1024 * 1024; - target_phys_addr_t map_start; + hwaddr map_size = 64 * 1024 * 1024; + hwaddr map_start; cpu_synchronize_state(env); stl_p(&curspin->pir, env->spr[SPR_PIR]); @@ -113,11 +114,11 @@ static void spin_kick(void *data) env->halted = 0; env->exception_index = -1; - env->stopped = 0; - qemu_cpu_kick(env); + cpu->stopped = false; + qemu_cpu_kick(cpu); } -static void spin_write(void *opaque, target_phys_addr_t addr, uint64_t value, +static void spin_write(void *opaque, hwaddr addr, uint64_t value, unsigned len) { SpinState *s = opaque; @@ -158,15 +159,15 @@ static void spin_write(void *opaque, target_phys_addr_t addr, uint64_t value, if (!(ldq_p(&curspin->addr) & 1)) { /* run CPU */ SpinKick kick = { - .env = env, + .cpu = ppc_env_get_cpu(env), .spin = curspin, }; - run_on_cpu(env, spin_kick, &kick); + run_on_cpu(CPU(kick.cpu), spin_kick, &kick); } } -static uint64_t spin_read(void *opaque, target_phys_addr_t addr, unsigned len) +static uint64_t spin_read(void *opaque, hwaddr addr, unsigned len) { SpinState *s = opaque; uint8_t *spin_p = &((uint8_t*)s->spin)[addr]; diff --git a/hw/prep_pci.c b/hw/prep_pci.c index 38dbff44a1..212a2ac4f1 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -23,13 +23,19 @@ */ #include "hw.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" #include "pc.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" + +#define TYPE_RAVEN_PCI_HOST_BRIDGE "raven-pcihost" + +#define RAVEN_PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(PREPPCIState, (obj), TYPE_RAVEN_PCI_HOST_BRIDGE) typedef struct PRePPCIState { - PCIHostState host_state; + PCIHostState parent_obj; + MemoryRegion intack; qemu_irq irq[4]; } PREPPCIState; @@ -38,29 +44,32 @@ typedef struct RavenPCIState { PCIDevice dev; } RavenPCIState; -static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr) +static inline uint32_t PPC_PCIIO_config(hwaddr addr) { int i; - for(i = 0; i < 11; i++) { - if ((addr & (1 << (11 + i))) != 0) + for (i = 0; i < 11; i++) { + if ((addr & (1 << (11 + i))) != 0) { break; + } } return (addr & 0x7ff) | (i << 11); } -static void ppc_pci_io_write(void *opaque, target_phys_addr_t addr, +static void ppc_pci_io_write(void *opaque, hwaddr addr, uint64_t val, unsigned int size) { PREPPCIState *s = opaque; - pci_data_write(s->host_state.bus, PPC_PCIIO_config(addr), val, size); + PCIHostState *phb = PCI_HOST_BRIDGE(s); + pci_data_write(phb->bus, PPC_PCIIO_config(addr), val, size); } -static uint64_t ppc_pci_io_read(void *opaque, target_phys_addr_t addr, +static uint64_t ppc_pci_io_read(void *opaque, hwaddr addr, unsigned int size) { PREPPCIState *s = opaque; - return pci_data_read(s->host_state.bus, PPC_PCIIO_config(addr), size); + PCIHostState *phb = PCI_HOST_BRIDGE(s); + return pci_data_read(phb->bus, PPC_PCIIO_config(addr), size); } static const MemoryRegionOps PPC_PCIIO_ops = { @@ -69,7 +78,7 @@ static const MemoryRegionOps PPC_PCIIO_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static uint64_t ppc_intack_read(void *opaque, target_phys_addr_t addr, +static uint64_t ppc_intack_read(void *opaque, hwaddr addr, unsigned int size) { return pic_read_irq(isa_pic); @@ -96,8 +105,8 @@ static void prep_set_irq(void *opaque, int irq_num, int level) static int raven_pcihost_init(SysBusDevice *dev) { - PCIHostState *h = FROM_SYSBUS(PCIHostState, dev); - PREPPCIState *s = DO_UPCAST(PREPPCIState, host_state, h); + PCIHostState *h = PCI_HOST_BRIDGE(dev); + PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev); MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *address_space_io = get_system_io(); PCIBus *bus; @@ -107,7 +116,7 @@ static int raven_pcihost_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq[i]); } - bus = pci_register_bus(&h->busdev.qdev, NULL, + bus = pci_register_bus(DEVICE(dev), NULL, prep_set_irq, prep_map_irq, s->irq, address_space_mem, address_space_io, 0, 4); h->bus = bus; @@ -166,7 +175,7 @@ static void raven_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo raven_info = { +static const TypeInfo raven_info = { .name = "raven", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(RavenPCIState), @@ -183,9 +192,9 @@ static void raven_pcihost_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo raven_pcihost_info = { - .name = "raven-pcihost", - .parent = TYPE_SYS_BUS_DEVICE, +static const TypeInfo raven_pcihost_info = { + .name = TYPE_RAVEN_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(PREPPCIState), .class_init = raven_pcihost_class_init, }; @@ -23,8 +23,8 @@ */ #include "hw.h" #include "ps2.h" -#include "console.h" -#include "sysemu.h" +#include "ui/console.h" +#include "sysemu/sysemu.h" /* debug PC keyboard */ //#define DEBUG_KBD diff --git a/hw/ptimer.c b/hw/ptimer.c index bc0b3f802f..24af6a2afe 100644 --- a/hw/ptimer.c +++ b/hw/ptimer.c @@ -6,9 +6,9 @@ * This code is licensed under the GNU LGPL. */ #include "hw.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "ptimer.h" -#include "host-utils.h" +#include "qemu/host-utils.h" struct ptimer_state { diff --git a/hw/ptimer.h b/hw/ptimer.h index 6638f61322..28fcaf17f8 100644 --- a/hw/ptimer.h +++ b/hw/ptimer.h @@ -9,8 +9,8 @@ #define PTIMER_H #include "qemu-common.h" -#include "qemu-timer.h" -#include "vmstate.h" +#include "qemu/timer.h" +#include "migration/vmstate.h" /* ptimer.c */ typedef struct ptimer_state ptimer_state; @@ -8,9 +8,11 @@ * published by the Free Software Foundation, or any later version. * See the COPYING file in the top-level directory. */ -#include "console.h" + +#include "qemu-common.h" +#include "ui/console.h" #include "elf.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #include "sysbus.h" #include "boards.h" #include "loader.h" @@ -91,10 +93,12 @@ static void puv3_load_kernel(const char *kernel_filename) graphic_console_init(NULL, NULL, NULL, NULL, NULL); } -static void puv3_init(ram_addr_t ram_size, const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void puv3_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *initrd_filename = args->initrd_filename; CPUUniCore32State *env; if (initrd_filename) { @@ -120,7 +124,6 @@ static QEMUMachine puv3_machine = { .desc = "PKUnity Version-3 based on UniCore32", .init = puv3_init, .is_default = 1, - .use_scsi = 0, }; static void puv3_machine_init(void) diff --git a/hw/puv3_dma.c b/hw/puv3_dma.c index 85b97bfdeb..9de63b4c34 100644 --- a/hw/puv3_dma.c +++ b/hw/puv3_dma.c @@ -24,7 +24,7 @@ typedef struct { uint32_t reg_CFG[PUV3_DMA_CH_NR]; } PUV3DMAState; -static uint64_t puv3_dma_read(void *opaque, target_phys_addr_t offset, +static uint64_t puv3_dma_read(void *opaque, hwaddr offset, unsigned size) { PUV3DMAState *s = opaque; @@ -44,7 +44,7 @@ static uint64_t puv3_dma_read(void *opaque, target_phys_addr_t offset, return ret; } -static void puv3_dma_write(void *opaque, target_phys_addr_t offset, +static void puv3_dma_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PUV3DMAState *s = opaque; diff --git a/hw/puv3_gpio.c b/hw/puv3_gpio.c index 9436e6c62c..152248d291 100644 --- a/hw/puv3_gpio.c +++ b/hw/puv3_gpio.c @@ -24,7 +24,7 @@ typedef struct { uint32_t reg_GPIR; } PUV3GPIOState; -static uint64_t puv3_gpio_read(void *opaque, target_phys_addr_t offset, +static uint64_t puv3_gpio_read(void *opaque, hwaddr offset, unsigned size) { PUV3GPIOState *s = opaque; @@ -48,7 +48,7 @@ static uint64_t puv3_gpio_read(void *opaque, target_phys_addr_t offset, return ret; } -static void puv3_gpio_write(void *opaque, target_phys_addr_t offset, +static void puv3_gpio_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PUV3GPIOState *s = opaque; diff --git a/hw/puv3_intc.c b/hw/puv3_intc.c index 9e0b975ea2..07f5649065 100644 --- a/hw/puv3_intc.c +++ b/hw/puv3_intc.c @@ -46,7 +46,7 @@ static void puv3_intc_handler(void *opaque, int irq, int level) puv3_intc_update(s); } -static uint64_t puv3_intc_read(void *opaque, target_phys_addr_t offset, +static uint64_t puv3_intc_read(void *opaque, hwaddr offset, unsigned size) { PUV3INTCState *s = opaque; @@ -66,7 +66,7 @@ static uint64_t puv3_intc_read(void *opaque, target_phys_addr_t offset, return ret; } -static void puv3_intc_write(void *opaque, target_phys_addr_t offset, +static void puv3_intc_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PUV3INTCState *s = opaque; diff --git a/hw/puv3_ost.c b/hw/puv3_ost.c index dd30cad0e2..14c6f21a75 100644 --- a/hw/puv3_ost.c +++ b/hw/puv3_ost.c @@ -28,7 +28,7 @@ typedef struct { uint32_t reg_OIER; } PUV3OSTState; -static uint64_t puv3_ost_read(void *opaque, target_phys_addr_t offset, +static uint64_t puv3_ost_read(void *opaque, hwaddr offset, unsigned size) { PUV3OSTState *s = opaque; @@ -51,7 +51,7 @@ static uint64_t puv3_ost_read(void *opaque, target_phys_addr_t offset, return ret; } -static void puv3_ost_write(void *opaque, target_phys_addr_t offset, +static void puv3_ost_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PUV3OSTState *s = opaque; diff --git a/hw/puv3_pm.c b/hw/puv3_pm.c index 621c96875c..87a687afae 100644 --- a/hw/puv3_pm.c +++ b/hw/puv3_pm.c @@ -26,7 +26,7 @@ typedef struct { uint32_t reg_DIVCFG; } PUV3PMState; -static uint64_t puv3_pm_read(void *opaque, target_phys_addr_t offset, +static uint64_t puv3_pm_read(void *opaque, hwaddr offset, unsigned size) { PUV3PMState *s = opaque; @@ -74,7 +74,7 @@ static uint64_t puv3_pm_read(void *opaque, target_phys_addr_t offset, return ret; } -static void puv3_pm_write(void *opaque, target_phys_addr_t offset, +static void puv3_pm_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PUV3PMState *s = opaque; @@ -9,7 +9,7 @@ #ifndef PXA_H # define PXA_H "pxa.h" -#include "memory.h" +#include "exec/memory.h" /* Interrupt numbers */ # define PXA2XX_PIC_SSP3 0 @@ -65,28 +65,28 @@ # define PXA2XX_INTERNAL_SIZE 0x40000 /* pxa2xx_pic.c */ -DeviceState *pxa2xx_pic_init(target_phys_addr_t base, ARMCPU *cpu); +DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu); /* pxa2xx_gpio.c */ -DeviceState *pxa2xx_gpio_init(target_phys_addr_t base, +DeviceState *pxa2xx_gpio_init(hwaddr base, CPUARMState *env, DeviceState *pic, int lines); void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler); /* pxa2xx_dma.c */ -DeviceState *pxa255_dma_init(target_phys_addr_t base, qemu_irq irq); -DeviceState *pxa27x_dma_init(target_phys_addr_t base, qemu_irq irq); +DeviceState *pxa255_dma_init(hwaddr base, qemu_irq irq); +DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq); /* pxa2xx_lcd.c */ typedef struct PXA2xxLCDState PXA2xxLCDState; PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem, - target_phys_addr_t base, qemu_irq irq); + hwaddr base, qemu_irq irq); void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler); void pxa2xx_lcdc_oritentation(void *opaque, int angle); /* pxa2xx_mmci.c */ typedef struct PXA2xxMMCIState PXA2xxMMCIState; PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem, - target_phys_addr_t base, + hwaddr base, BlockDriverState *bd, qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma); void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly, @@ -95,7 +95,7 @@ void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly, /* pxa2xx_pcmcia.c */ typedef struct PXA2xxPCMCIAState PXA2xxPCMCIAState; PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem, - target_phys_addr_t base); + hwaddr base); int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card); int pxa2xx_pcmcia_dettach(void *opaque); void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq); @@ -107,14 +107,14 @@ struct keymap { }; typedef struct PXA2xxKeyPadState PXA2xxKeyPadState; PXA2xxKeyPadState *pxa27x_keypad_init(MemoryRegion *sysmem, - target_phys_addr_t base, + hwaddr base, qemu_irq irq); void pxa27x_register_keypad(PXA2xxKeyPadState *kp, struct keymap *map, int size); /* pxa2xx.c */ typedef struct PXA2xxI2CState PXA2xxI2CState; -PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base, +PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base, qemu_irq irq, uint32_t page_size); i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s); @@ -142,16 +142,16 @@ typedef struct { PXA2xxKeyPadState *kp; /* Power management */ - target_phys_addr_t pm_base; + hwaddr pm_base; uint32_t pm_regs[0x40]; /* Clock management */ - target_phys_addr_t cm_base; + hwaddr cm_base; uint32_t cm_regs[4]; uint32_t clkcfg; /* Memory management */ - target_phys_addr_t mm_base; + hwaddr mm_base; uint32_t mm_regs[0x1a]; /* Performance monitoring */ diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index d5f1420ed9..3c51bc82aa 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -9,15 +9,15 @@ #include "sysbus.h" #include "pxa.h" -#include "sysemu.h" -#include "pc.h" +#include "sysemu/sysemu.h" +#include "serial.h" #include "i2c.h" #include "ssi.h" -#include "qemu-char.h" -#include "blockdev.h" +#include "char/char.h" +#include "sysemu/blockdev.h" static struct { - target_phys_addr_t io_base; + hwaddr io_base; int irqn; } pxa255_serial[] = { { 0x40100000, PXA2XX_PIC_FFUART }, @@ -33,7 +33,7 @@ static struct { }; typedef struct PXASSPDef { - target_phys_addr_t io_base; + hwaddr io_base; int irqn; } PXASSPDef; @@ -88,7 +88,7 @@ static PXASSPDef pxa27x_ssp[] = { #define PCMD0 0x80 /* Power Manager I2C Command register File 0 */ #define PCMD31 0xfc /* Power Manager I2C Command register File 31 */ -static uint64_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr, +static uint64_t pxa2xx_pm_read(void *opaque, hwaddr addr, unsigned size) { PXA2xxState *s = (PXA2xxState *) opaque; @@ -107,7 +107,7 @@ static uint64_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr, return 0; } -static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr, +static void pxa2xx_pm_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { PXA2xxState *s = (PXA2xxState *) opaque; @@ -160,7 +160,7 @@ static const VMStateDescription vmstate_pxa2xx_pm = { #define OSCC 0x08 /* Oscillator Configuration register */ #define CCSR 0x0c /* Core Clock Status register */ -static uint64_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr, +static uint64_t pxa2xx_cm_read(void *opaque, hwaddr addr, unsigned size) { PXA2xxState *s = (PXA2xxState *) opaque; @@ -181,7 +181,7 @@ static uint64_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr, return 0; } -static void pxa2xx_cm_write(void *opaque, target_phys_addr_t addr, +static void pxa2xx_cm_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { PXA2xxState *s = (PXA2xxState *) opaque; @@ -405,7 +405,7 @@ static void pxa2xx_setup_cp14(PXA2xxState *s) #define BSCNTR3 0x60 /* Memory Buffer Strength Control register 3 */ #define SA1110 0x64 /* SA-1110 Memory Compatibility register */ -static uint64_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr, +static uint64_t pxa2xx_mm_read(void *opaque, hwaddr addr, unsigned size) { PXA2xxState *s = (PXA2xxState *) opaque; @@ -422,7 +422,7 @@ static uint64_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr, return 0; } -static void pxa2xx_mm_write(void *opaque, target_phys_addr_t addr, +static void pxa2xx_mm_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { PXA2xxState *s = (PXA2xxState *) opaque; @@ -567,7 +567,7 @@ static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s) pxa2xx_ssp_int_update(s); } -static uint64_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr, +static uint64_t pxa2xx_ssp_read(void *opaque, hwaddr addr, unsigned size) { PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; @@ -613,7 +613,7 @@ static uint64_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr, return 0; } -static void pxa2xx_ssp_write(void *opaque, target_phys_addr_t addr, +static void pxa2xx_ssp_write(void *opaque, hwaddr addr, uint64_t value64, unsigned size) { PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; @@ -943,7 +943,7 @@ static inline void pxa2xx_rtc_pi_tick(void *opaque) pxa2xx_rtc_int_update(s); } -static uint64_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr, +static uint64_t pxa2xx_rtc_read(void *opaque, hwaddr addr, unsigned size) { PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; @@ -989,7 +989,7 @@ static uint64_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr, return 0; } -static void pxa2xx_rtc_write(void *opaque, target_phys_addr_t addr, +static void pxa2xx_rtc_write(void *opaque, hwaddr addr, uint64_t value64, unsigned size) { PXA2xxRTCState *s = (PXA2xxRTCState *) opaque; @@ -1294,7 +1294,7 @@ static int pxa2xx_i2c_tx(I2CSlave *i2c, uint8_t data) return 1; } -static uint64_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr, +static uint64_t pxa2xx_i2c_read(void *opaque, hwaddr addr, unsigned size) { PXA2xxI2CState *s = (PXA2xxI2CState *) opaque; @@ -1322,7 +1322,7 @@ static uint64_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr, return 0; } -static void pxa2xx_i2c_write(void *opaque, target_phys_addr_t addr, +static void pxa2xx_i2c_write(void *opaque, hwaddr addr, uint64_t value64, unsigned size) { PXA2xxI2CState *s = (PXA2xxI2CState *) opaque; @@ -1449,7 +1449,7 @@ static TypeInfo pxa2xx_i2c_slave_info = { .class_init = pxa2xx_i2c_slave_class_init, }; -PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base, +PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base, qemu_irq irq, uint32_t region_size) { DeviceState *dev; @@ -1572,7 +1572,7 @@ static inline void pxa2xx_i2s_update(PXA2xxI2SState *i2s) #define SADIV 0x60 /* Serial Audio Clock Divider register */ #define SADR 0x80 /* Serial Audio Data register */ -static uint64_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr, +static uint64_t pxa2xx_i2s_read(void *opaque, hwaddr addr, unsigned size) { PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; @@ -1604,7 +1604,7 @@ static uint64_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr, return 0; } -static void pxa2xx_i2s_write(void *opaque, target_phys_addr_t addr, +static void pxa2xx_i2s_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { PXA2xxI2SState *s = (PXA2xxI2SState *) opaque; @@ -1706,7 +1706,7 @@ static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx) } static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem, - target_phys_addr_t base, + hwaddr base, qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma) { PXA2xxI2SState *s = (PXA2xxI2SState *) @@ -1801,7 +1801,7 @@ static inline void pxa2xx_fir_update(PXA2xxFIrState *s) #define ICSR1 0x18 /* FICP Status register 1 */ #define ICFOR 0x1c /* FICP FIFO Occupancy Status register */ -static uint64_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr, +static uint64_t pxa2xx_fir_read(void *opaque, hwaddr addr, unsigned size) { PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; @@ -1839,7 +1839,7 @@ static uint64_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr, return 0; } -static void pxa2xx_fir_write(void *opaque, target_phys_addr_t addr, +static void pxa2xx_fir_write(void *opaque, hwaddr addr, uint64_t value64, unsigned size) { PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; @@ -1963,7 +1963,7 @@ static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id) } static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, - target_phys_addr_t base, + hwaddr base, qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma, CharDriverState *chr) { @@ -2108,7 +2108,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); } - if (usb_enabled) { + if (usb_enabled(false)) { sysbus_create_simple("sysbus-ohci", 0x4c000000, qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1)); } @@ -2239,7 +2239,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); } - if (usb_enabled) { + if (usb_enabled(false)) { sysbus_create_simple("sysbus-ohci", 0x4c000000, qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1)); } diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index 031015400b..dbea1d2098 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -147,7 +147,7 @@ static inline void pxa2xx_dma_descriptor_fetch( PXA2xxDMAState *s, int ch) { uint32_t desc[4]; - target_phys_addr_t daddr = s->chan[ch].descr & ~0xf; + hwaddr daddr = s->chan[ch].descr & ~0xf; if ((s->chan[ch].descr & DDADR_BREN) && (s->chan[ch].state & DCSR_CMPST)) daddr += 32; @@ -251,7 +251,7 @@ static void pxa2xx_dma_run(PXA2xxDMAState *s) } } -static uint64_t pxa2xx_dma_read(void *opaque, target_phys_addr_t offset, +static uint64_t pxa2xx_dma_read(void *opaque, hwaddr offset, unsigned size) { PXA2xxDMAState *s = (PXA2xxDMAState *) opaque; @@ -310,7 +310,7 @@ static uint64_t pxa2xx_dma_read(void *opaque, target_phys_addr_t offset, return 7; } -static void pxa2xx_dma_write(void *opaque, target_phys_addr_t offset, +static void pxa2xx_dma_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PXA2xxDMAState *s = (PXA2xxDMAState *) opaque; @@ -473,7 +473,7 @@ static int pxa2xx_dma_init(SysBusDevice *dev) return 0; } -DeviceState *pxa27x_dma_init(target_phys_addr_t base, qemu_irq irq) +DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq) { DeviceState *dev; @@ -487,7 +487,7 @@ DeviceState *pxa27x_dma_init(target_phys_addr_t base, qemu_irq irq) return dev; } -DeviceState *pxa255_dma_init(target_phys_addr_t base, qemu_irq irq) +DeviceState *pxa255_dma_init(hwaddr base, qemu_irq irq) { DeviceState *dev; diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 3c90c9c4e0..7aaf4092df 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -139,7 +139,7 @@ static void pxa2xx_gpio_handler_update(PXA2xxGPIOInfo *s) { } } -static uint64_t pxa2xx_gpio_read(void *opaque, target_phys_addr_t offset, +static uint64_t pxa2xx_gpio_read(void *opaque, hwaddr offset, unsigned size) { PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque; @@ -191,7 +191,7 @@ static uint64_t pxa2xx_gpio_read(void *opaque, target_phys_addr_t offset, return 0; } -static void pxa2xx_gpio_write(void *opaque, target_phys_addr_t offset, +static void pxa2xx_gpio_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque; @@ -249,7 +249,7 @@ static const MemoryRegionOps pxa_gpio_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -DeviceState *pxa2xx_gpio_init(target_phys_addr_t base, +DeviceState *pxa2xx_gpio_init(hwaddr base, CPUARMState *env, DeviceState *pic, int lines) { DeviceState *dev; diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c index 59db02584e..4ff04ad63b 100644 --- a/hw/pxa2xx_keypad.c +++ b/hw/pxa2xx_keypad.c @@ -13,7 +13,7 @@ #include "hw.h" #include "pxa.h" -#include "console.h" +#include "ui/console.h" /* * Keypad @@ -172,10 +172,9 @@ static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode) kp->kpc |= KPC_MI; qemu_irq_raise(kp->irq); } - return; } -static uint64_t pxa2xx_keypad_read(void *opaque, target_phys_addr_t offset, +static uint64_t pxa2xx_keypad_read(void *opaque, hwaddr offset, unsigned size) { PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque; @@ -237,7 +236,7 @@ static uint64_t pxa2xx_keypad_read(void *opaque, target_phys_addr_t offset, return 0; } -static void pxa2xx_keypad_write(void *opaque, target_phys_addr_t offset, +static void pxa2xx_keypad_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque; @@ -306,7 +305,7 @@ static const VMStateDescription vmstate_pxa2xx_keypad = { }; PXA2xxKeyPadState *pxa27x_keypad_init(MemoryRegion *sysmem, - target_phys_addr_t base, + hwaddr base, qemu_irq irq) { PXA2xxKeyPadState *s; diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index ee8bf577cb..512a27e702 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -11,11 +11,11 @@ */ #include "hw.h" -#include "console.h" +#include "ui/console.h" #include "pxa.h" -#include "pixel_ops.h" +#include "ui/pixel_ops.h" /* FIXME: For graphic_rotate. Should probably be done in common code. */ -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "framebuffer.h" struct DMAChannel { @@ -23,7 +23,7 @@ struct DMAChannel { uint8_t up; uint8_t palette[1024]; uint8_t pbuffer[1024]; - void (*redraw)(PXA2xxLCDState *s, target_phys_addr_t addr, + void (*redraw)(PXA2xxLCDState *s, hwaddr addr, int *miny, int *maxy); uint32_t descriptor; @@ -291,7 +291,7 @@ static inline void pxa2xx_dma_rdst_set(PXA2xxLCDState *s) static void pxa2xx_descriptor_load(PXA2xxLCDState *s) { PXAFrameDescriptor desc; - target_phys_addr_t descptr; + hwaddr descptr; int i; for (i = 0; i < PXA_LCDDMA_CHANS; i ++) { @@ -323,7 +323,7 @@ static void pxa2xx_descriptor_load(PXA2xxLCDState *s) } } -static uint64_t pxa2xx_lcdc_read(void *opaque, target_phys_addr_t offset, +static uint64_t pxa2xx_lcdc_read(void *opaque, hwaddr offset, unsigned size) { PXA2xxLCDState *s = (PXA2xxLCDState *) opaque; @@ -417,7 +417,7 @@ static uint64_t pxa2xx_lcdc_read(void *opaque, target_phys_addr_t offset, return 0; } -static void pxa2xx_lcdc_write(void *opaque, target_phys_addr_t offset, +static void pxa2xx_lcdc_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PXA2xxLCDState *s = (PXA2xxLCDState *) opaque; @@ -674,7 +674,7 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp) } static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s, - target_phys_addr_t addr, int *miny, int *maxy) + hwaddr addr, int *miny, int *maxy) { int src_width, dest_width; drawfn fn = NULL; @@ -701,7 +701,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s, } static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s, - target_phys_addr_t addr, int *miny, int *maxy) + hwaddr addr, int *miny, int *maxy) { int src_width, dest_width; drawfn fn = NULL; @@ -729,7 +729,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s, } static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s, - target_phys_addr_t addr, int *miny, int *maxy) + hwaddr addr, int *miny, int *maxy) { int src_width, dest_width; drawfn fn = NULL; @@ -759,7 +759,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s, } static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s, - target_phys_addr_t addr, int *miny, int *maxy) + hwaddr addr, int *miny, int *maxy) { int src_width, dest_width; drawfn fn = NULL; @@ -813,7 +813,7 @@ static void pxa2xx_lcdc_resize(PXA2xxLCDState *s) static void pxa2xx_update_display(void *opaque) { PXA2xxLCDState *s = (PXA2xxLCDState *) opaque; - target_phys_addr_t fbptr; + hwaddr fbptr; int miny, maxy; int ch; if (!(s->control[0] & LCCR0_ENB)) @@ -871,20 +871,20 @@ static void pxa2xx_update_display(void *opaque) if (miny >= 0) { switch (s->orientation) { case 0: - dpy_update(s->ds, 0, miny, s->xres, maxy - miny + 1); + dpy_gfx_update(s->ds, 0, miny, s->xres, maxy - miny + 1); break; case 90: - dpy_update(s->ds, miny, 0, maxy - miny + 1, s->xres); + dpy_gfx_update(s->ds, miny, 0, maxy - miny + 1, s->xres); break; case 180: maxy = s->yres - maxy - 1; miny = s->yres - miny - 1; - dpy_update(s->ds, 0, maxy, s->xres, miny - maxy + 1); + dpy_gfx_update(s->ds, 0, maxy, s->xres, miny - maxy + 1); break; case 270: maxy = s->yres - maxy - 1; miny = s->yres - miny - 1; - dpy_update(s->ds, maxy, 0, miny - maxy + 1, s->xres); + dpy_gfx_update(s->ds, maxy, 0, miny - maxy + 1, s->xres); break; } } @@ -987,7 +987,7 @@ static const VMStateDescription vmstate_pxa2xx_lcdc = { #include "pxa2xx_template.h" PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem, - target_phys_addr_t base, qemu_irq irq) + hwaddr base, qemu_irq irq) { PXA2xxLCDState *s; diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c index b505a4cc98..3589968712 100644 --- a/hw/pxa2xx_mmci.c +++ b/hw/pxa2xx_mmci.c @@ -215,7 +215,7 @@ static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s) pxa2xx_mmci_fifo_update(s); } -static uint32_t pxa2xx_mmci_read(void *opaque, target_phys_addr_t offset) +static uint32_t pxa2xx_mmci_read(void *opaque, hwaddr offset) { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; uint32_t ret; @@ -277,7 +277,7 @@ static uint32_t pxa2xx_mmci_read(void *opaque, target_phys_addr_t offset) } static void pxa2xx_mmci_write(void *opaque, - target_phys_addr_t offset, uint32_t value) + hwaddr offset, uint32_t value) { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; @@ -386,21 +386,21 @@ static void pxa2xx_mmci_write(void *opaque, } } -static uint32_t pxa2xx_mmci_readb(void *opaque, target_phys_addr_t offset) +static uint32_t pxa2xx_mmci_readb(void *opaque, hwaddr offset) { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; s->ac_width = 1; return pxa2xx_mmci_read(opaque, offset); } -static uint32_t pxa2xx_mmci_readh(void *opaque, target_phys_addr_t offset) +static uint32_t pxa2xx_mmci_readh(void *opaque, hwaddr offset) { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; s->ac_width = 2; return pxa2xx_mmci_read(opaque, offset); } -static uint32_t pxa2xx_mmci_readw(void *opaque, target_phys_addr_t offset) +static uint32_t pxa2xx_mmci_readw(void *opaque, hwaddr offset) { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; s->ac_width = 4; @@ -408,7 +408,7 @@ static uint32_t pxa2xx_mmci_readw(void *opaque, target_phys_addr_t offset) } static void pxa2xx_mmci_writeb(void *opaque, - target_phys_addr_t offset, uint32_t value) + hwaddr offset, uint32_t value) { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; s->ac_width = 1; @@ -416,7 +416,7 @@ static void pxa2xx_mmci_writeb(void *opaque, } static void pxa2xx_mmci_writeh(void *opaque, - target_phys_addr_t offset, uint32_t value) + hwaddr offset, uint32_t value) { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; s->ac_width = 2; @@ -424,7 +424,7 @@ static void pxa2xx_mmci_writeh(void *opaque, } static void pxa2xx_mmci_writew(void *opaque, - target_phys_addr_t offset, uint32_t value) + hwaddr offset, uint32_t value) { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; s->ac_width = 4; @@ -522,7 +522,7 @@ static int pxa2xx_mmci_load(QEMUFile *f, void *opaque, int version_id) } PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem, - target_phys_addr_t base, + hwaddr base, BlockDriverState *bd, qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma) { diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c index b15872a9d9..3a79c728ab 100644 --- a/hw/pxa2xx_pcmcia.c +++ b/hw/pxa2xx_pcmcia.c @@ -27,7 +27,7 @@ struct PXA2xxPCMCIAState { }; static uint64_t pxa2xx_pcmcia_common_read(void *opaque, - target_phys_addr_t offset, unsigned size) + hwaddr offset, unsigned size) { PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; @@ -38,7 +38,7 @@ static uint64_t pxa2xx_pcmcia_common_read(void *opaque, return 0; } -static void pxa2xx_pcmcia_common_write(void *opaque, target_phys_addr_t offset, +static void pxa2xx_pcmcia_common_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; @@ -49,7 +49,7 @@ static void pxa2xx_pcmcia_common_write(void *opaque, target_phys_addr_t offset, } static uint64_t pxa2xx_pcmcia_attr_read(void *opaque, - target_phys_addr_t offset, unsigned size) + hwaddr offset, unsigned size) { PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; @@ -60,7 +60,7 @@ static uint64_t pxa2xx_pcmcia_attr_read(void *opaque, return 0; } -static void pxa2xx_pcmcia_attr_write(void *opaque, target_phys_addr_t offset, +static void pxa2xx_pcmcia_attr_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; @@ -71,7 +71,7 @@ static void pxa2xx_pcmcia_attr_write(void *opaque, target_phys_addr_t offset, } static uint64_t pxa2xx_pcmcia_io_read(void *opaque, - target_phys_addr_t offset, unsigned size) + hwaddr offset, unsigned size) { PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; @@ -82,7 +82,7 @@ static uint64_t pxa2xx_pcmcia_io_read(void *opaque, return 0; } -static void pxa2xx_pcmcia_io_write(void *opaque, target_phys_addr_t offset, +static void pxa2xx_pcmcia_io_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; @@ -120,7 +120,7 @@ static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level) } PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem, - target_phys_addr_t base) + hwaddr base) { PXA2xxPCMCIAState *s; diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c index e1e8830ff0..70b2b79d07 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -119,7 +119,7 @@ static inline uint32_t pxa2xx_pic_highest(PXA2xxPICState *s) { return ichp; } -static uint64_t pxa2xx_pic_mem_read(void *opaque, target_phys_addr_t offset, +static uint64_t pxa2xx_pic_mem_read(void *opaque, hwaddr offset, unsigned size) { PXA2xxPICState *s = (PXA2xxPICState *) opaque; @@ -159,7 +159,7 @@ static uint64_t pxa2xx_pic_mem_read(void *opaque, target_phys_addr_t offset, } } -static void pxa2xx_pic_mem_write(void *opaque, target_phys_addr_t offset, +static void pxa2xx_pic_mem_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PXA2xxPICState *s = (PXA2xxPICState *) opaque; @@ -257,7 +257,7 @@ static int pxa2xx_pic_post_load(void *opaque, int version_id) return 0; } -DeviceState *pxa2xx_pic_init(target_phys_addr_t base, ARMCPU *cpu) +DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu) { CPUARMState *env = &cpu->env; DeviceState *dev = qdev_create(NULL, "pxa2xx_pic"); diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index 77b033b541..e4ffb15bb2 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -8,8 +8,8 @@ */ #include "hw.h" -#include "qemu-timer.h" -#include "sysemu.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" #include "pxa.h" #include "sysbus.h" @@ -149,7 +149,7 @@ static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n) qemu_mod_timer(s->tm4[n].tm.qtimer, new_qemu); } -static uint64_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset, +static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, unsigned size) { PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; @@ -227,7 +227,7 @@ static uint64_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset, return 0; } -static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset, +static void pxa2xx_timer_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { int i, tm = 0; diff --git a/hw/q35.c b/hw/q35.c new file mode 100644 index 0000000000..efebc2786a --- /dev/null +++ b/hw/q35.c @@ -0,0 +1,309 @@ +/* + * QEMU MCH/ICH9 PCI Bridge Emulation + * + * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2009, 2010, 2011 + * Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * Copyright (C) 2012 Jason Baron <jbaron@redhat.com> + * + * This is based on piix_pci.c, but heavily modified. + * + * 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. + */ +#include "hw.h" +#include "q35.h" + +/**************************************************************************** + * Q35 host + */ + +static int q35_host_init(SysBusDevice *dev) +{ + PCIBus *b; + PCIHostState *pci = FROM_SYSBUS(PCIHostState, dev); + Q35PCIHost *s = Q35_HOST_DEVICE(&dev->qdev); + + memory_region_init_io(&pci->conf_mem, &pci_host_conf_le_ops, pci, + "pci-conf-idx", 4); + sysbus_add_io(dev, MCH_HOST_BRIDGE_CONFIG_ADDR, &pci->conf_mem); + sysbus_init_ioports(&pci->busdev, MCH_HOST_BRIDGE_CONFIG_ADDR, 4); + + memory_region_init_io(&pci->data_mem, &pci_host_data_le_ops, pci, + "pci-conf-data", 4); + sysbus_add_io(dev, MCH_HOST_BRIDGE_CONFIG_DATA, &pci->data_mem); + sysbus_init_ioports(&pci->busdev, MCH_HOST_BRIDGE_CONFIG_DATA, 4); + + if (pcie_host_init(&s->host) < 0) { + return -1; + } + b = pci_bus_new(&s->host.pci.busdev.qdev, "pcie.0", + s->mch.pci_address_space, s->mch.address_space_io, 0); + s->host.pci.bus = b; + qdev_set_parent_bus(DEVICE(&s->mch), BUS(b)); + qdev_init_nofail(DEVICE(&s->mch)); + + return 0; +} + +static Property mch_props[] = { + DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr, + MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT), + DEFINE_PROP_END_OF_LIST(), +}; + +static void q35_host_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = q35_host_init; + dc->props = mch_props; +} + +static void q35_host_initfn(Object *obj) +{ + Q35PCIHost *s = Q35_HOST_DEVICE(obj); + + object_initialize(&s->mch, TYPE_MCH_PCI_DEVICE); + object_property_add_child(OBJECT(s), "mch", OBJECT(&s->mch), NULL); + qdev_prop_set_uint32(DEVICE(&s->mch), "addr", PCI_DEVFN(0, 0)); + qdev_prop_set_bit(DEVICE(&s->mch), "multifunction", false); +} + +static const TypeInfo q35_host_info = { + .name = TYPE_Q35_HOST_DEVICE, + .parent = TYPE_PCIE_HOST_BRIDGE, + .instance_size = sizeof(Q35PCIHost), + .instance_init = q35_host_initfn, + .class_init = q35_host_class_init, +}; + +/**************************************************************************** + * MCH D0:F0 + */ + +/* PCIe MMCFG */ +static void mch_update_pciexbar(MCHPCIState *mch) +{ + PCIDevice *pci_dev = &mch->d; + BusState *bus = qdev_get_parent_bus(&pci_dev->qdev); + DeviceState *qdev = bus->parent; + Q35PCIHost *s = Q35_HOST_DEVICE(qdev); + + uint64_t pciexbar; + int enable; + uint64_t addr; + uint64_t addr_mask; + uint32_t length; + + pciexbar = pci_get_quad(pci_dev->config + MCH_HOST_BRIDGE_PCIEXBAR); + enable = pciexbar & MCH_HOST_BRIDGE_PCIEXBAREN; + addr_mask = MCH_HOST_BRIDGE_PCIEXBAR_ADMSK; + switch (pciexbar & MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK) { + case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M: + length = 256 * 1024 * 1024; + break; + case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M: + length = 128 * 1024 * 1024; + addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_128ADMSK | + MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK; + break; + case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M: + length = 64 * 1024 * 1024; + addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK; + break; + case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD: + default: + enable = 0; + length = 0; + abort(); + break; + } + addr = pciexbar & addr_mask; + pcie_host_mmcfg_update(&s->host, enable, addr, length); +} + +/* PAM */ +static void mch_update_pam(MCHPCIState *mch) +{ + int i; + + memory_region_transaction_begin(); + for (i = 0; i < 13; i++) { + pam_update(&mch->pam_regions[i], i, + mch->d.config[MCH_HOST_BRIDGE_PAM0 + ((i + 1) / 2)]); + } + memory_region_transaction_commit(); +} + +/* SMRAM */ +static void mch_update_smram(MCHPCIState *mch) +{ + memory_region_transaction_begin(); + smram_update(&mch->smram_region, mch->d.config[MCH_HOST_BRDIGE_SMRAM], + mch->smm_enabled); + memory_region_transaction_commit(); +} + +static void mch_set_smm(int smm, void *arg) +{ + MCHPCIState *mch = arg; + + memory_region_transaction_begin(); + smram_set_smm(&mch->smm_enabled, smm, mch->d.config[MCH_HOST_BRDIGE_SMRAM], + &mch->smram_region); + memory_region_transaction_commit(); +} + +static void mch_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len) +{ + MCHPCIState *mch = MCH_PCI_DEVICE(d); + + /* XXX: implement SMRAM.D_LOCK */ + pci_default_write_config(d, address, val, len); + + if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PAM0, + MCH_HOST_BRIDGE_PAM_SIZE)) { + mch_update_pam(mch); + } + + if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PCIEXBAR, + MCH_HOST_BRIDGE_PCIEXBAR_SIZE)) { + mch_update_pciexbar(mch); + } + + if (ranges_overlap(address, len, MCH_HOST_BRDIGE_SMRAM, + MCH_HOST_BRDIGE_SMRAM_SIZE)) { + mch_update_smram(mch); + } +} + +static void mch_update(MCHPCIState *mch) +{ + mch_update_pciexbar(mch); + mch_update_pam(mch); + mch_update_smram(mch); +} + +static int mch_post_load(void *opaque, int version_id) +{ + MCHPCIState *mch = opaque; + mch_update(mch); + return 0; +} + +static const VMStateDescription vmstate_mch = { + .name = "mch", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = mch_post_load, + .fields = (VMStateField []) { + VMSTATE_PCI_DEVICE(d, MCHPCIState), + VMSTATE_UINT8(smm_enabled, MCHPCIState), + VMSTATE_END_OF_LIST() + } +}; + +static void mch_reset(DeviceState *qdev) +{ + PCIDevice *d = PCI_DEVICE(qdev); + MCHPCIState *mch = MCH_PCI_DEVICE(d); + + pci_set_quad(d->config + MCH_HOST_BRIDGE_PCIEXBAR, + MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT); + + d->config[MCH_HOST_BRDIGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT; + + mch_update(mch); +} + +static int mch_init(PCIDevice *d) +{ + int i; + hwaddr pci_hole64_size; + MCHPCIState *mch = MCH_PCI_DEVICE(d); + + /* setup pci memory regions */ + memory_region_init_alias(&mch->pci_hole, "pci-hole", + mch->pci_address_space, + mch->below_4g_mem_size, + 0x100000000ULL - mch->below_4g_mem_size); + memory_region_add_subregion(mch->system_memory, mch->below_4g_mem_size, + &mch->pci_hole); + pci_hole64_size = (sizeof(hwaddr) == 4 ? 0 : + ((uint64_t)1 << 62)); + memory_region_init_alias(&mch->pci_hole_64bit, "pci-hole64", + mch->pci_address_space, + 0x100000000ULL + mch->above_4g_mem_size, + pci_hole64_size); + if (pci_hole64_size) { + memory_region_add_subregion(mch->system_memory, + 0x100000000ULL + mch->above_4g_mem_size, + &mch->pci_hole_64bit); + } + /* smram */ + cpu_smm_register(&mch_set_smm, mch); + memory_region_init_alias(&mch->smram_region, "smram-region", + mch->pci_address_space, 0xa0000, 0x20000); + memory_region_add_subregion_overlap(mch->system_memory, 0xa0000, + &mch->smram_region, 1); + memory_region_set_enabled(&mch->smram_region, false); + init_pam(mch->ram_memory, mch->system_memory, mch->pci_address_space, + &mch->pam_regions[0], PAM_BIOS_BASE, PAM_BIOS_SIZE); + for (i = 0; i < 12; ++i) { + init_pam(mch->ram_memory, mch->system_memory, mch->pci_address_space, + &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, + PAM_EXPAN_SIZE); + } + return 0; +} + +static void mch_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = mch_init; + k->config_write = mch_write_config; + dc->reset = mch_reset; + dc->desc = "Host bridge"; + dc->vmsd = &vmstate_mch; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_Q35_MCH; + k->revision = MCH_HOST_BRIDGE_REVISION_DEFUALT; + k->class_id = PCI_CLASS_BRIDGE_HOST; +} + +static const TypeInfo mch_info = { + .name = TYPE_MCH_PCI_DEVICE, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(MCHPCIState), + .class_init = mch_class_init, +}; + +static void q35_register(void) +{ + type_register_static(&mch_info); + type_register_static(&q35_host_info); +} + +type_init(q35_register); diff --git a/hw/q35.h b/hw/q35.h new file mode 100644 index 0000000000..246c12cb04 --- /dev/null +++ b/hw/q35.h @@ -0,0 +1,150 @@ +/* + * q35.h + * + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * Copyright (C) 2012 Jason Baron <jbaron@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/> + */ + +#ifndef HW_Q35_H +#define HW_Q35_H + +#include "hw.h" +#include "qemu/range.h" +#include "isa.h" +#include "sysbus.h" +#include "pc.h" +#include "apm.h" +#include "apic.h" +#include "pci/pci.h" +#include "pci/pcie_host.h" +#include "acpi.h" +#include "acpi_ich9.h" +#include "pam.h" + +#define TYPE_Q35_HOST_DEVICE "q35-pcihost" +#define Q35_HOST_DEVICE(obj) \ + OBJECT_CHECK(Q35PCIHost, (obj), TYPE_Q35_HOST_DEVICE) + +#define TYPE_MCH_PCI_DEVICE "mch" +#define MCH_PCI_DEVICE(obj) \ + OBJECT_CHECK(MCHPCIState, (obj), TYPE_MCH_PCI_DEVICE) + +typedef struct MCHPCIState { + PCIDevice d; + MemoryRegion *ram_memory; + MemoryRegion *pci_address_space; + MemoryRegion *system_memory; + MemoryRegion *address_space_io; + PAMMemoryRegion pam_regions[13]; + MemoryRegion smram_region; + MemoryRegion pci_hole; + MemoryRegion pci_hole_64bit; + uint8_t smm_enabled; + ram_addr_t below_4g_mem_size; + ram_addr_t above_4g_mem_size; +} MCHPCIState; + +typedef struct Q35PCIHost { + PCIExpressHost host; + MCHPCIState mch; +} Q35PCIHost; + +#define Q35_MASK(bit, ms_bit, ls_bit) \ +((uint##bit##_t)(((1ULL << ((ms_bit) + 1)) - 1) & ~((1ULL << ls_bit) - 1))) + +/* + * gmch part + */ + +/* PCI configuration */ +#define MCH_HOST_BRIDGE "MCH" + +#define MCH_HOST_BRIDGE_CONFIG_ADDR 0xcf8 +#define MCH_HOST_BRIDGE_CONFIG_DATA 0xcfc + +/* D0:F0 configuration space */ +#define MCH_HOST_BRIDGE_REVISION_DEFUALT 0x0 + +#define MCH_HOST_BRIDGE_PCIEXBAR 0x60 /* 64bit register */ +#define MCH_HOST_BRIDGE_PCIEXBAR_SIZE 8 /* 64bit register */ +#define MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT 0xb0000000 +#define MCH_HOST_BRIDGE_PCIEXBAR_ADMSK Q35_MASK(64, 35, 28) +#define MCH_HOST_BRIDGE_PCIEXBAR_128ADMSK ((uint64_t)(1 << 26)) +#define MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK ((uint64_t)(1 << 25)) +#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK ((uint64_t)(0x3 << 1)) +#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M ((uint64_t)(0x0 << 1)) +#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M ((uint64_t)(0x1 << 1)) +#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M ((uint64_t)(0x2 << 1)) +#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD ((uint64_t)(0x3 << 1)) +#define MCH_HOST_BRIDGE_PCIEXBAREN ((uint64_t)1) + +#define MCH_HOST_BRIDGE_PAM_NB 7 +#define MCH_HOST_BRIDGE_PAM_SIZE 7 +#define MCH_HOST_BRIDGE_PAM0 0x90 +#define MCH_HOST_BRIDGE_PAM_BIOS_AREA 0xf0000 +#define MCH_HOST_BRIDGE_PAM_AREA_SIZE 0x10000 /* 16KB */ +#define MCH_HOST_BRIDGE_PAM1 0x91 +#define MCH_HOST_BRIDGE_PAM_EXPAN_AREA 0xc0000 +#define MCH_HOST_BRIDGE_PAM_EXPAN_SIZE 0x04000 +#define MCH_HOST_BRIDGE_PAM2 0x92 +#define MCH_HOST_BRIDGE_PAM3 0x93 +#define MCH_HOST_BRIDGE_PAM4 0x94 +#define MCH_HOST_BRIDGE_PAM_EXBIOS_AREA 0xe0000 +#define MCH_HOST_BRIDGE_PAM_EXBIOS_SIZE 0x04000 +#define MCH_HOST_BRIDGE_PAM5 0x95 +#define MCH_HOST_BRIDGE_PAM6 0x96 +#define MCH_HOST_BRIDGE_PAM_WE_HI ((uint8_t)(0x2 << 4)) +#define MCH_HOST_BRIDGE_PAM_RE_HI ((uint8_t)(0x1 << 4)) +#define MCH_HOST_BRIDGE_PAM_HI_MASK ((uint8_t)(0x3 << 4)) +#define MCH_HOST_BRIDGE_PAM_WE_LO ((uint8_t)0x2) +#define MCH_HOST_BRIDGE_PAM_RE_LO ((uint8_t)0x1) +#define MCH_HOST_BRIDGE_PAM_LO_MASK ((uint8_t)0x3) +#define MCH_HOST_BRIDGE_PAM_WE ((uint8_t)0x2) +#define MCH_HOST_BRIDGE_PAM_RE ((uint8_t)0x1) +#define MCH_HOST_BRIDGE_PAM_MASK ((uint8_t)0x3) + +#define MCH_HOST_BRDIGE_SMRAM 0x9d +#define MCH_HOST_BRDIGE_SMRAM_SIZE 1 +#define MCH_HOST_BRIDGE_SMRAM_DEFAULT ((uint8_t)0x2) +#define MCH_HOST_BRIDGE_SMRAM_D_OPEN ((uint8_t)(1 << 6)) +#define MCH_HOST_BRIDGE_SMRAM_D_CLS ((uint8_t)(1 << 5)) +#define MCH_HOST_BRIDGE_SMRAM_D_LCK ((uint8_t)(1 << 4)) +#define MCH_HOST_BRIDGE_SMRAM_G_SMRAME ((uint8_t)(1 << 3)) +#define MCH_HOST_BRIDGE_SMRAM_C_BASE_SEG_MASK ((uint8_t)0x7) +#define MCH_HOST_BRIDGE_SMRAM_C_BASE_SEG ((uint8_t)0x2) /* hardwired to b010 */ +#define MCH_HOST_BRIDGE_SMRAM_C_BASE 0xa0000 +#define MCH_HOST_BRIDGE_SMRAM_C_END 0xc0000 +#define MCH_HOST_BRIDGE_SMRAM_C_SIZE 0x20000 +#define MCH_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END 0x100000 + +#define MCH_HOST_BRIDGE_ESMRAMC 0x9e +#define MCH_HOST_BRDIGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 6)) +#define MCH_HOST_BRDIGE_ESMRAMC_E_SMERR ((uint8_t)(1 << 5)) +#define MCH_HOST_BRDIGE_ESMRAMC_SM_CACHE ((uint8_t)(1 << 4)) +#define MCH_HOST_BRDIGE_ESMRAMC_SM_L1 ((uint8_t)(1 << 3)) +#define MCH_HOST_BRDIGE_ESMRAMC_SM_L2 ((uint8_t)(1 << 2)) +#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_MASK ((uint8_t)(0x3 << 1)) +#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_1MB ((uint8_t)(0x0 << 1)) +#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_2MB ((uint8_t)(0x1 << 1)) +#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_8MB ((uint8_t)(0x2 << 1)) +#define MCH_HOST_BRDIGE_ESMRAMC_T_EN ((uint8_t)1) + +/* D1:F0 PCIE* port*/ +#define MCH_PCIE_DEV 1 +#define MCH_PCIE_FUNC 0 + +#endif /* HW_Q35_H */ diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c index b711b6bf96..3bfe101d79 100644 --- a/hw/qdev-addr.c +++ b/hw/qdev-addr.c @@ -1,12 +1,13 @@ #include "qdev.h" #include "qdev-addr.h" -#include "targphys.h" +#include "exec/hwaddr.h" +#include "qapi/visitor.h" /* --- target physical address --- */ static int parse_taddr(DeviceState *dev, Property *prop, const char *str) { - target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop); + hwaddr *ptr = qdev_get_prop_ptr(dev, prop); *ptr = strtoull(str, NULL, 16); return 0; @@ -14,7 +15,7 @@ static int parse_taddr(DeviceState *dev, Property *prop, const char *str) static int print_taddr(DeviceState *dev, Property *prop, char *dest, size_t len) { - target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop); + hwaddr *ptr = qdev_get_prop_ptr(dev, prop); return snprintf(dest, len, "0x" TARGET_FMT_plx, *ptr); } @@ -23,7 +24,7 @@ static void get_taddr(Object *obj, Visitor *v, void *opaque, { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop); + hwaddr *ptr = qdev_get_prop_ptr(dev, prop); int64_t value; value = *ptr; @@ -35,7 +36,7 @@ static void set_taddr(Object *obj, Visitor *v, void *opaque, { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop); + hwaddr *ptr = qdev_get_prop_ptr(dev, prop); Error *local_err = NULL; int64_t value; @@ -49,12 +50,12 @@ static void set_taddr(Object *obj, Visitor *v, void *opaque, error_propagate(errp, local_err); return; } - if ((uint64_t)value <= (uint64_t) ~(target_phys_addr_t)0) { + if ((uint64_t)value <= (uint64_t) ~(hwaddr)0) { *ptr = value; } else { error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, dev->id?:"", name, value, (uint64_t) 0, - (uint64_t) ~(target_phys_addr_t)0); + (uint64_t) ~(hwaddr)0); } } @@ -67,7 +68,7 @@ PropertyInfo qdev_prop_taddr = { .set = set_taddr, }; -void qdev_prop_set_taddr(DeviceState *dev, const char *name, target_phys_addr_t value) +void qdev_prop_set_taddr(DeviceState *dev, const char *name, hwaddr value) { Error *errp = NULL; object_property_set_int(OBJECT(dev), value, name, &errp); diff --git a/hw/qdev-addr.h b/hw/qdev-addr.h index a0ddf3863c..79708e6751 100644 --- a/hw/qdev-addr.h +++ b/hw/qdev-addr.h @@ -1,5 +1,10 @@ +#ifndef HW_QDEV_ADDR_H +#define HW_QDEV_ADDR_H 1 + #define DEFINE_PROP_TADDR(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_taddr, target_phys_addr_t) + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_taddr, hwaddr) extern PropertyInfo qdev_prop_taddr; -void qdev_prop_set_taddr(DeviceState *dev, const char *name, target_phys_addr_t value); +void qdev_prop_set_taddr(DeviceState *dev, const char *name, hwaddr value); + +#endif diff --git a/hw/qdev-core.h b/hw/qdev-core.h new file mode 100644 index 0000000000..fdf14ec4a6 --- /dev/null +++ b/hw/qdev-core.h @@ -0,0 +1,224 @@ +#ifndef QDEV_CORE_H +#define QDEV_CORE_H + +#include "qemu/queue.h" +#include "qemu/option.h" +#include "qemu/typedefs.h" +#include "qom/object.h" +#include "hw/irq.h" +#include "qapi/error.h" + +enum DevState { + DEV_STATE_CREATED = 1, + DEV_STATE_INITIALIZED, +}; + +enum { + DEV_NVECTORS_UNSPECIFIED = -1, +}; + +#define TYPE_DEVICE "device" +#define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE) +#define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE) +#define DEVICE_GET_CLASS(obj) OBJECT_GET_CLASS(DeviceClass, (obj), TYPE_DEVICE) + +typedef int (*qdev_initfn)(DeviceState *dev); +typedef int (*qdev_event)(DeviceState *dev); +typedef void (*qdev_resetfn)(DeviceState *dev); + +struct VMStateDescription; + +typedef struct DeviceClass { + ObjectClass parent_class; + + const char *fw_name; + const char *desc; + Property *props; + int no_user; + + /* callbacks */ + void (*reset)(DeviceState *dev); + + /* device state */ + const struct VMStateDescription *vmsd; + + /* Private to qdev / bus. */ + qdev_initfn init; + qdev_event unplug; + qdev_event exit; + const char *bus_type; +} DeviceClass; + +/* This structure should not be accessed directly. We declare it here + so that it can be embedded in individual device state structures. */ +struct DeviceState { + Object parent_obj; + + const char *id; + enum DevState state; + QemuOpts *opts; + int hotplugged; + BusState *parent_bus; + int num_gpio_out; + qemu_irq *gpio_out; + int num_gpio_in; + qemu_irq *gpio_in; + QLIST_HEAD(, BusState) child_bus; + int num_child_bus; + int instance_id_alias; + int alias_required_for_version; +}; + +#define TYPE_BUS "bus" +#define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS) +#define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS) +#define BUS_GET_CLASS(obj) OBJECT_GET_CLASS(BusClass, (obj), TYPE_BUS) + +struct BusClass { + ObjectClass parent_class; + + /* FIXME first arg should be BusState */ + void (*print_dev)(Monitor *mon, DeviceState *dev, int indent); + char *(*get_dev_path)(DeviceState *dev); + /* + * This callback is used to create Open Firmware device path in accordance + * with OF spec http://forthworks.com/standards/of1275.pdf. Individual bus + * bindings can be found at http://playground.sun.com/1275/bindings/. + */ + char *(*get_fw_dev_path)(DeviceState *dev); + int (*reset)(BusState *bus); +}; + +typedef struct BusChild { + DeviceState *child; + int index; + QTAILQ_ENTRY(BusChild) sibling; +} BusChild; + +/** + * BusState: + */ +struct BusState { + Object obj; + DeviceState *parent; + const char *name; + int allow_hotplug; + int max_index; + QTAILQ_HEAD(ChildrenHead, BusChild) children; + QLIST_ENTRY(BusState) sibling; +}; + +struct Property { + const char *name; + PropertyInfo *info; + int offset; + uint8_t bitnr; + uint8_t qtype; + int64_t defval; +}; + +struct PropertyInfo { + const char *name; + const char *legacy_name; + const char **enum_table; + int (*parse)(DeviceState *dev, Property *prop, const char *str); + int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len); + ObjectPropertyAccessor *get; + ObjectPropertyAccessor *set; + ObjectPropertyRelease *release; +}; + +typedef struct GlobalProperty { + const char *driver; + const char *property; + const char *value; + QTAILQ_ENTRY(GlobalProperty) next; +} GlobalProperty; + +/*** Board API. This should go away once we have a machine config file. ***/ + +DeviceState *qdev_create(BusState *bus, const char *name); +DeviceState *qdev_try_create(BusState *bus, const char *name); +int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT; +void qdev_init_nofail(DeviceState *dev); +void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, + int required_for_version); +void qdev_unplug(DeviceState *dev, Error **errp); +void qdev_free(DeviceState *dev); +int qdev_simple_unplug_cb(DeviceState *dev); +void qdev_machine_creation_done(void); +bool qdev_machine_modified(void); + +qemu_irq qdev_get_gpio_in(DeviceState *dev, int n); +void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin); + +BusState *qdev_get_child_bus(DeviceState *dev, const char *name); + +/*** Device API. ***/ + +/* Register device properties. */ +/* GPIO inputs also double as IRQ sinks. */ +void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n); +void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n); + +BusState *qdev_get_parent_bus(DeviceState *dev); + +/*** BUS API. ***/ + +DeviceState *qdev_find_recursive(BusState *bus, const char *id); + +/* Returns 0 to walk children, > 0 to skip walk, < 0 to terminate walk. */ +typedef int (qbus_walkerfn)(BusState *bus, void *opaque); +typedef int (qdev_walkerfn)(DeviceState *dev, void *opaque); + +void qbus_create_inplace(BusState *bus, const char *typename, + DeviceState *parent, const char *name); +BusState *qbus_create(const char *typename, DeviceState *parent, const char *name); +/* Returns > 0 if either devfn or busfn skip walk somewhere in cursion, + * < 0 if either devfn or busfn terminate walk somewhere in cursion, + * 0 otherwise. */ +int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, + qbus_walkerfn *busfn, void *opaque); +int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn, + qbus_walkerfn *busfn, void *opaque); +void qdev_reset_all(DeviceState *dev); +void qbus_reset_all_fn(void *opaque); + +void qbus_free(BusState *bus); + +#define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev) + +/* This should go away once we get rid of the NULL bus hack */ +BusState *sysbus_get_default(void); + +char *qdev_get_fw_dev_path(DeviceState *dev); + +/** + * @qdev_machine_init + * + * Initialize platform devices before machine init. This is a hack until full + * support for composition is added. + */ +void qdev_machine_init(void); + +/** + * @device_reset + * + * Reset a single device (by calling the reset method). + */ +void device_reset(DeviceState *dev); + +const struct VMStateDescription *qdev_get_vmsd(DeviceState *dev); + +const char *qdev_fw_name(DeviceState *dev); + +Object *qdev_get_machine(void); + +/* FIXME: make this a link<> */ +void qdev_set_parent_bus(DeviceState *dev, BusState *bus); + +extern int qdev_hotplug; + +char *qdev_get_dev_path(DeviceState *dev); + +#endif diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c index 018b386782..b73986759b 100644 --- a/hw/qdev-monitor.c +++ b/hw/qdev-monitor.c @@ -18,9 +18,10 @@ */ #include "qdev.h" -#include "monitor.h" +#include "monitor/monitor.h" #include "qmp-commands.h" -#include "arch_init.h" +#include "sysemu/arch_init.h" +#include "qemu/config-file.h" /* * Aliases were a bad idea from the start. Let's keep them @@ -44,6 +45,7 @@ static const QDevAlias qdev_alias_table[] = { { "virtio-serial-s390", "virtio-serial", QEMU_ARCH_S390X }, { "lsi53c895a", "lsi" }, { "ich9-ahci", "ahci" }, + { "kvm-pci-assign", "pci-assign" }, { } }; @@ -288,8 +290,7 @@ static BusState *qbus_find_recursive(BusState *bus, const char *name, if (name && (strcmp(bus->name, name) != 0)) { match = 0; } - if (bus_typename && - (strcmp(object_get_typename(OBJECT(bus)), bus_typename) != 0)) { + if (bus_typename && !object_dynamic_cast(OBJECT(bus), bus_typename)) { match = 0; } if (match) { @@ -434,7 +435,7 @@ DeviceState *qdev_device_add(QemuOpts *opts) if (!bus) { return NULL; } - if (strcmp(object_get_typename(OBJECT(bus)), k->bus_type) != 0) { + if (!object_dynamic_cast(OBJECT(bus), k->bus_type)) { qerror_report(QERR_BAD_BUS_FOR_DEVICE, driver, object_get_typename(OBJECT(bus))); return NULL; @@ -543,7 +544,7 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent) qdev_print_props(mon, dev, DEVICE_CLASS(class)->props, indent); class = object_class_get_parent(class); } while (class != object_class_by_name(TYPE_DEVICE)); - bus_print_dev(dev->parent_bus, mon, dev, indent + 2); + bus_print_dev(dev->parent_bus, mon, dev, indent); QLIST_FOREACH(child, &dev->child_bus, sibling) { qbus_print(mon, child, indent); } diff --git a/hw/qdev-monitor.h b/hw/qdev-monitor.h new file mode 100644 index 0000000000..fae1b1ec84 --- /dev/null +++ b/hw/qdev-monitor.h @@ -0,0 +1,16 @@ +#ifndef QEMU_QDEV_MONITOR_H +#define QEMU_QDEV_MONITOR_H + +#include "qdev-core.h" +#include "monitor/monitor.h" + +/*** monitor commands ***/ + +void do_info_qtree(Monitor *mon); +void do_info_qdm(Monitor *mon); +int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data); +int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data); +int qdev_device_help(QemuOpts *opts); +DeviceState *qdev_device_add(QemuOpts *opts); + +#endif diff --git a/hw/qdev-properties-system.c b/hw/qdev-properties-system.c new file mode 100644 index 0000000000..c73c713080 --- /dev/null +++ b/hw/qdev-properties-system.c @@ -0,0 +1,358 @@ +/* + * qdev property parsing and global properties + * (parts specific for qemu-system-*) + * + * This file is based on code from hw/qdev-properties.c from + * commit 074a86fccd185616469dfcdc0e157f438aebba18, + * Copyright (c) Gerd Hoffmann <kraxel@redhat.com> and other contributors. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "net/net.h" +#include "qdev.h" +#include "qapi/qmp/qerror.h" +#include "sysemu/blockdev.h" +#include "hw/block-common.h" +#include "net/hub.h" +#include "qapi/visitor.h" +#include "char/char.h" + +static void get_pointer(Object *obj, Visitor *v, Property *prop, + const char *(*print)(void *ptr), + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + void **ptr = qdev_get_prop_ptr(dev, prop); + char *p; + + p = (char *) (*ptr ? print(*ptr) : ""); + visit_type_str(v, &p, name, errp); +} + +static void set_pointer(Object *obj, Visitor *v, Property *prop, + int (*parse)(DeviceState *dev, const char *str, + void **ptr), + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Error *local_err = NULL; + void **ptr = qdev_get_prop_ptr(dev, prop); + char *str; + int ret; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_str(v, &str, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (!*str) { + g_free(str); + *ptr = NULL; + return; + } + ret = parse(dev, str, ptr); + error_set_from_qdev_prop_error(errp, ret, dev, prop, str); + g_free(str); +} + +/* --- drive --- */ + +static int parse_drive(DeviceState *dev, const char *str, void **ptr) +{ + BlockDriverState *bs; + + bs = bdrv_find(str); + if (bs == NULL) { + return -ENOENT; + } + if (bdrv_attach_dev(bs, dev) < 0) { + return -EEXIST; + } + *ptr = bs; + return 0; +} + +static void release_drive(Object *obj, const char *name, void *opaque) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); + + if (*ptr) { + bdrv_detach_dev(*ptr, dev); + blockdev_auto_del(*ptr); + } +} + +static const char *print_drive(void *ptr) +{ + return bdrv_get_device_name(ptr); +} + +static void get_drive(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_drive, name, errp); +} + +static void set_drive(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_drive, name, errp); +} + +PropertyInfo qdev_prop_drive = { + .name = "drive", + .get = get_drive, + .set = set_drive, + .release = release_drive, +}; + +/* --- character device --- */ + +static int parse_chr(DeviceState *dev, const char *str, void **ptr) +{ + CharDriverState *chr = qemu_chr_find(str); + if (chr == NULL) { + return -ENOENT; + } + if (chr->avail_connections < 1) { + return -EEXIST; + } + *ptr = chr; + --chr->avail_connections; + return 0; +} + +static void release_chr(Object *obj, const char *name, void *opaque) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); + + if (*ptr) { + qemu_chr_add_handlers(*ptr, NULL, NULL, NULL, NULL); + } +} + + +static const char *print_chr(void *ptr) +{ + CharDriverState *chr = ptr; + + return chr->label ? chr->label : ""; +} + +static void get_chr(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_chr, name, errp); +} + +static void set_chr(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_chr, name, errp); +} + +PropertyInfo qdev_prop_chr = { + .name = "chr", + .get = get_chr, + .set = set_chr, + .release = release_chr, +}; + +/* --- netdev device --- */ + +static int parse_netdev(DeviceState *dev, const char *str, void **ptr) +{ + NetClientState *netdev = qemu_find_netdev(str); + + if (netdev == NULL) { + return -ENOENT; + } + if (netdev->peer) { + return -EEXIST; + } + *ptr = netdev; + return 0; +} + +static const char *print_netdev(void *ptr) +{ + NetClientState *netdev = ptr; + + return netdev->name ? netdev->name : ""; +} + +static void get_netdev(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_netdev, name, errp); +} + +static void set_netdev(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_netdev, name, errp); +} + +PropertyInfo qdev_prop_netdev = { + .name = "netdev", + .get = get_netdev, + .set = set_netdev, +}; + +/* --- vlan --- */ + +static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + NetClientState **ptr = qdev_get_prop_ptr(dev, prop); + + if (*ptr) { + int id; + if (!net_hub_id_for_client(*ptr, &id)) { + return snprintf(dest, len, "%d", id); + } + } + + return snprintf(dest, len, "<null>"); +} + +static void get_vlan(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + NetClientState **ptr = qdev_get_prop_ptr(dev, prop); + int32_t id = -1; + + if (*ptr) { + int hub_id; + if (!net_hub_id_for_client(*ptr, &hub_id)) { + id = hub_id; + } + } + + visit_type_int32(v, &id, name, errp); +} + +static void set_vlan(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + NetClientState **ptr = qdev_get_prop_ptr(dev, prop); + Error *local_err = NULL; + int32_t id; + NetClientState *hubport; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_int32(v, &id, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (id == -1) { + *ptr = NULL; + return; + } + + hubport = net_hub_port_find(id); + if (!hubport) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, + name, prop->info->name); + return; + } + *ptr = hubport; +} + +PropertyInfo qdev_prop_vlan = { + .name = "vlan", + .print = print_vlan, + .get = get_vlan, + .set = set_vlan, +}; + +int qdev_prop_set_drive(DeviceState *dev, const char *name, + BlockDriverState *value) +{ + Error *errp = NULL; + const char *bdrv_name = value ? bdrv_get_device_name(value) : ""; + object_property_set_str(OBJECT(dev), bdrv_name, + name, &errp); + if (errp) { + qerror_report_err(errp); + error_free(errp); + return -1; + } + return 0; +} + +void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, + BlockDriverState *value) +{ + if (qdev_prop_set_drive(dev, name, value) < 0) { + exit(1); + } +} +void qdev_prop_set_chr(DeviceState *dev, const char *name, + CharDriverState *value) +{ + Error *errp = NULL; + assert(!value || value->label); + object_property_set_str(OBJECT(dev), + value ? value->label : "", name, &errp); + assert_no_error(errp); +} + +void qdev_prop_set_netdev(DeviceState *dev, const char *name, + NetClientState *value) +{ + Error *errp = NULL; + assert(!value || value->name); + object_property_set_str(OBJECT(dev), + value ? value->name : "", name, &errp); + assert_no_error(errp); +} + +void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) +{ + qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a); + if (nd->netdev) { + qdev_prop_set_netdev(dev, "netdev", nd->netdev); + } + if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED && + object_property_find(OBJECT(dev), "vectors", NULL)) { + qdev_prop_set_uint32(dev, "vectors", nd->nvectors); + } + nd->instantiated = 1; +} + +static int qdev_add_one_global(QemuOpts *opts, void *opaque) +{ + GlobalProperty *g; + + g = g_malloc0(sizeof(*g)); + g->driver = qemu_opt_get(opts, "driver"); + g->property = qemu_opt_get(opts, "property"); + g->value = qemu_opt_get(opts, "value"); + qdev_prop_register_global(g); + return 0; +} + +void qemu_add_globals(void) +{ + qemu_opts_foreach(qemu_find_opts("global"), qdev_add_one_global, NULL, 0); +} diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index 8aca0d43fe..f724357ccb 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -1,9 +1,11 @@ -#include "net.h" +#include "net/net.h" #include "qdev.h" -#include "qerror.h" -#include "blockdev.h" +#include "qapi/qmp/qerror.h" +#include "sysemu/blockdev.h" #include "hw/block-common.h" #include "net/hub.h" +#include "qapi/visitor.h" +#include "char/char.h" void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) { @@ -12,49 +14,6 @@ void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) return ptr; } -static void get_pointer(Object *obj, Visitor *v, Property *prop, - const char *(*print)(void *ptr), - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - void **ptr = qdev_get_prop_ptr(dev, prop); - char *p; - - p = (char *) (*ptr ? print(*ptr) : ""); - visit_type_str(v, &p, name, errp); -} - -static void set_pointer(Object *obj, Visitor *v, Property *prop, - int (*parse)(DeviceState *dev, const char *str, - void **ptr), - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Error *local_err = NULL; - void **ptr = qdev_get_prop_ptr(dev, prop); - char *str; - int ret; - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_str(v, &str, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - if (!*str) { - g_free(str); - *ptr = NULL; - return; - } - ret = parse(dev, str, ptr); - error_set_from_qdev_prop_error(errp, ret, dev, prop, str); - g_free(str); -} - static void get_enum(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { @@ -94,10 +53,11 @@ static void bit_prop_set(DeviceState *dev, Property *props, bool val) { uint32_t *p = qdev_get_prop_ptr(dev, props); uint32_t mask = qdev_get_prop_mask(props); - if (val) + if (val) { *p |= mask; - else + } else { *p &= ~mask; + } } static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) @@ -419,11 +379,13 @@ static void release_string(Object *obj, const char *name, void *opaque) g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop)); } -static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len) +static int print_string(DeviceState *dev, Property *prop, char *dest, + size_t len) { char **ptr = qdev_get_prop_ptr(dev, prop); - if (!*ptr) + if (!*ptr) { return snprintf(dest, len, "<null>"); + } return snprintf(dest, len, "\"%s\"", *ptr); } @@ -475,227 +437,6 @@ PropertyInfo qdev_prop_string = { .set = set_string, }; -/* --- drive --- */ - -static int parse_drive(DeviceState *dev, const char *str, void **ptr) -{ - BlockDriverState *bs; - - bs = bdrv_find(str); - if (bs == NULL) - return -ENOENT; - if (bdrv_attach_dev(bs, dev) < 0) - return -EEXIST; - *ptr = bs; - return 0; -} - -static void release_drive(Object *obj, const char *name, void *opaque) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); - - if (*ptr) { - bdrv_detach_dev(*ptr, dev); - blockdev_auto_del(*ptr); - } -} - -static const char *print_drive(void *ptr) -{ - return bdrv_get_device_name(ptr); -} - -static void get_drive(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - get_pointer(obj, v, opaque, print_drive, name, errp); -} - -static void set_drive(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - set_pointer(obj, v, opaque, parse_drive, name, errp); -} - -PropertyInfo qdev_prop_drive = { - .name = "drive", - .get = get_drive, - .set = set_drive, - .release = release_drive, -}; - -/* --- character device --- */ - -static int parse_chr(DeviceState *dev, const char *str, void **ptr) -{ - CharDriverState *chr = qemu_chr_find(str); - if (chr == NULL) { - return -ENOENT; - } - if (chr->avail_connections < 1) { - return -EEXIST; - } - *ptr = chr; - --chr->avail_connections; - return 0; -} - -static void release_chr(Object *obj, const char *name, void *opaque) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); - - if (*ptr) { - qemu_chr_add_handlers(*ptr, NULL, NULL, NULL, NULL); - } -} - - -static const char *print_chr(void *ptr) -{ - CharDriverState *chr = ptr; - - return chr->label ? chr->label : ""; -} - -static void get_chr(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - get_pointer(obj, v, opaque, print_chr, name, errp); -} - -static void set_chr(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - set_pointer(obj, v, opaque, parse_chr, name, errp); -} - -PropertyInfo qdev_prop_chr = { - .name = "chr", - .get = get_chr, - .set = set_chr, - .release = release_chr, -}; - -/* --- netdev device --- */ - -static int parse_netdev(DeviceState *dev, const char *str, void **ptr) -{ - NetClientState *netdev = qemu_find_netdev(str); - - if (netdev == NULL) { - return -ENOENT; - } - if (netdev->peer) { - return -EEXIST; - } - *ptr = netdev; - return 0; -} - -static const char *print_netdev(void *ptr) -{ - NetClientState *netdev = ptr; - - return netdev->name ? netdev->name : ""; -} - -static void get_netdev(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - get_pointer(obj, v, opaque, print_netdev, name, errp); -} - -static void set_netdev(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - set_pointer(obj, v, opaque, parse_netdev, name, errp); -} - -PropertyInfo qdev_prop_netdev = { - .name = "netdev", - .get = get_netdev, - .set = set_netdev, -}; - -/* --- vlan --- */ - -static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - NetClientState **ptr = qdev_get_prop_ptr(dev, prop); - - if (*ptr) { - int id; - if (!net_hub_id_for_client(*ptr, &id)) { - return snprintf(dest, len, "%d", id); - } - } - - return snprintf(dest, len, "<null>"); -} - -static void get_vlan(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - NetClientState **ptr = qdev_get_prop_ptr(dev, prop); - int32_t id = -1; - - if (*ptr) { - int hub_id; - if (!net_hub_id_for_client(*ptr, &hub_id)) { - id = hub_id; - } - } - - visit_type_int32(v, &id, name, errp); -} - -static void set_vlan(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - NetClientState **ptr = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; - int32_t id; - NetClientState *hubport; - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_int32(v, &id, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - if (id == -1) { - *ptr = NULL; - return; - } - - hubport = net_hub_port_find(id); - if (!hubport) { - error_set(errp, QERR_INVALID_PARAMETER_VALUE, - name, prop->info->name); - return; - } - *ptr = hubport; -} - -PropertyInfo qdev_prop_vlan = { - .name = "vlan", - .print = print_vlan, - .get = get_vlan, - .set = set_vlan, -}; - /* --- pointer --- */ /* Not a proper property, just for dirty hacks. TODO Remove it! */ @@ -748,16 +489,20 @@ static void set_mac(Object *obj, Visitor *v, void *opaque, } for (i = 0, pos = 0; i < 6; i++, pos += 3) { - if (!qemu_isxdigit(str[pos])) + if (!qemu_isxdigit(str[pos])) { goto inval; - if (!qemu_isxdigit(str[pos+1])) + } + if (!qemu_isxdigit(str[pos+1])) { goto inval; + } if (i == 5) { - if (str[pos+2] != '\0') + if (str[pos+2] != '\0') { goto inval; + } } else { - if (str[pos+2] != ':' && str[pos+2] != '-') + if (str[pos+2] != ':' && str[pos+2] != '-') { goto inval; + } } mac->a[i] = strtol(str+pos, &p, 16); } @@ -863,7 +608,8 @@ invalid: g_free(str); } -static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) +static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, + size_t len) { int32_t *ptr = qdev_get_prop_ptr(dev, prop); @@ -1037,11 +783,13 @@ PropertyInfo qdev_prop_pci_host_devaddr = { static Property *qdev_prop_walk(Property *props, const char *name) { - if (!props) + if (!props) { return NULL; + } while (props->name) { - if (strcmp(props->name, name) == 0) + if (strcmp(props->name, name) == 0) { return props; + } props++; } return NULL; @@ -1157,44 +905,6 @@ void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value) assert_no_error(errp); } -int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) -{ - Error *errp = NULL; - const char *bdrv_name = value ? bdrv_get_device_name(value) : ""; - object_property_set_str(OBJECT(dev), bdrv_name, - name, &errp); - if (errp) { - qerror_report_err(errp); - error_free(errp); - return -1; - } - return 0; -} - -void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value) -{ - if (qdev_prop_set_drive(dev, name, value) < 0) { - exit(1); - } -} -void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value) -{ - Error *errp = NULL; - assert(!value || value->label); - object_property_set_str(OBJECT(dev), - value ? value->label : "", name, &errp); - assert_no_error(errp); -} - -void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *value) -{ - Error *errp = NULL; - assert(!value || value->name); - object_property_set_str(OBJECT(dev), - value ? value->name : "", name, &errp); - assert_no_error(errp); -} - void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value) { Error *errp = NULL; @@ -1228,9 +938,10 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) *ptr = value; } -static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props); +static QTAILQ_HEAD(, GlobalProperty) global_props = + QTAILQ_HEAD_INITIALIZER(global_props); -static void qdev_prop_register_global(GlobalProperty *prop) +void qdev_prop_register_global(GlobalProperty *prop) { QTAILQ_INSERT_TAIL(&global_props, prop, next); } @@ -1261,20 +972,3 @@ void qdev_prop_set_globals(DeviceState *dev) class = object_class_get_parent(class); } while (class); } - -static int qdev_add_one_global(QemuOpts *opts, void *opaque) -{ - GlobalProperty *g; - - g = g_malloc0(sizeof(*g)); - g->driver = qemu_opt_get(opts, "driver"); - g->property = qemu_opt_get(opts, "property"); - g->value = qemu_opt_get(opts, "value"); - qdev_prop_register_global(g); - return 0; -} - -void qemu_add_globals(void) -{ - qemu_opts_foreach(qemu_find_opts("global"), qdev_add_one_global, NULL, 0); -} diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h new file mode 100644 index 0000000000..ddcf774506 --- /dev/null +++ b/hw/qdev-properties.h @@ -0,0 +1,131 @@ +#ifndef QEMU_QDEV_PROPERTIES_H +#define QEMU_QDEV_PROPERTIES_H + +#include "qdev-core.h" + +/*** qdev-properties.c ***/ + +extern PropertyInfo qdev_prop_bit; +extern PropertyInfo qdev_prop_uint8; +extern PropertyInfo qdev_prop_uint16; +extern PropertyInfo qdev_prop_uint32; +extern PropertyInfo qdev_prop_int32; +extern PropertyInfo qdev_prop_uint64; +extern PropertyInfo qdev_prop_hex8; +extern PropertyInfo qdev_prop_hex32; +extern PropertyInfo qdev_prop_hex64; +extern PropertyInfo qdev_prop_string; +extern PropertyInfo qdev_prop_chr; +extern PropertyInfo qdev_prop_ptr; +extern PropertyInfo qdev_prop_macaddr; +extern PropertyInfo qdev_prop_losttickpolicy; +extern PropertyInfo qdev_prop_bios_chs_trans; +extern PropertyInfo qdev_prop_drive; +extern PropertyInfo qdev_prop_netdev; +extern PropertyInfo qdev_prop_vlan; +extern PropertyInfo qdev_prop_pci_devfn; +extern PropertyInfo qdev_prop_blocksize; +extern PropertyInfo qdev_prop_pci_host_devaddr; + +#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \ + .name = (_name), \ + .info = &(_prop), \ + .offset = offsetof(_state, _field) \ + + type_check(_type,typeof_field(_state, _field)), \ + } +#define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \ + .name = (_name), \ + .info = &(_prop), \ + .offset = offsetof(_state, _field) \ + + type_check(_type,typeof_field(_state, _field)), \ + .qtype = QTYPE_QINT, \ + .defval = (_type)_defval, \ + } +#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) { \ + .name = (_name), \ + .info = &(qdev_prop_bit), \ + .bitnr = (_bit), \ + .offset = offsetof(_state, _field) \ + + type_check(uint32_t,typeof_field(_state, _field)), \ + .qtype = QTYPE_QBOOL, \ + .defval = (bool)_defval, \ + } + +#define DEFINE_PROP_UINT8(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t) +#define DEFINE_PROP_UINT16(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint16, uint16_t) +#define DEFINE_PROP_UINT32(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint32, uint32_t) +#define DEFINE_PROP_INT32(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_int32, int32_t) +#define DEFINE_PROP_UINT64(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint64, uint64_t) +#define DEFINE_PROP_HEX8(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex8, uint8_t) +#define DEFINE_PROP_HEX32(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t) +#define DEFINE_PROP_HEX64(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t) +#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t) + +#define DEFINE_PROP_PTR(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*) +#define DEFINE_PROP_CHR(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharDriverState*) +#define DEFINE_PROP_STRING(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*) +#define DEFINE_PROP_NETDEV(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NetClientState*) +#define DEFINE_PROP_VLAN(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NetClientState*) +#define DEFINE_PROP_DRIVE(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *) +#define DEFINE_PROP_MACADDR(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr) +#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \ + LostTickPolicy) +#define DEFINE_PROP_BIOS_CHS_TRANS(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int) +#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t) +#define DEFINE_PROP_PCI_HOST_DEVADDR(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_pci_host_devaddr, PCIHostDeviceAddress) + +#define DEFINE_PROP_END_OF_LIST() \ + {} + +/* Set properties between creation and init. */ +void *qdev_get_prop_ptr(DeviceState *dev, Property *prop); +int qdev_prop_parse(DeviceState *dev, const char *name, const char *value); +void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value); +void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value); +void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value); +void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value); +void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value); +void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value); +void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value); +void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value); +void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *value); +int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT; +void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value); +void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value); +void qdev_prop_set_enum(DeviceState *dev, const char *name, int value); +/* FIXME: Remove opaque pointer properties. */ +void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value); + +void qdev_prop_register_global(GlobalProperty *prop); +void qdev_prop_register_global_list(GlobalProperty *props); +void qdev_prop_set_globals(DeviceState *dev); +void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, + Property *prop, const char *value); + +/** + * @qdev_property_add_static - add a @Property to a device referencing a + * field in a struct. + */ +void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp); + +#endif @@ -25,16 +25,15 @@ inherit from a particular bus (e.g. PCI or I2C) rather than this API directly. */ -#include "net.h" #include "qdev.h" -#include "sysemu.h" -#include "error.h" +#include "sysemu/sysemu.h" +#include "qapi/error.h" +#include "qapi/visitor.h" int qdev_hotplug = 0; static bool qdev_hot_added = false; static bool qdev_hot_removed = false; -/* Register a new device type. */ const VMStateDescription *qdev_get_vmsd(DeviceState *dev) { DeviceClass *dc = DEVICE_GET_CLASS(dev); @@ -52,11 +51,6 @@ const char *qdev_fw_name(DeviceState *dev) return object_get_typename(OBJECT(dev)); } -bool qdev_exists(const char *name) -{ - return !!object_class_by_name(name); -} - static void qdev_property_add_legacy(DeviceState *dev, Property *prop, Error **errp); @@ -114,10 +108,12 @@ DeviceState *qdev_create(BusState *bus, const char *name) dev = qdev_try_create(bus, name); if (!dev) { if (bus) { - hw_error("Unknown device '%s' for bus '%s'\n", name, - object_get_typename(OBJECT(bus))); + error_report("Unknown device '%s' for bus '%s'\n", name, + object_get_typename(OBJECT(bus))); + abort(); } else { - hw_error("Unknown device '%s' for default sysbus\n", name); + error_report("Unknown device '%s' for default sysbus\n", name); + abort(); } } @@ -159,7 +155,6 @@ int qdev_init(DeviceState *dev) rc = dc->init(dev); if (rc < 0) { - object_unparent(OBJECT(dev)); qdev_free(dev); return rc; } @@ -243,7 +238,6 @@ void qbus_reset_all_fn(void *opaque) int qdev_simple_unplug_cb(DeviceState *dev) { /* just zap it */ - object_unparent(OBJECT(dev)); qdev_free(dev); return 0; } @@ -293,9 +287,9 @@ BusState *qdev_get_parent_bus(DeviceState *dev) void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n) { - assert(dev->num_gpio_in == 0); - dev->num_gpio_in = n; - dev->gpio_in = qemu_allocate_irqs(handler, dev, n); + dev->gpio_in = qemu_extend_irqs(dev->gpio_in, dev->num_gpio_in, handler, + dev, n); + dev->num_gpio_in += n; } void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n) @@ -317,18 +311,6 @@ void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin) dev->gpio_out[n] = pin; } -void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) -{ - qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a); - if (nd->netdev) - qdev_prop_set_netdev(dev, "netdev", nd->netdev); - if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED && - object_property_find(OBJECT(dev), "vectors", NULL)) { - qdev_prop_set_uint32(dev, "vectors", nd->nvectors); - } - nd->instantiated = 1; -} - BusState *qdev_get_child_bus(DeviceState *dev, const char *name) { BusState *bus; @@ -461,7 +443,6 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam BusState *bus; bus = BUS(object_new(typename)); - bus->qom_allocated = true; bus->parent = parent; bus->name = name ? g_strdup(name) : NULL; @@ -472,14 +453,7 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam void qbus_free(BusState *bus) { - if (bus->qom_allocated) { - object_delete(OBJECT(bus)); - } else { - object_finalize(OBJECT(bus)); - if (bus->glib_allocated) { - g_free(bus); - } - } + object_delete(OBJECT(bus)); } static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev) @@ -522,7 +496,7 @@ char* qdev_get_fw_dev_path(DeviceState *dev) path[l-1] = '\0'; - return strdup(path); + return g_strdup(path); } char *qdev_get_dev_path(DeviceState *dev) @@ -712,9 +686,6 @@ static void device_finalize(Object *obj) qemu_opts_del(dev->opts); } } - if (dev->parent_bus) { - bus_remove_child(dev->parent_bus, dev); - } } static void device_class_base_init(ObjectClass *class, void *data) @@ -727,6 +698,20 @@ static void device_class_base_init(ObjectClass *class, void *data) klass->props = NULL; } +static void device_unparent(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + + if (dev->parent_bus != NULL) { + bus_remove_child(dev->parent_bus, dev); + } +} + +static void device_class_init(ObjectClass *class, void *data) +{ + class->unparent = device_unparent; +} + void device_reset(DeviceState *dev) { DeviceClass *klass = DEVICE_GET_CLASS(dev); @@ -754,6 +739,7 @@ static TypeInfo device_type_info = { .instance_init = device_initfn, .instance_finalize = device_finalize, .class_base_init = device_class_base_init, + .class_init = device_class_init, .abstract = true, .class_size = sizeof(DeviceClass), }; @@ -1,372 +1,9 @@ #ifndef QDEV_H #define QDEV_H -#include "hw.h" -#include "qemu-queue.h" -#include "qemu-char.h" -#include "qemu-option.h" -#include "qapi/qapi-visit-core.h" -#include "qemu/object.h" -#include "error.h" - -typedef struct Property Property; - -typedef struct PropertyInfo PropertyInfo; - -typedef struct CompatProperty CompatProperty; - -typedef struct BusState BusState; - -typedef struct BusClass BusClass; - -enum DevState { - DEV_STATE_CREATED = 1, - DEV_STATE_INITIALIZED, -}; - -enum { - DEV_NVECTORS_UNSPECIFIED = -1, -}; - -#define TYPE_DEVICE "device" -#define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE) -#define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE) -#define DEVICE_GET_CLASS(obj) OBJECT_GET_CLASS(DeviceClass, (obj), TYPE_DEVICE) - -typedef int (*qdev_initfn)(DeviceState *dev); -typedef int (*qdev_event)(DeviceState *dev); -typedef void (*qdev_resetfn)(DeviceState *dev); - -typedef struct DeviceClass { - ObjectClass parent_class; - - const char *fw_name; - const char *desc; - Property *props; - int no_user; - - /* callbacks */ - void (*reset)(DeviceState *dev); - - /* device state */ - const VMStateDescription *vmsd; - - /* Private to qdev / bus. */ - qdev_initfn init; - qdev_event unplug; - qdev_event exit; - const char *bus_type; -} DeviceClass; - -/* This structure should not be accessed directly. We declare it here - so that it can be embedded in individual device state structures. */ -struct DeviceState { - Object parent_obj; - - const char *id; - enum DevState state; - QemuOpts *opts; - int hotplugged; - BusState *parent_bus; - int num_gpio_out; - qemu_irq *gpio_out; - int num_gpio_in; - qemu_irq *gpio_in; - QLIST_HEAD(, BusState) child_bus; - int num_child_bus; - int instance_id_alias; - int alias_required_for_version; -}; - -#define TYPE_BUS "bus" -#define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS) -#define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS) -#define BUS_GET_CLASS(obj) OBJECT_GET_CLASS(BusClass, (obj), TYPE_BUS) - -struct BusClass { - ObjectClass parent_class; - - /* FIXME first arg should be BusState */ - void (*print_dev)(Monitor *mon, DeviceState *dev, int indent); - char *(*get_dev_path)(DeviceState *dev); - /* - * This callback is used to create Open Firmware device path in accordance - * with OF spec http://forthworks.com/standards/of1275.pdf. Individual bus - * bindings can be found at http://playground.sun.com/1275/bindings/. - */ - char *(*get_fw_dev_path)(DeviceState *dev); - int (*reset)(BusState *bus); -}; - -typedef struct BusChild { - DeviceState *child; - int index; - QTAILQ_ENTRY(BusChild) sibling; -} BusChild; - -/** - * BusState: - * @qom_allocated: Indicates whether the object was allocated by QOM. - * @glib_allocated: Indicates whether the object was initialized in-place - * yet is expected to be freed with g_free(). - */ -struct BusState { - Object obj; - DeviceState *parent; - const char *name; - int allow_hotplug; - bool qom_allocated; - bool glib_allocated; - int max_index; - QTAILQ_HEAD(ChildrenHead, BusChild) children; - QLIST_ENTRY(BusState) sibling; -}; - -struct Property { - const char *name; - PropertyInfo *info; - int offset; - uint8_t bitnr; - uint8_t qtype; - int64_t defval; -}; - -struct PropertyInfo { - const char *name; - const char *legacy_name; - const char **enum_table; - int (*parse)(DeviceState *dev, Property *prop, const char *str); - int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len); - ObjectPropertyAccessor *get; - ObjectPropertyAccessor *set; - ObjectPropertyRelease *release; -}; - -typedef struct GlobalProperty { - const char *driver; - const char *property; - const char *value; - QTAILQ_ENTRY(GlobalProperty) next; -} GlobalProperty; - -/*** Board API. This should go away once we have a machine config file. ***/ - -DeviceState *qdev_create(BusState *bus, const char *name); -DeviceState *qdev_try_create(BusState *bus, const char *name); -bool qdev_exists(const char *name); -int qdev_device_help(QemuOpts *opts); -DeviceState *qdev_device_add(QemuOpts *opts); -int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT; -void qdev_init_nofail(DeviceState *dev); -void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, - int required_for_version); -void qdev_unplug(DeviceState *dev, Error **errp); -void qdev_free(DeviceState *dev); -int qdev_simple_unplug_cb(DeviceState *dev); -void qdev_machine_creation_done(void); -bool qdev_machine_modified(void); - -qemu_irq qdev_get_gpio_in(DeviceState *dev, int n); -void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin); - -BusState *qdev_get_child_bus(DeviceState *dev, const char *name); - -/*** Device API. ***/ - -/* Register device properties. */ -/* GPIO inputs also double as IRQ sinks. */ -void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n); -void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n); - -BusState *qdev_get_parent_bus(DeviceState *dev); - -/*** BUS API. ***/ - -DeviceState *qdev_find_recursive(BusState *bus, const char *id); - -/* Returns 0 to walk children, > 0 to skip walk, < 0 to terminate walk. */ -typedef int (qbus_walkerfn)(BusState *bus, void *opaque); -typedef int (qdev_walkerfn)(DeviceState *dev, void *opaque); - -void qbus_create_inplace(BusState *bus, const char *typename, - DeviceState *parent, const char *name); -BusState *qbus_create(const char *typename, DeviceState *parent, const char *name); -/* Returns > 0 if either devfn or busfn skip walk somewhere in cursion, - * < 0 if either devfn or busfn terminate walk somewhere in cursion, - * 0 otherwise. */ -int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, - qbus_walkerfn *busfn, void *opaque); -int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn, - qbus_walkerfn *busfn, void *opaque); -void qdev_reset_all(DeviceState *dev); -void qbus_reset_all_fn(void *opaque); - -void qbus_free(BusState *bus); - -#define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev) - -/* This should go away once we get rid of the NULL bus hack */ -BusState *sysbus_get_default(void); - -/*** monitor commands ***/ - -void do_info_qtree(Monitor *mon); -void do_info_qdm(Monitor *mon); -int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data); -int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data); - -/*** qdev-properties.c ***/ - -extern PropertyInfo qdev_prop_bit; -extern PropertyInfo qdev_prop_uint8; -extern PropertyInfo qdev_prop_uint16; -extern PropertyInfo qdev_prop_uint32; -extern PropertyInfo qdev_prop_int32; -extern PropertyInfo qdev_prop_uint64; -extern PropertyInfo qdev_prop_hex8; -extern PropertyInfo qdev_prop_hex32; -extern PropertyInfo qdev_prop_hex64; -extern PropertyInfo qdev_prop_string; -extern PropertyInfo qdev_prop_chr; -extern PropertyInfo qdev_prop_ptr; -extern PropertyInfo qdev_prop_macaddr; -extern PropertyInfo qdev_prop_losttickpolicy; -extern PropertyInfo qdev_prop_bios_chs_trans; -extern PropertyInfo qdev_prop_drive; -extern PropertyInfo qdev_prop_netdev; -extern PropertyInfo qdev_prop_vlan; -extern PropertyInfo qdev_prop_pci_devfn; -extern PropertyInfo qdev_prop_blocksize; -extern PropertyInfo qdev_prop_pci_host_devaddr; - -#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \ - .name = (_name), \ - .info = &(_prop), \ - .offset = offsetof(_state, _field) \ - + type_check(_type,typeof_field(_state, _field)), \ - } -#define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \ - .name = (_name), \ - .info = &(_prop), \ - .offset = offsetof(_state, _field) \ - + type_check(_type,typeof_field(_state, _field)), \ - .qtype = QTYPE_QINT, \ - .defval = (_type)_defval, \ - } -#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) { \ - .name = (_name), \ - .info = &(qdev_prop_bit), \ - .bitnr = (_bit), \ - .offset = offsetof(_state, _field) \ - + type_check(uint32_t,typeof_field(_state, _field)), \ - .qtype = QTYPE_QBOOL, \ - .defval = (bool)_defval, \ - } - -#define DEFINE_PROP_UINT8(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t) -#define DEFINE_PROP_UINT16(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint16, uint16_t) -#define DEFINE_PROP_UINT32(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint32, uint32_t) -#define DEFINE_PROP_INT32(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_int32, int32_t) -#define DEFINE_PROP_UINT64(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint64, uint64_t) -#define DEFINE_PROP_HEX8(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex8, uint8_t) -#define DEFINE_PROP_HEX32(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t) -#define DEFINE_PROP_HEX64(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t) -#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t) - -#define DEFINE_PROP_PTR(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*) -#define DEFINE_PROP_CHR(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharDriverState*) -#define DEFINE_PROP_STRING(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*) -#define DEFINE_PROP_NETDEV(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NetClientState*) -#define DEFINE_PROP_VLAN(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NetClientState*) -#define DEFINE_PROP_DRIVE(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *) -#define DEFINE_PROP_MACADDR(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr) -#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \ - LostTickPolicy) -#define DEFINE_PROP_BIOS_CHS_TRANS(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int) -#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t) -#define DEFINE_PROP_PCI_HOST_DEVADDR(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_pci_host_devaddr, PCIHostDeviceAddress) - -#define DEFINE_PROP_END_OF_LIST() \ - {} - -/* Set properties between creation and init. */ -void *qdev_get_prop_ptr(DeviceState *dev, Property *prop); -int qdev_prop_parse(DeviceState *dev, const char *name, const char *value); -void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value); -void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value); -void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value); -void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value); -void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value); -void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value); -void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value); -void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value); -void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *value); -int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT; -void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value); -void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value); -void qdev_prop_set_enum(DeviceState *dev, const char *name, int value); -/* FIXME: Remove opaque pointer properties. */ -void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value); - -void qdev_prop_register_global_list(GlobalProperty *props); -void qdev_prop_set_globals(DeviceState *dev); -void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, - Property *prop, const char *value); - -char *qdev_get_fw_dev_path(DeviceState *dev); - -/** - * @qdev_property_add_static - add a @Property to a device referencing a - * field in a struct. - */ -void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp); - -/** - * @qdev_machine_init - * - * Initialize platform devices before machine init. This is a hack until full - * support for composition is added. - */ -void qdev_machine_init(void); - -/** - * @device_reset - * - * Reset a single device (by calling the reset method). - */ -void device_reset(DeviceState *dev); - -const VMStateDescription *qdev_get_vmsd(DeviceState *dev); - -const char *qdev_fw_name(DeviceState *dev); - -Object *qdev_get_machine(void); - -/* FIXME: make this a link<> */ -void qdev_set_parent_bus(DeviceState *dev, BusState *bus); - -extern int qdev_hotplug; - -char *qdev_get_dev_path(DeviceState *dev); +#include "hw/hw.h" +#include "qdev-core.h" +#include "qdev-properties.h" +#include "qdev-monitor.h" #endif diff --git a/hw/qxl-logger.c b/hw/qxl-logger.c index fe2878c836..3cd85d9b97 100644 --- a/hw/qxl-logger.c +++ b/hw/qxl-logger.c @@ -19,7 +19,7 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "qemu-timer.h" +#include "qemu/timer.h" #include "qxl.h" static const char *qxl_type[] = { diff --git a/hw/qxl-render.c b/hw/qxl-render.c index e2e3fe2d37..88e63f8085 100644 --- a/hw/qxl-render.c +++ b/hw/qxl-render.c @@ -24,7 +24,7 @@ static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) { uint8_t *src; - uint8_t *dst = qxl->vga.ds->surface->data; + uint8_t *dst = ds_get_data(qxl->vga.ds); int len, i; if (is_buffer_shared(qxl->vga.ds->surface)) { @@ -99,7 +99,6 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) { VGACommonState *vga = &qxl->vga; int i; - DisplaySurface *surface = vga->ds->surface; if (qxl->guest_primary.resized) { qxl->guest_primary.resized = 0; @@ -112,32 +111,30 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) qxl->guest_primary.qxl_stride, qxl->guest_primary.bytes_pp, qxl->guest_primary.bits_pp); - } - if (surface->width != qxl->guest_primary.surface.width || - surface->height != qxl->guest_primary.surface.height) { if (qxl->guest_primary.qxl_stride > 0) { qemu_free_displaysurface(vga->ds); - qemu_create_displaysurface_from(qxl->guest_primary.surface.width, - qxl->guest_primary.surface.height, - qxl->guest_primary.bits_pp, - qxl->guest_primary.abs_stride, - qxl->guest_primary.data); + vga->ds->surface = qemu_create_displaysurface_from + (qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height, + qxl->guest_primary.bits_pp, + qxl->guest_primary.abs_stride, + qxl->guest_primary.data); } else { qemu_resize_displaysurface(vga->ds, qxl->guest_primary.surface.width, qxl->guest_primary.surface.height); } - dpy_resize(vga->ds); + dpy_gfx_resize(vga->ds); } for (i = 0; i < qxl->num_dirty_rects; i++) { if (qemu_spice_rect_is_empty(qxl->dirty+i)) { break; } qxl_blit(qxl, qxl->dirty+i); - dpy_update(vga->ds, - qxl->dirty[i].left, qxl->dirty[i].top, - qxl->dirty[i].right - qxl->dirty[i].left, - qxl->dirty[i].bottom - qxl->dirty[i].top); + dpy_gfx_update(vga->ds, + qxl->dirty[i].left, qxl->dirty[i].top, + qxl->dirty[i].right - qxl->dirty[i].left, + qxl->dirty[i].bottom - qxl->dirty[i].top); } qxl->num_dirty_rects = 0; } @@ -238,7 +235,7 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) return 1; } - if (!qxl->ssd.ds->mouse_set || !qxl->ssd.ds->cursor_define) { + if (!dpy_cursor_define_supported(qxl->ssd.ds)) { return 0; } @@ -18,11 +18,13 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include <zlib.h> + #include "qemu-common.h" -#include "qemu-timer.h" -#include "qemu-queue.h" -#include "monitor.h" -#include "sysemu.h" +#include "qemu/timer.h" +#include "qemu/queue.h" +#include "monitor/monitor.h" +#include "sysemu/sysemu.h" #include "trace.h" #include "qxl.h" @@ -136,6 +138,7 @@ static void qxl_ring_set_dirty(PCIQXLDevice *qxl); void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) { + trace_qxl_set_guest_bug(qxl->id); qxl_send_events(qxl, QXL_INTERRUPT_ERROR); qxl->guest_bug = 1; if (qxl->guestdebug) { @@ -196,6 +199,7 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie); } else { qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); + qxl_spice_destroy_surface_wait_complete(qxl, id); } } @@ -231,7 +235,8 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) { trace_qxl_spice_destroy_surfaces_complete(qxl->id); qemu_mutex_lock(&qxl->track_lock); - memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds)); + memset(qxl->guest_surfaces.cmds, 0, + sizeof(qxl->guest_surfaces.cmds) * qxl->ssd.num_surfaces); qxl->guest_surfaces.count = 0; qemu_mutex_unlock(&qxl->track_lock); } @@ -249,6 +254,32 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) } } +static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay) +{ + trace_qxl_spice_monitors_config(qxl->id); + if (replay) { + /* + * don't use QXL_COOKIE_TYPE_IO: + * - we are not running yet (post_load), we will assert + * in send_events + * - this is not a guest io, but a reply, so async_io isn't set. + */ + spice_qxl_monitors_config_async(&qxl->ssd.qxl, + qxl->guest_monitors_config, + MEMSLOT_GROUP_GUEST, + (uintptr_t)qxl_cookie_new( + QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG, + 0)); + } else { + qxl->guest_monitors_config = qxl->ram->monitors_config; + spice_qxl_monitors_config_async(&qxl->ssd.qxl, + qxl->ram->monitors_config, + MEMSLOT_GROUP_GUEST, + (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, + QXL_IO_MONITORS_CONFIG_ASYNC)); + } +} + void qxl_spice_reset_image_cache(PCIQXLDevice *qxl) { trace_qxl_spice_reset_image_cache(qxl->id); @@ -262,6 +293,10 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl) qemu_mutex_lock(&qxl->track_lock); qxl->guest_cursor = 0; qemu_mutex_unlock(&qxl->track_lock); + if (qxl->ssd.cursor) { + cursor_put(qxl->ssd.cursor); + } + qxl->ssd.cursor = cursor_builtin_hidden(); } @@ -307,7 +342,7 @@ static void init_qxl_rom(PCIQXLDevice *d) rom->slot_id_bits = MEMSLOT_SLOT_BITS; rom->slots_start = 1; rom->slots_end = NUM_MEMSLOTS - 1; - rom->n_surfaces = cpu_to_le32(NUM_SURFACES); + rom->n_surfaces = cpu_to_le32(d->ssd.num_surfaces); for (i = 0, n = 0; i < ARRAY_SIZE(qxl_modes); i++) { fb = qxl_modes[i].y_res * qxl_modes[i].stride; @@ -411,9 +446,15 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) } uint32_t id = le32_to_cpu(cmd->surface_id); - if (id >= NUM_SURFACES) { + if (id >= qxl->ssd.num_surfaces) { qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE id %d >= %d", id, - NUM_SURFACES); + qxl->ssd.num_surfaces); + return 1; + } + if (cmd->type == QXL_SURFACE_CMD_CREATE && + (cmd->u.surface_create.stride & 0x03) != 0) { + qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE stride = %d %% 4 != 0\n", + cmd->u.surface_create.stride); return 1; } qemu_mutex_lock(&qxl->track_lock); @@ -489,7 +530,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) info->num_memslots_groups = NUM_MEMSLOTS_GROUPS; info->internal_groupslot_id = 0; info->qxl_ram_size = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS; - info->n_surfaces = NUM_SURFACES; + info->n_surfaces = qxl->ssd.num_surfaces; } static const char *qxl_mode_to_string(int mode) @@ -538,6 +579,7 @@ static const char *io_port_to_string(uint32_t io_port) = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC", [QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC", [QXL_IO_FLUSH_RELEASE] = "QXL_IO_FLUSH_RELEASE", + [QXL_IO_MONITORS_CONFIG_ASYNC] = "QXL_IO_MONITORS_CONFIG_ASYNC", }; return io_port_to_string[io_port]; } @@ -557,9 +599,9 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) case QXL_MODE_VGA: ret = false; qemu_mutex_lock(&qxl->ssd.lock); - if (qxl->ssd.update != NULL) { - update = qxl->ssd.update; - qxl->ssd.update = NULL; + update = QTAILQ_FIRST(&qxl->ssd.updates); + if (update != NULL) { + QTAILQ_REMOVE(&qxl->ssd.updates, update, next); *ext = update->ext; ret = true; } @@ -819,6 +861,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) case QXL_IO_DESTROY_PRIMARY_ASYNC: case QXL_IO_UPDATE_AREA_ASYNC: case QXL_IO_FLUSH_SURFACES_ASYNC: + case QXL_IO_MONITORS_CONFIG_ASYNC: break; case QXL_IO_CREATE_PRIMARY_ASYNC: qxl_create_guest_primary_complete(qxl); @@ -894,6 +937,8 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA: qxl_render_update_area_done(qxl, cookie); break; + case QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG: + break; default: fprintf(stderr, "qxl: %s: unexpected cookie type %d\n", __func__, cookie->type); @@ -901,6 +946,96 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) } } +/* called from spice server thread context only */ +static void interface_set_client_capabilities(QXLInstance *sin, + uint8_t client_present, + uint8_t caps[58]) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + + if (runstate_check(RUN_STATE_INMIGRATE) || + runstate_check(RUN_STATE_POSTMIGRATE)) { + return; + } + + qxl->shadow_rom.client_present = client_present; + memcpy(qxl->shadow_rom.client_capabilities, caps, sizeof(caps)); + qxl->rom->client_present = client_present; + memcpy(qxl->rom->client_capabilities, caps, sizeof(caps)); + qxl_rom_set_dirty(qxl); + + qxl_send_events(qxl, QXL_INTERRUPT_CLIENT); +} + +static uint32_t qxl_crc32(const uint8_t *p, unsigned len) +{ + /* + * zlib xors the seed with 0xffffffff, and xors the result + * again with 0xffffffff; Both are not done with linux's crc32, + * which we want to be compatible with, so undo that. + */ + return crc32(0xffffffff, p, len) ^ 0xffffffff; +} + +/* called from main context only */ +static int interface_client_monitors_config(QXLInstance *sin, + VDAgentMonitorsConfig *monitors_config) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar); + int i; + + /* + * Older windows drivers set int_mask to 0 when their ISR is called, + * then later set it to ~0. So it doesn't relate to the actual interrupts + * handled. However, they are old, so clearly they don't support this + * interrupt + */ + if (qxl->ram->int_mask == 0 || qxl->ram->int_mask == ~0 || + !(qxl->ram->int_mask & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)) { + trace_qxl_client_monitors_config_unsupported_by_guest(qxl->id, + qxl->ram->int_mask, + monitors_config); + return 0; + } + if (!monitors_config) { + return 1; + } + memset(&rom->client_monitors_config, 0, + sizeof(rom->client_monitors_config)); + rom->client_monitors_config.count = monitors_config->num_of_monitors; + /* monitors_config->flags ignored */ + if (rom->client_monitors_config.count >= + ARRAY_SIZE(rom->client_monitors_config.heads)) { + trace_qxl_client_monitors_config_capped(qxl->id, + monitors_config->num_of_monitors, + ARRAY_SIZE(rom->client_monitors_config.heads)); + rom->client_monitors_config.count = + ARRAY_SIZE(rom->client_monitors_config.heads); + } + for (i = 0 ; i < rom->client_monitors_config.count ; ++i) { + VDAgentMonConfig *monitor = &monitors_config->monitors[i]; + QXLURect *rect = &rom->client_monitors_config.heads[i]; + /* monitor->depth ignored */ + rect->left = monitor->x; + rect->top = monitor->y; + rect->right = monitor->x + monitor->width; + rect->bottom = monitor->y + monitor->height; + } + rom->client_monitors_config_crc = qxl_crc32( + (const uint8_t *)&rom->client_monitors_config, + sizeof(rom->client_monitors_config)); + trace_qxl_client_monitors_config_crc(qxl->id, + sizeof(rom->client_monitors_config), + rom->client_monitors_config_crc); + + trace_qxl_interrupt_client_monitors_config(qxl->id, + rom->client_monitors_config.count, + rom->client_monitors_config.heads); + qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG); + return 1; +} + static const QXLInterface qxl_interface = { .base.type = SPICE_INTERFACE_QXL, .base.description = "qxl gpu", @@ -922,6 +1057,8 @@ static const QXLInterface qxl_interface = { .flush_resources = interface_flush_resources, .async_complete = interface_async_complete, .update_area_complete = interface_update_area_complete, + .set_client_capabilities = interface_set_client_capabilities, + .client_monitors_config = interface_client_monitors_config, }; static void qxl_enter_vga_mode(PCIQXLDevice *d) @@ -932,7 +1069,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d) trace_qxl_enter_vga_mode(d->id); qemu_spice_create_host_primary(&d->ssd); d->mode = QXL_MODE_VGA; - memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty)); + dpy_gfx_resize(d->ssd.ds); vga_dirty_log_start(&d->vga); } @@ -958,9 +1095,10 @@ static void qxl_update_irq(PCIQXLDevice *d) static void qxl_check_state(PCIQXLDevice *d) { QXLRam *ram = d->ram; + int spice_display_running = qemu_spice_display_is_running(&d->ssd); - assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cmd_ring)); - assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cursor_ring)); + assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cmd_ring)); + assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cursor_ring)); } static void qxl_reset_state(PCIQXLDevice *d) @@ -1229,6 +1367,12 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, trace_qxl_create_guest_primary_rest(qxl->id, sc->stride, sc->type, sc->flags); + if ((surface.stride & 0x3) != 0) { + qxl_set_guest_bug(qxl, "primary surface stride = %d %% 4 != 0", + surface.stride); + return; + } + surface.mouse_mode = true; surface.group_id = MEMSLOT_GROUP_GUEST; if (loadvm) { @@ -1292,17 +1436,15 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) d->mode = QXL_MODE_COMPAT; d->cmdflags = QXL_COMMAND_FLAG_COMPAT; -#ifdef QXL_COMMAND_FLAG_COMPAT_16BPP /* new in spice 0.6.1 */ if (mode->bits == 16) { d->cmdflags |= QXL_COMMAND_FLAG_COMPAT_16BPP; } -#endif d->shadow_rom.mode = cpu_to_le32(modenr); d->rom->mode = cpu_to_le32(modenr); qxl_rom_set_dirty(d); } -static void ioport_write(void *opaque, target_phys_addr_t addr, +static void ioport_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { PCIQXLDevice *d = opaque; @@ -1310,7 +1452,14 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, qxl_async_io async = QXL_SYNC; uint32_t orig_io_port = io_port; - if (d->guest_bug && !io_port == QXL_IO_RESET) { + if (d->guest_bug && io_port != QXL_IO_RESET) { + return; + } + + if (d->revision <= QXL_REVISION_STABLE_V10 && + io_port > QXL_IO_FLUSH_RELEASE) { + qxl_set_guest_bug(d, "unsupported io %d for revision %d\n", + io_port, d->revision); return; } @@ -1330,10 +1479,10 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, break; } trace_qxl_io_unexpected_vga_mode(d->id, - io_port, io_port_to_string(io_port)); + addr, val, io_port_to_string(io_port)); /* be nice to buggy guest drivers */ if (io_port >= QXL_IO_UPDATE_AREA_ASYNC && - io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) { + io_port < QXL_IO_RANGE_SIZE) { qxl_send_events(d, QXL_INTERRUPT_IO_CMD); } return; @@ -1361,6 +1510,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, io_port = QXL_IO_DESTROY_ALL_SURFACES; goto async_common; case QXL_IO_FLUSH_SURFACES_ASYNC: + case QXL_IO_MONITORS_CONFIG_ASYNC: async_common: async = QXL_ASYNC; qemu_mutex_lock(&d->async_lock); @@ -1385,6 +1535,18 @@ async_common: QXLCookie *cookie = NULL; QXLRect update = d->ram->update_area; + if (d->ram->update_surface > d->ssd.num_surfaces) { + qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n", + d->ram->update_surface); + break; + } + if (update.left >= update.right || update.top >= update.bottom || + update.left < 0 || update.top < 0) { + qxl_set_guest_bug(d, + "QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n", + update.left, update.top, update.right, update.bottom); + break; + } if (async == QXL_ASYNC) { cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, QXL_IO_UPDATE_AREA_ASYNC); @@ -1416,6 +1578,7 @@ async_common: qxl_set_mode(d, val, 0); break; case QXL_IO_LOG: + trace_qxl_io_log(d->id, d->ram->log_buf); if (d->guestdebug) { fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id, qemu_get_clock_ns(vm_clock), d->ram->log_buf); @@ -1466,7 +1629,7 @@ async_common: } break; case QXL_IO_DESTROY_SURFACE_WAIT: - if (val >= NUM_SURFACES) { + if (val >= d->ssd.num_surfaces) { qxl_set_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):" "%" PRIu64 " >= NUM_SURFACES", async, val); goto cancel_async; @@ -1490,6 +1653,9 @@ async_common: d->mode = QXL_MODE_UNDEFINED; qxl_spice_destroy_surfaces(d, async); break; + case QXL_IO_MONITORS_CONFIG_ASYNC: + qxl_spice_monitors_config_async(d, 0); + break; default: qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port); } @@ -1503,12 +1669,12 @@ cancel_async: } } -static uint64_t ioport_read(void *opaque, target_phys_addr_t addr, +static uint64_t ioport_read(void *opaque, hwaddr addr, unsigned size) { - PCIQXLDevice *d = opaque; + PCIQXLDevice *qxl = opaque; - trace_qxl_io_read_unexpected(d->id); + trace_qxl_io_read_unexpected(qxl->id); return 0xff; } @@ -1538,7 +1704,14 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) uint32_t old_pending; uint32_t le_events = cpu_to_le32(events); - assert(d->ssd.running); + trace_qxl_send_events(d->id, events); + if (!qemu_spice_display_is_running(&d->ssd)) { + /* spice-server tracks guest running state and should not do this */ + fprintf(stderr, "%s: spice-server bug: guest stopped, ignoring\n", + __func__); + trace_qxl_send_events_vm_stopped(d->id, events); + return; + } old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events); if ((old_pending & le_events) == le_events) { return; @@ -1595,7 +1768,8 @@ static void qxl_hw_invalidate(void *opaque) vga->invalidate(vga); } -static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch) +static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp) { PCIQXLDevice *qxl = opaque; VGACommonState *vga = &qxl->vga; @@ -1604,10 +1778,10 @@ static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch) case QXL_MODE_COMPAT: case QXL_MODE_NATIVE: qxl_render_update(qxl); - ppm_save(filename, qxl->ssd.ds->surface); + ppm_save(filename, qxl->ssd.ds->surface, errp); break; case QXL_MODE_VGA: - vga->screen_dump(vga, filename, cswitch); + vga->screen_dump(vga, filename, cswitch, errp); break; default: break; @@ -1627,7 +1801,7 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata) static void qxl_dirty_surfaces(PCIQXLDevice *qxl) { - intptr_t vram_start; + uintptr_t vram_start; int i; if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) { @@ -1638,10 +1812,10 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset, qxl->shadow_rom.surface0_area_size); - vram_start = (intptr_t)memory_region_get_ram_ptr(&qxl->vram_bar); + vram_start = (uintptr_t)memory_region_get_ram_ptr(&qxl->vram_bar); /* dirty the off-screen surfaces */ - for (i = 0; i < NUM_SURFACES; i++) { + for (i = 0; i < qxl->ssd.num_surfaces; i++) { QXLSurfaceCmd *cmd; intptr_t surface_offset; int surface_size; @@ -1670,7 +1844,6 @@ static void qxl_vm_change_state_handler(void *opaque, int running, RunState state) { PCIQXLDevice *qxl = opaque; - qemu_spice_vm_change_state_handler(&qxl->ssd, running, state); if (running) { /* @@ -1713,8 +1886,8 @@ static void display_refresh(struct DisplayState *ds) } static DisplayChangeListener display_listener = { - .dpy_update = display_update, - .dpy_resize = display_resize, + .dpy_gfx_update = display_update, + .dpy_gfx_resize = display_resize, .dpy_refresh = display_refresh, }; @@ -1769,7 +1942,6 @@ static int qxl_init_common(PCIQXLDevice *qxl) qxl->mode = QXL_MODE_UNDEFINED; qxl->generation = 1; qxl->num_memslots = NUM_MEMSLOTS; - qxl->num_surfaces = NUM_SURFACES; qemu_mutex_init(&qxl->track_lock); qemu_mutex_init(&qxl->async_lock); qxl->current_async = QXL_UNDEFINED_IO; @@ -1785,10 +1957,17 @@ static int qxl_init_common(PCIQXLDevice *qxl) io_size = 16; break; case 3: /* qxl-3 */ - default: - pci_device_rev = QXL_DEFAULT_REVISION; + pci_device_rev = QXL_REVISION_STABLE_V10; + io_size = 32; /* PCI region size must be pow2 */ + break; + case 4: /* qxl-4 */ + pci_device_rev = QXL_REVISION_STABLE_V12; io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); break; + default: + error_report("Invalid revision %d for qxl device (max %d)", + qxl->revision, QXL_DEFAULT_REVISION); + return -1; } pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev); @@ -1800,6 +1979,7 @@ static int qxl_init_common(PCIQXLDevice *qxl) init_qxl_rom(qxl); init_qxl_ram(qxl); + qxl->guest_surfaces.cmds = g_new0(QXLPHYSICAL, qxl->ssd.num_surfaces); memory_region_init_ram(&qxl->vram_bar, "qxl.vram", qxl->vram_size); vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev); memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar, @@ -1810,6 +1990,7 @@ static int qxl_init_common(PCIQXLDevice *qxl) if (qxl->id == 0) { vga_dirty_log_start(&qxl->vga); } + memory_region_set_flush_coalesced(&qxl->io_bar); pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX, @@ -1848,7 +2029,11 @@ static int qxl_init_common(PCIQXLDevice *qxl) qxl->ssd.qxl.base.sif = &qxl_interface.base; qxl->ssd.qxl.id = qxl->id; - qemu_spice_add_interface(&qxl->ssd.qxl.base); + if (qemu_spice_add_interface(&qxl->ssd.qxl.base) != 0) { + error_report("qxl interface %d.%d not supported by spice-server\n", + SPICE_INTERFACE_QXL_MAJOR, SPICE_INTERFACE_QXL_MINOR); + return -1; + } qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl); init_pipe_signaling(qxl); @@ -1864,6 +2049,7 @@ static int qxl_init_primary(PCIDevice *dev) PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); VGACommonState *vga = &qxl->vga; PortioList *qxl_vga_port_list = g_new(PortioList, 1); + int rc; qxl->id = 0; qxl_init_ramsize(qxl); @@ -1878,9 +2064,14 @@ static int qxl_init_primary(PCIDevice *dev) qemu_spice_display_init_common(&qxl->ssd, vga->ds); qxl0 = qxl; - register_displaychangelistener(vga->ds, &display_listener); - return qxl_init_common(qxl); + rc = qxl_init_common(qxl); + if (rc != 0) { + return rc; + } + + register_displaychangelistener(vga->ds, &display_listener); + return rc; } static int qxl_init_secondary(PCIDevice *dev) @@ -1955,6 +2146,7 @@ static int qxl_post_load(void *opaque, int version) switch (newmode) { case QXL_MODE_UNDEFINED: + qxl_create_memslots(d); break; case QXL_MODE_VGA: qxl_create_memslots(d); @@ -1965,8 +2157,8 @@ static int qxl_post_load(void *opaque, int version) qxl_create_guest_primary(d, 1, QXL_SYNC); /* replay surface-create and cursor-set commands */ - cmds = g_malloc0(sizeof(QXLCommandExt) * (NUM_SURFACES + 1)); - for (in = 0, out = 0; in < NUM_SURFACES; in++) { + cmds = g_malloc0(sizeof(QXLCommandExt) * (d->ssd.num_surfaces + 1)); + for (in = 0, out = 0; in < d->ssd.num_surfaces; in++) { if (d->guest_surfaces.cmds[in] == 0) { continue; } @@ -1983,7 +2175,9 @@ static int qxl_post_load(void *opaque, int version) } qxl_spice_loadvm_commands(d, cmds, out); g_free(cmds); - + if (d->guest_monitors_config) { + qxl_spice_monitors_config_async(d, 1); + } break; case QXL_MODE_COMPAT: /* note: no need to call qxl_create_memslots, qxl_set_mode @@ -1996,6 +2190,14 @@ static int qxl_post_load(void *opaque, int version) #define QXL_SAVE_VERSION 21 +static bool qxl_monitors_config_needed(void *opaque) +{ + PCIQXLDevice *qxl = opaque; + + return qxl->guest_monitors_config != 0; +} + + static VMStateDescription qxl_memslot = { .name = "qxl-memslot", .version_id = QXL_SAVE_VERSION, @@ -2026,6 +2228,16 @@ static VMStateDescription qxl_surface = { } }; +static VMStateDescription qxl_vmstate_monitors_config = { + .name = "qxl/monitors-config", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(guest_monitors_config, PCIQXLDevice), + VMSTATE_END_OF_LIST() + }, +}; + static VMStateDescription qxl_vmstate = { .name = "qxl", .version_id = QXL_SAVE_VERSION, @@ -2033,7 +2245,7 @@ static VMStateDescription qxl_vmstate = { .pre_save = qxl_pre_save, .pre_load = qxl_pre_load, .post_load = qxl_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(pci, PCIQXLDevice), VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState), VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice), @@ -2046,12 +2258,21 @@ static VMStateDescription qxl_vmstate = { qxl_memslot, struct guest_slots), VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0, qxl_surface, QXLSurfaceCreate), - VMSTATE_INT32_EQUAL(num_surfaces, PCIQXLDevice), - VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, 0, - vmstate_info_uint64, uint64_t), + VMSTATE_INT32_EQUAL(ssd.num_surfaces, PCIQXLDevice), + VMSTATE_VARRAY_INT32(guest_surfaces.cmds, PCIQXLDevice, + ssd.num_surfaces, 0, + vmstate_info_uint64, uint64_t), VMSTATE_UINT64(guest_cursor, PCIQXLDevice), VMSTATE_END_OF_LIST() }, + .subsections = (VMStateSubsection[]) { + { + .vmsd = &qxl_vmstate_monitors_config, + .needed = qxl_monitors_config_needed, + }, { + /* empty */ + } + } }; static Property qxl_properties[] = { @@ -2068,6 +2289,7 @@ static Property qxl_properties[] = { DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1), DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1), DEFINE_PROP_UINT32("vgamem_mb", PCIQXLDevice, vgamem_size_mb, 16), + DEFINE_PROP_INT32("surfaces", PCIQXLDevice, ssd.num_surfaces, 1024), DEFINE_PROP_END_OF_LIST(), }; @@ -1,10 +1,13 @@ +#ifndef HW_QXL_H +#define HW_QXL_H 1 + #include "qemu-common.h" -#include "console.h" +#include "ui/console.h" #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "vga_int.h" -#include "qemu-thread.h" +#include "qemu/thread.h" #include "ui/qemu-spice.h" #include "ui/spice-display.h" @@ -40,7 +43,6 @@ typedef struct PCIQXLDevice { uint32_t revision; int32_t num_memslots; - int32_t num_surfaces; uint32_t current_async; QemuMutex async_lock; @@ -65,12 +67,14 @@ typedef struct PCIQXLDevice { } guest_primary; struct surfaces { - QXLPHYSICAL cmds[NUM_SURFACES]; + QXLPHYSICAL *cmds; uint32_t count; uint32_t max; } guest_surfaces; QXLPHYSICAL guest_cursor; + QXLPHYSICAL guest_monitors_config; + QemuMutex track_lock; /* thread signaling */ @@ -128,7 +132,7 @@ typedef struct PCIQXLDevice { } \ } while (0) -#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10 +#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12 /* qxl.c */ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); @@ -157,3 +161,5 @@ void qxl_render_update(PCIQXLDevice *qxl); int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext); void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie); void qxl_render_update_area_bh(void *opaque); + +#endif @@ -27,17 +27,17 @@ #include "hw.h" #include "sh.h" #include "devices.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "boards.h" -#include "pci.h" -#include "net.h" +#include "pci/pci.h" +#include "net/net.h" #include "sh7750_regs.h" #include "ide.h" #include "loader.h" #include "usb.h" #include "flash.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" #define FLASH_BASE 0x00000000 #define FLASH_SIZE 0x02000000 @@ -127,7 +127,7 @@ static void r2d_fpga_irq_set(void *opaque, int n, int level) update_irl(fpga); } -static uint32_t r2d_fpga_read(void *opaque, target_phys_addr_t addr) +static uint32_t r2d_fpga_read(void *opaque, hwaddr addr) { r2d_fpga_t *s = opaque; @@ -146,7 +146,7 @@ static uint32_t r2d_fpga_read(void *opaque, target_phys_addr_t addr) } static void -r2d_fpga_write(void *opaque, target_phys_addr_t addr, uint32_t value) +r2d_fpga_write(void *opaque, hwaddr addr, uint32_t value) { r2d_fpga_t *s = opaque; @@ -178,7 +178,7 @@ static const MemoryRegionOps r2d_fpga_ops = { }; static qemu_irq *r2d_fpga_init(MemoryRegion *sysmem, - target_phys_addr_t base, qemu_irq irl) + hwaddr base, qemu_irq irl) { r2d_fpga_t *s; @@ -219,11 +219,12 @@ static struct QEMU_PACKED char kernel_cmdline[256]; } boot_params; -static void r2d_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void r2d_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; SuperHCPU *cpu; CPUSH4State *env; ResetData *reset_info; @@ -332,6 +333,8 @@ static void r2d_init(ram_addr_t ram_size, } if (kernel_cmdline) { + /* I see no evidence that this .kernel_cmdline buffer requires + NUL-termination, so using strncpy should be ok. */ strncpy(boot_params.kernel_cmdline, kernel_cmdline, sizeof(boot_params.kernel_cmdline)); } diff --git a/hw/rc4030.c b/hw/rc4030.c index 9f39b30505..a0358a319c 100644 --- a/hw/rc4030.c +++ b/hw/rc4030.c @@ -24,7 +24,7 @@ #include "hw.h" #include "mips.h" -#include "qemu-timer.h" +#include "qemu/timer.h" /********************************************************/ /* debug rc4030 */ @@ -112,7 +112,7 @@ static void set_next_tick(rc4030State *s) } /* called for accesses to rc4030 */ -static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr) +static uint32_t rc4030_readl(void *opaque, hwaddr addr) { rc4030State *s = opaque; uint32_t val; @@ -250,7 +250,7 @@ static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr) return val; } -static uint32_t rc4030_readw(void *opaque, target_phys_addr_t addr) +static uint32_t rc4030_readw(void *opaque, hwaddr addr) { uint32_t v = rc4030_readl(opaque, addr & ~0x3); if (addr & 0x2) @@ -259,13 +259,13 @@ static uint32_t rc4030_readw(void *opaque, target_phys_addr_t addr) return v & 0xffff; } -static uint32_t rc4030_readb(void *opaque, target_phys_addr_t addr) +static uint32_t rc4030_readb(void *opaque, hwaddr addr) { uint32_t v = rc4030_readl(opaque, addr & ~0x3); return (v >> (8 * (addr & 0x3))) & 0xff; } -static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val) { rc4030State *s = opaque; addr &= 0x3fff; @@ -308,7 +308,7 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val) case 0x0060: /* HACK */ if (s->cache_ltag == 0x80000001 && s->cache_bmask == 0xf0f0f0f) { - target_phys_addr_t dest = s->cache_ptag & ~0x1; + hwaddr dest = s->cache_ptag & ~0x1; dest += (s->cache_maint & 0x3) << 3; cpu_physical_memory_write(dest, &val, 4); } @@ -390,7 +390,7 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val) } } -static void rc4030_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +static void rc4030_writew(void *opaque, hwaddr addr, uint32_t val) { uint32_t old_val = rc4030_readl(opaque, addr & ~0x3); @@ -401,7 +401,7 @@ static void rc4030_writew(void *opaque, target_phys_addr_t addr, uint32_t val) rc4030_writel(opaque, addr & ~0x3, val); } -static void rc4030_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void rc4030_writeb(void *opaque, hwaddr addr, uint32_t val) { uint32_t old_val = rc4030_readl(opaque, addr & ~0x3); @@ -479,7 +479,7 @@ static void rc4030_periodic_timer(void *opaque) qemu_irq_raise(s->timer_irq); } -static uint32_t jazzio_readw(void *opaque, target_phys_addr_t addr) +static uint32_t jazzio_readw(void *opaque, hwaddr addr) { rc4030State *s = opaque; uint32_t val; @@ -517,14 +517,14 @@ static uint32_t jazzio_readw(void *opaque, target_phys_addr_t addr) return val; } -static uint32_t jazzio_readb(void *opaque, target_phys_addr_t addr) +static uint32_t jazzio_readb(void *opaque, hwaddr addr) { uint32_t v; v = jazzio_readw(opaque, addr & ~0x1); return (v >> (8 * (addr & 0x1))) & 0xff; } -static uint32_t jazzio_readl(void *opaque, target_phys_addr_t addr) +static uint32_t jazzio_readl(void *opaque, hwaddr addr) { uint32_t v; v = jazzio_readw(opaque, addr); @@ -532,7 +532,7 @@ static uint32_t jazzio_readl(void *opaque, target_phys_addr_t addr) return v; } -static void jazzio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +static void jazzio_writew(void *opaque, hwaddr addr, uint32_t val) { rc4030State *s = opaque; addr &= 0xfff; @@ -551,7 +551,7 @@ static void jazzio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) } } -static void jazzio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +static void jazzio_writeb(void *opaque, hwaddr addr, uint32_t val) { uint32_t old_val = jazzio_readw(opaque, addr & ~0x1); @@ -566,7 +566,7 @@ static void jazzio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) jazzio_writew(opaque, addr & ~0x1, val); } -static void jazzio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void jazzio_writel(void *opaque, hwaddr addr, uint32_t val) { jazzio_writew(opaque, addr, val & 0xffff); jazzio_writew(opaque, addr + 2, (val >> 16) & 0xffff); @@ -672,11 +672,11 @@ static void rc4030_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->itr); } -void rc4030_dma_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write) +void rc4030_dma_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write) { rc4030State *s = opaque; - target_phys_addr_t entry_addr; - target_phys_addr_t phys_addr; + hwaddr entry_addr; + hwaddr phys_addr; dma_pagetable_entry entry; int index; int ncpy, i; @@ -713,7 +713,7 @@ void rc4030_dma_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, i static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write) { rc4030State *s = opaque; - target_phys_addr_t dma_addr; + hwaddr dma_addr; int dev_to_mem; s->dma_regs[n][DMA_REG_ENABLE] &= ~(DMA_FLAG_TC_INTR | DMA_FLAG_MEM_INTR | DMA_FLAG_ADDR_INTR); diff --git a/hw/realview.c b/hw/realview.c index 19db4d026b..872b3b468a 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -11,13 +11,13 @@ #include "arm-misc.h" #include "primecell.h" #include "devices.h" -#include "pci.h" -#include "net.h" -#include "sysemu.h" +#include "pci/pci.h" +#include "net/net.h" +#include "sysemu/sysemu.h" #include "boards.h" #include "i2c.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" #define SMP_BOOT_ADDR 0xe0000000 #define SMP_BOOTREG_ADDR 0x10000030 @@ -44,11 +44,8 @@ static const int realview_board_id[] = { 0x76d }; -static void realview_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model, - enum realview_board_type board_type) +static void realview_init(QEMUMachineInitArgs *args, + enum realview_board_type board_type) { ARMCPU *cpu = NULL; CPUARMState *env; @@ -73,6 +70,7 @@ static void realview_init(ram_addr_t ram_size, uint32_t proc_id = 0; uint32_t sys_id; ram_addr_t low_ram_size; + ram_addr_t ram_size = args->ram_size; switch (board_type) { case BOARD_EB: @@ -89,7 +87,7 @@ static void realview_init(ram_addr_t ram_size, break; } for (n = 0; n < smp_cpus; n++) { - cpu = cpu_arm_init(cpu_model); + cpu = cpu_arm_init(args->cpu_model); if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); @@ -145,7 +143,7 @@ static void realview_init(ram_addr_t ram_size, sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000); if (is_mpcore) { - target_phys_addr_t periphbase; + hwaddr periphbase; dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore"); qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); qdev_init_nofail(dev); @@ -227,7 +225,7 @@ static void realview_init(ram_addr_t ram_size, sysbus_connect_irq(busdev, 2, pic[50]); sysbus_connect_irq(busdev, 3, pic[51]); pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci"); - if (usb_enabled) { + if (usb_enabled(false)) { pci_create_simple(pci_bus, -1, "pci-ohci"); } n = drive_get_max_bus(IF_SCSI); @@ -321,75 +319,59 @@ static void realview_init(ram_addr_t ram_size, memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack); realview_binfo.ram_size = ram_size; - realview_binfo.kernel_filename = kernel_filename; - realview_binfo.kernel_cmdline = kernel_cmdline; - realview_binfo.initrd_filename = initrd_filename; + realview_binfo.kernel_filename = args->kernel_filename; + realview_binfo.kernel_cmdline = args->kernel_cmdline; + realview_binfo.initrd_filename = args->initrd_filename; realview_binfo.nb_cpus = smp_cpus; realview_binfo.board_id = realview_board_id[board_type]; realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0); arm_load_kernel(arm_env_get_cpu(first_cpu), &realview_binfo); } -static void realview_eb_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void realview_eb_init(QEMUMachineInitArgs *args) { - if (!cpu_model) { - cpu_model = "arm926"; + if (!args->cpu_model) { + args->cpu_model = "arm926"; } - realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, BOARD_EB); + realview_init(args, BOARD_EB); } -static void realview_eb_mpcore_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void realview_eb_mpcore_init(QEMUMachineInitArgs *args) { - if (!cpu_model) { - cpu_model = "arm11mpcore"; + if (!args->cpu_model) { + args->cpu_model = "arm11mpcore"; } - realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, BOARD_EB_MPCORE); + realview_init(args, BOARD_EB_MPCORE); } -static void realview_pb_a8_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void realview_pb_a8_init(QEMUMachineInitArgs *args) { - if (!cpu_model) { - cpu_model = "cortex-a8"; + if (!args->cpu_model) { + args->cpu_model = "cortex-a8"; } - realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, BOARD_PB_A8); + realview_init(args, BOARD_PB_A8); } -static void realview_pbx_a9_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void realview_pbx_a9_init(QEMUMachineInitArgs *args) { - if (!cpu_model) { - cpu_model = "cortex-a9"; + if (!args->cpu_model) { + args->cpu_model = "cortex-a9"; } - realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, BOARD_PBX_A9); + realview_init(args, BOARD_PBX_A9); } static QEMUMachine realview_eb_machine = { .name = "realview-eb", .desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)", .init = realview_eb_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, }; static QEMUMachine realview_eb_mpcore_machine = { .name = "realview-eb-mpcore", .desc = "ARM RealView Emulation Baseboard (ARM11MPCore)", .init = realview_eb_mpcore_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, .max_cpus = 4, }; @@ -403,7 +385,7 @@ static QEMUMachine realview_pbx_a9_machine = { .name = "realview-pbx-a9", .desc = "ARM RealView Platform Baseboard Explore for Cortex-A9", .init = realview_pbx_a9_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, .max_cpus = 4, }; diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 844f1b8c3f..3e080621f6 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -52,13 +52,13 @@ #include <zlib.h> #include "hw.h" -#include "pci.h" -#include "dma.h" -#include "qemu-timer.h" -#include "net.h" +#include "pci/pci.h" +#include "sysemu/dma.h" +#include "qemu/timer.h" +#include "net/net.h" #include "loader.h" -#include "sysemu.h" -#include "iov.h" +#include "sysemu/sysemu.h" +#include "qemu/iov.h" /* debug RTL8139 card */ //#define DEBUG_RTL8139 1 @@ -167,7 +167,7 @@ enum IntrStatusBits { PCIErr = 0x8000, PCSTimeout = 0x4000, RxFIFOOver = 0x40, - RxUnderrun = 0x20, + RxUnderrun = 0x20, /* Packet Underrun / Link Change */ RxOverflow = 0x10, TxErr = 0x08, TxOK = 0x04, @@ -774,11 +774,7 @@ static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size) #define MIN_BUF_SIZE 60 static inline dma_addr_t rtl8139_addr64(uint32_t low, uint32_t high) { -#if TARGET_PHYS_ADDR_BITS > 32 - return low | ((target_phys_addr_t)high << 32); -#else - return low; -#endif + return low | ((uint64_t)high << 32); } /* Workaround for buggy guest driver such as linux who allocates rx @@ -1262,7 +1258,8 @@ static void rtl8139_reset(DeviceState *d) s->BasicModeStatus = 0x7809; //s->BasicModeStatus |= 0x0040; /* UTP medium */ s->BasicModeStatus |= 0x0020; /* autonegotiation completed */ - s->BasicModeStatus |= 0x0004; /* link is up */ + /* preserve link state */ + s->BasicModeStatus |= s->nic->nc.link_down ? 0 : 0x04; s->NWayAdvert = 0x05e1; /* all modes, full duplex */ s->NWayLPAR = 0x05e1; /* all modes, full duplex */ @@ -2459,7 +2456,7 @@ static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32 if (descriptor == 0 && (val & 0x8)) { - target_phys_addr_t tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]); + hwaddr tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]); /* dump tally counters to specified memory location */ RTL8139TallyCounters_dma_write(s, tc_addr); @@ -3007,7 +3004,8 @@ static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr) break; case MediaStatus: - ret = 0xd0; + /* The LinkDown bit of MediaStatus is inverse with link status */ + ret = 0xd0 | (~s->BasicModeStatus & 0x04); DPRINTF("MediaStatus read 0x%x\n", ret); break; @@ -3190,65 +3188,33 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) /* */ -static void rtl8139_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) +static void rtl8139_mmio_writeb(void *opaque, hwaddr addr, uint32_t val) { rtl8139_io_writeb(opaque, addr & 0xFF, val); } -static void rtl8139_ioport_writew(void *opaque, uint32_t addr, uint32_t val) +static void rtl8139_mmio_writew(void *opaque, hwaddr addr, uint32_t val) { rtl8139_io_writew(opaque, addr & 0xFF, val); } -static void rtl8139_ioport_writel(void *opaque, uint32_t addr, uint32_t val) +static void rtl8139_mmio_writel(void *opaque, hwaddr addr, uint32_t val) { rtl8139_io_writel(opaque, addr & 0xFF, val); } -static uint32_t rtl8139_ioport_readb(void *opaque, uint32_t addr) +static uint32_t rtl8139_mmio_readb(void *opaque, hwaddr addr) { return rtl8139_io_readb(opaque, addr & 0xFF); } -static uint32_t rtl8139_ioport_readw(void *opaque, uint32_t addr) -{ - return rtl8139_io_readw(opaque, addr & 0xFF); -} - -static uint32_t rtl8139_ioport_readl(void *opaque, uint32_t addr) -{ - return rtl8139_io_readl(opaque, addr & 0xFF); -} - -/* */ - -static void rtl8139_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - rtl8139_io_writeb(opaque, addr & 0xFF, val); -} - -static void rtl8139_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - rtl8139_io_writew(opaque, addr & 0xFF, val); -} - -static void rtl8139_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - rtl8139_io_writel(opaque, addr & 0xFF, val); -} - -static uint32_t rtl8139_mmio_readb(void *opaque, target_phys_addr_t addr) -{ - return rtl8139_io_readb(opaque, addr & 0xFF); -} - -static uint32_t rtl8139_mmio_readw(void *opaque, target_phys_addr_t addr) +static uint32_t rtl8139_mmio_readw(void *opaque, hwaddr addr) { uint32_t val = rtl8139_io_readw(opaque, addr & 0xFF); return val; } -static uint32_t rtl8139_mmio_readl(void *opaque, target_phys_addr_t addr) +static uint32_t rtl8139_mmio_readl(void *opaque, hwaddr addr) { uint32_t val = rtl8139_io_readl(opaque, addr & 0xFF); return val; @@ -3262,6 +3228,10 @@ static int rtl8139_post_load(void *opaque, int version_id) s->cplus_enabled = s->CpCmd != 0; } + /* nc.link_down can't be migrated, so infer link_down according + * to link status bit in BasicModeStatus */ + s->nic->nc.link_down = (s->BasicModeStatus & 0x04) == 0; + return 0; } @@ -3385,18 +3355,44 @@ static const VMStateDescription vmstate_rtl8139 = { /***********************************************************/ /* PCI RTL8139 definitions */ -static const MemoryRegionPortio rtl8139_portio[] = { - { 0, 0x100, 1, .read = rtl8139_ioport_readb, }, - { 0, 0x100, 1, .write = rtl8139_ioport_writeb, }, - { 0, 0x100, 2, .read = rtl8139_ioport_readw, }, - { 0, 0x100, 2, .write = rtl8139_ioport_writew, }, - { 0, 0x100, 4, .read = rtl8139_ioport_readl, }, - { 0, 0x100, 4, .write = rtl8139_ioport_writel, }, - PORTIO_END_OF_LIST() -}; +static void rtl8139_ioport_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + switch (size) { + case 1: + rtl8139_io_writeb(opaque, addr, val); + break; + case 2: + rtl8139_io_writew(opaque, addr, val); + break; + case 4: + rtl8139_io_writel(opaque, addr, val); + break; + } +} + +static uint64_t rtl8139_ioport_read(void *opaque, hwaddr addr, + unsigned size) +{ + switch (size) { + case 1: + return rtl8139_io_readb(opaque, addr); + case 2: + return rtl8139_io_readw(opaque, addr); + case 4: + return rtl8139_io_readl(opaque, addr); + } + + return -1; +} static const MemoryRegionOps rtl8139_io_ops = { - .old_portio = rtl8139_portio, + .read = rtl8139_ioport_read, + .write = rtl8139_ioport_write, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, .endianness = DEVICE_LITTLE_ENDIAN, }; @@ -3453,12 +3449,27 @@ static void pci_rtl8139_uninit(PCIDevice *dev) qemu_del_net_client(&s->nic->nc); } +static void rtl8139_set_link_status(NetClientState *nc) +{ + RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque; + + if (nc->link_down) { + s->BasicModeStatus &= ~0x04; + } else { + s->BasicModeStatus |= 0x04; + } + + s->IntrStatus |= RxUnderrun; + rtl8139_update_irq(s); +} + static NetClientInfo net_rtl8139_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = rtl8139_can_receive, .receive = rtl8139_receive, .cleanup = rtl8139_cleanup, + .link_status_changed = rtl8139_set_link_status, }; static int pci_rtl8139_init(PCIDevice *dev) diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index a245684692..7e991755b4 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -18,18 +18,18 @@ */ #include "hw.h" -#include "block.h" -#include "sysemu.h" -#include "net.h" +#include "block/block.h" +#include "sysemu/sysemu.h" #include "boards.h" -#include "monitor.h" +#include "monitor/monitor.h" #include "loader.h" #include "elf.h" #include "hw/virtio.h" +#include "hw/virtio-rng.h" #include "hw/virtio-serial.h" #include "hw/virtio-net.h" #include "hw/sysbus.h" -#include "kvm.h" +#include "sysemu/kvm.h" #include "hw/s390-virtio-bus.h" @@ -56,7 +56,7 @@ static const VirtIOBindings virtio_s390_bindings; static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev); /* length of VirtIO device pages */ -const target_phys_addr_t virtio_size = S390_DEVICE_PAGES * TARGET_PAGE_SIZE; +const hwaddr virtio_size = S390_DEVICE_PAGES * TARGET_PAGE_SIZE; static void s390_virtio_bus_reset(void *opaque) { @@ -67,7 +67,7 @@ static void s390_virtio_bus_reset(void *opaque) void s390_virtio_reset_idx(VirtIOS390Device *dev) { int i; - target_phys_addr_t idx_addr; + hwaddr idx_addr; uint8_t num_vq; num_vq = s390_virtio_device_num_vq(dev); @@ -110,10 +110,12 @@ VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size) return bus; } -static void s390_virtio_irq(CPUS390XState *env, int config_change, uint64_t token) +static void s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token) { + CPUS390XState *env = &cpu->env; + if (kvm_enabled()) { - kvm_s390_virtio_irq(env, config_change, token); + kvm_s390_virtio_irq(cpu, config_change, token); } else { cpu_inject_ext(env, VIRTIO_EXT_CODE, config_change, token); } @@ -136,14 +138,13 @@ static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev) bus->dev_offs += dev_len; - virtio_bind_device(vdev, &virtio_s390_bindings, dev); + virtio_bind_device(vdev, &virtio_s390_bindings, DEVICE(dev)); dev->host_features = vdev->get_features(vdev, dev->host_features); s390_virtio_device_sync(dev); s390_virtio_reset_idx(dev); if (dev->qdev.hotplugged) { S390CPU *cpu = s390_cpu_addr2state(0); - CPUS390XState *env = &cpu->env; - s390_virtio_irq(env, VIRTIO_PARAM_DEV_ADD, dev->dev_offs); + s390_virtio_irq(cpu, VIRTIO_PARAM_DEV_ADD, dev->dev_offs); } return 0; @@ -206,6 +207,18 @@ static int s390_virtio_scsi_init(VirtIOS390Device *dev) return s390_virtio_device_init(dev, vdev); } +static int s390_virtio_rng_init(VirtIOS390Device *dev) +{ + VirtIODevice *vdev; + + vdev = virtio_rng_init((DeviceState *)dev, &dev->rng); + if (!vdev) { + return -1; + } + + return s390_virtio_device_init(dev, vdev); +} + static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq) { ram_addr_t token_off; @@ -351,19 +364,32 @@ VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem) return NULL; } -static void virtio_s390_notify(void *opaque, uint16_t vector) +/* DeviceState to VirtIOS390Device. Note: used on datapath, + * be careful and test performance if you change this. + */ +static inline VirtIOS390Device *to_virtio_s390_device_fast(DeviceState *d) +{ + return container_of(d, VirtIOS390Device, qdev); +} + +/* DeviceState to VirtIOS390Device. TODO: use QOM. */ +static inline VirtIOS390Device *to_virtio_s390_device(DeviceState *d) { - VirtIOS390Device *dev = (VirtIOS390Device*)opaque; + return container_of(d, VirtIOS390Device, qdev); +} + +static void virtio_s390_notify(DeviceState *d, uint16_t vector) +{ + VirtIOS390Device *dev = to_virtio_s390_device_fast(d); uint64_t token = s390_virtio_device_vq_token(dev, vector); S390CPU *cpu = s390_cpu_addr2state(0); - CPUS390XState *env = &cpu->env; - s390_virtio_irq(env, 0, token); + s390_virtio_irq(cpu, 0, token); } -static unsigned virtio_s390_get_features(void *opaque) +static unsigned virtio_s390_get_features(DeviceState *d) { - VirtIOS390Device *dev = (VirtIOS390Device*)opaque; + VirtIOS390Device *dev = to_virtio_s390_device(d); return dev->host_features; } @@ -448,6 +474,29 @@ static TypeInfo s390_virtio_serial = { .class_init = s390_virtio_serial_class_init, }; +static void s390_virtio_rng_initfn(Object *obj) +{ + VirtIOS390Device *dev = VIRTIO_S390_DEVICE(obj); + + object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, + (Object **)&dev->rng.rng, NULL); +} + +static void s390_virtio_rng_class_init(ObjectClass *klass, void *data) +{ + VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass); + + k->init = s390_virtio_rng_init; +} + +static TypeInfo s390_virtio_rng = { + .name = "virtio-rng-s390", + .parent = TYPE_VIRTIO_S390_DEVICE, + .instance_size = sizeof(VirtIOS390Device), + .instance_init = s390_virtio_rng_initfn, + .class_init = s390_virtio_rng_class_init, +}; + static int s390_virtio_busdev_init(DeviceState *dev) { VirtIOS390Device *_dev = (VirtIOS390Device *)dev; @@ -528,6 +577,7 @@ static void s390_virtio_register_types(void) type_register_static(&s390_virtio_blk); type_register_static(&s390_virtio_net); type_register_static(&s390_virtio_scsi); + type_register_static(&s390_virtio_rng); type_register_static(&s390_virtio_bridge_info); } diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h index 4873134ae9..23fedd5be8 100644 --- a/hw/s390-virtio-bus.h +++ b/hw/s390-virtio-bus.h @@ -16,9 +16,12 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#ifndef HW_S390_VIRTIO_BUS_H +#define HW_S390_VIRTIO_BUS_H 1 #include "virtio-blk.h" #include "virtio-net.h" +#include "virtio-rng.h" #include "virtio-serial.h" #include "virtio-scsi.h" @@ -75,6 +78,7 @@ struct VirtIOS390Device { virtio_serial_conf serial; virtio_net_conf net; VirtIOSCSIConf scsi; + VirtIORNGConf rng; }; typedef struct VirtIOS390Bus { @@ -98,3 +102,5 @@ VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem); void s390_virtio_device_sync(VirtIOS390Device *dev); void s390_virtio_reset_idx(VirtIOS390Device *dev); + +#endif diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index 47eed35da3..20827761d0 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -18,20 +18,21 @@ */ #include "hw.h" -#include "block.h" -#include "blockdev.h" -#include "sysemu.h" -#include "net.h" +#include "block/block.h" +#include "sysemu/blockdev.h" +#include "sysemu/sysemu.h" +#include "net/net.h" #include "boards.h" -#include "monitor.h" +#include "monitor/monitor.h" #include "loader.h" #include "elf.h" #include "hw/virtio.h" #include "hw/sysbus.h" -#include "kvm.h" -#include "exec-memory.h" +#include "sysemu/kvm.h" +#include "exec/address-spaces.h" #include "hw/s390-virtio-bus.h" +#include "hw/s390x/sclp.h" //#define DEBUG_S390 @@ -151,13 +152,13 @@ unsigned s390_del_running_cpu(CPUS390XState *env) } /* PC hardware initialisation */ -static void s390_init(ram_addr_t my_ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void s390_init(QEMUMachineInitArgs *args) { + ram_addr_t my_ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; CPUS390XState *env = NULL; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); @@ -167,8 +168,8 @@ static void s390_init(ram_addr_t my_ram_size, int shift = 0; uint8_t *storage_keys; void *virtio_region; - target_phys_addr_t virtio_region_len; - target_phys_addr_t virtio_region_start; + hwaddr virtio_region_len; + hwaddr virtio_region_start; int i; /* s390x ram size detection needs a 16bit multiplier + an increment. So @@ -183,6 +184,7 @@ static void s390_init(ram_addr_t my_ram_size, /* get a BUS */ s390_bus = s390_virtio_bus_init(&my_ram_size); + s390_sclp_init(); /* allocate RAM */ memory_region_init_ram(ram, "s390.ram", my_ram_size); @@ -284,8 +286,8 @@ static void s390_init(ram_addr_t my_ram_size, } /* we have to overwrite values in the kernel image, which are "rom" */ - memcpy(rom_ptr(INITRD_PARM_START), &initrd_offset, 8); - memcpy(rom_ptr(INITRD_PARM_SIZE), &initrd_size, 8); + stq_p(rom_ptr(INITRD_PARM_START), initrd_offset); + stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size); } if (rom_ptr(KERN_PARM_AREA)) { @@ -312,21 +314,6 @@ static void s390_init(ram_addr_t my_ram_size, qdev_set_nic_properties(dev, nd); qdev_init_nofail(dev); } - - /* Create VirtIO disk drives */ - for(i = 0; i < MAX_BLK_DEVS; i++) { - DriveInfo *dinfo; - DeviceState *dev; - - dinfo = drive_get(IF_IDE, 0, i); - if (!dinfo) { - continue; - } - - dev = qdev_create((BusState *)s390_bus, "virtio-blk-s390"); - qdev_prop_set_drive_nofail(dev, "drive", dinfo->bdrv); - qdev_init_nofail(dev); - } } static QEMUMachine s390_machine = { @@ -334,6 +321,7 @@ static QEMUMachine s390_machine = { .alias = "s390", .desc = "VirtIO based S390 machine", .init = s390_init, + .block_default_type = IF_VIRTIO, .no_cdrom = 1, .no_floppy = 1, .no_serial = 1, @@ -350,3 +338,4 @@ static void s390_machine_init(void) } machine_init(s390_machine_init); + diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index dcdcac8a81..096dfcd6a1 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -1,3 +1,6 @@ obj-y = s390-virtio-bus.o s390-virtio.o obj-y := $(addprefix ../,$(obj-y)) +obj-y += sclp.o +obj-y += event-facility.o +obj-y += sclpquiesce.o sclpconsole.o diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c new file mode 100644 index 0000000000..89b1b66bd2 --- /dev/null +++ b/hw/s390x/event-facility.c @@ -0,0 +1,399 @@ +/* + * SCLP + * Event Facility + * handles SCLP event types + * - Signal Quiesce - system power down + * - ASCII Console Data - VT220 read and write + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Heinz Graalfs <graalfs@de.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at your + * option) any later version. See the COPYING file in the top-level directory. + * + */ + +#include "monitor/monitor.h" +#include "sysemu/sysemu.h" + +#include "sclp.h" +#include "event-facility.h" + +typedef struct EventTypesBus { + BusState qbus; +} EventTypesBus; + +struct SCLPEventFacility { + EventTypesBus sbus; + DeviceState *qdev; + /* guest' receive mask */ + unsigned int receive_mask; +}; + +/* return true if any child has event pending set */ +static bool event_pending(SCLPEventFacility *ef) +{ + BusChild *kid; + SCLPEvent *event; + SCLPEventClass *event_class; + + QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) { + DeviceState *qdev = kid->child; + event = DO_UPCAST(SCLPEvent, qdev, qdev); + event_class = SCLP_EVENT_GET_CLASS(event); + if (event->event_pending && + event_class->get_send_mask() & ef->receive_mask) { + return true; + } + } + return false; +} + +static unsigned int get_host_send_mask(SCLPEventFacility *ef) +{ + unsigned int mask; + BusChild *kid; + SCLPEventClass *child; + + mask = 0; + + QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) { + DeviceState *qdev = kid->child; + child = SCLP_EVENT_GET_CLASS((SCLPEvent *) qdev); + mask |= child->get_send_mask(); + } + return mask; +} + +static unsigned int get_host_receive_mask(SCLPEventFacility *ef) +{ + unsigned int mask; + BusChild *kid; + SCLPEventClass *child; + + mask = 0; + + QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) { + DeviceState *qdev = kid->child; + child = SCLP_EVENT_GET_CLASS((SCLPEvent *) qdev); + mask |= child->get_receive_mask(); + } + return mask; +} + +static uint16_t write_event_length_check(SCCB *sccb) +{ + int slen; + unsigned elen = 0; + EventBufferHeader *event; + WriteEventData *wed = (WriteEventData *) sccb; + + event = (EventBufferHeader *) &wed->ebh; + for (slen = sccb_data_len(sccb); slen > 0; slen -= elen) { + elen = be16_to_cpu(event->length); + if (elen < sizeof(*event) || elen > slen) { + return SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR; + } + event = (void *) event + elen; + } + if (slen) { + return SCLP_RC_INCONSISTENT_LENGTHS; + } + return SCLP_RC_NORMAL_COMPLETION; +} + +static uint16_t handle_write_event_buf(SCLPEventFacility *ef, + EventBufferHeader *event_buf, SCCB *sccb) +{ + uint16_t rc; + BusChild *kid; + SCLPEvent *event; + SCLPEventClass *ec; + + rc = SCLP_RC_INVALID_FUNCTION; + + QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) { + DeviceState *qdev = kid->child; + event = (SCLPEvent *) qdev; + ec = SCLP_EVENT_GET_CLASS(event); + + if (ec->write_event_data && + ec->event_type() == event_buf->type) { + rc = ec->write_event_data(event, event_buf); + break; + } + } + return rc; +} + +static uint16_t handle_sccb_write_events(SCLPEventFacility *ef, SCCB *sccb) +{ + uint16_t rc; + int slen; + unsigned elen = 0; + EventBufferHeader *event_buf; + WriteEventData *wed = (WriteEventData *) sccb; + + event_buf = &wed->ebh; + rc = SCLP_RC_NORMAL_COMPLETION; + + /* loop over all contained event buffers */ + for (slen = sccb_data_len(sccb); slen > 0; slen -= elen) { + elen = be16_to_cpu(event_buf->length); + + /* in case of a previous error mark all trailing buffers + * as not accepted */ + if (rc != SCLP_RC_NORMAL_COMPLETION) { + event_buf->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED); + } else { + rc = handle_write_event_buf(ef, event_buf, sccb); + } + event_buf = (void *) event_buf + elen; + } + return rc; +} + +static void write_event_data(SCLPEventFacility *ef, SCCB *sccb) +{ + if (sccb->h.function_code != SCLP_FC_NORMAL_WRITE) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION); + goto out; + } + if (be16_to_cpu(sccb->h.length) < 8) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH); + goto out; + } + /* first do a sanity check of the write events */ + sccb->h.response_code = cpu_to_be16(write_event_length_check(sccb)); + + /* if no early error, then execute */ + if (sccb->h.response_code == be16_to_cpu(SCLP_RC_NORMAL_COMPLETION)) { + sccb->h.response_code = + cpu_to_be16(handle_sccb_write_events(ef, sccb)); + } + +out: + return; +} + +static uint16_t handle_sccb_read_events(SCLPEventFacility *ef, SCCB *sccb, + unsigned int mask) +{ + uint16_t rc; + int slen; + unsigned elen = 0; + BusChild *kid; + SCLPEvent *event; + SCLPEventClass *ec; + EventBufferHeader *event_buf; + ReadEventData *red = (ReadEventData *) sccb; + + event_buf = &red->ebh; + event_buf->length = 0; + slen = sizeof(sccb->data); + + rc = SCLP_RC_NO_EVENT_BUFFERS_STORED; + + QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) { + DeviceState *qdev = kid->child; + event = (SCLPEvent *) qdev; + ec = SCLP_EVENT_GET_CLASS(event); + + if (mask & ec->get_send_mask()) { + if (ec->read_event_data(event, event_buf, &slen)) { + rc = SCLP_RC_NORMAL_COMPLETION; + } + } + elen = be16_to_cpu(event_buf->length); + event_buf = (void *) event_buf + elen; + } + + if (sccb->h.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE) { + /* architecture suggests to reset variable-length-response bit */ + sccb->h.control_mask[2] &= ~SCLP_VARIABLE_LENGTH_RESPONSE; + /* with a new length value */ + sccb->h.length = cpu_to_be16(SCCB_SIZE - slen); + } + return rc; +} + +static void read_event_data(SCLPEventFacility *ef, SCCB *sccb) +{ + unsigned int sclp_active_selection_mask; + unsigned int sclp_cp_receive_mask; + + ReadEventData *red = (ReadEventData *) sccb; + + if (be16_to_cpu(sccb->h.length) != SCCB_SIZE) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH); + goto out; + } + + sclp_cp_receive_mask = ef->receive_mask; + + /* get active selection mask */ + switch (sccb->h.function_code) { + case SCLP_UNCONDITIONAL_READ: + sclp_active_selection_mask = sclp_cp_receive_mask; + break; + case SCLP_SELECTIVE_READ: + if (!(sclp_cp_receive_mask & be32_to_cpu(red->mask))) { + sccb->h.response_code = + cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK); + goto out; + } + sclp_active_selection_mask = be32_to_cpu(red->mask); + break; + default: + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION); + goto out; + } + sccb->h.response_code = cpu_to_be16( + handle_sccb_read_events(ef, sccb, sclp_active_selection_mask)); + +out: + return; +} + +static void write_event_mask(SCLPEventFacility *ef, SCCB *sccb) +{ + WriteEventMask *we_mask = (WriteEventMask *) sccb; + + /* Attention: We assume that Linux uses 4-byte masks, what it actually + does. Architecture allows for masks of variable size, though */ + if (be16_to_cpu(we_mask->mask_length) != 4) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_MASK_LENGTH); + goto out; + } + + /* keep track of the guest's capability masks */ + ef->receive_mask = be32_to_cpu(we_mask->cp_receive_mask); + + /* return the SCLP's capability masks to the guest */ + we_mask->send_mask = cpu_to_be32(get_host_send_mask(ef)); + we_mask->receive_mask = cpu_to_be32(get_host_receive_mask(ef)); + + sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION); + +out: + return; +} + +/* qemu object creation and initialization functions */ + +#define TYPE_SCLP_EVENTS_BUS "s390-sclp-events-bus" + +static void sclp_events_bus_class_init(ObjectClass *klass, void *data) +{ +} + +static const TypeInfo s390_sclp_events_bus_info = { + .name = TYPE_SCLP_EVENTS_BUS, + .parent = TYPE_BUS, + .class_init = sclp_events_bus_class_init, +}; + +static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code) +{ + switch (code) { + case SCLP_CMD_READ_EVENT_DATA: + read_event_data(ef, sccb); + break; + case SCLP_CMD_WRITE_EVENT_DATA: + write_event_data(ef, sccb); + break; + case SCLP_CMD_WRITE_EVENT_MASK: + write_event_mask(ef, sccb); + break; + default: + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + break; + } +} + +static int init_event_facility(S390SCLPDevice *sdev) +{ + SCLPEventFacility *event_facility; + DeviceState *quiesce; + + event_facility = g_malloc0(sizeof(SCLPEventFacility)); + sdev->ef = event_facility; + sdev->sclp_command_handler = command_handler; + sdev->event_pending = event_pending; + + /* Spawn a new sclp-events facility */ + qbus_create_inplace(&event_facility->sbus.qbus, + TYPE_SCLP_EVENTS_BUS, (DeviceState *)sdev, NULL); + event_facility->sbus.qbus.allow_hotplug = 0; + event_facility->qdev = (DeviceState *) sdev; + + quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce"); + if (!quiesce) { + return -1; + } + qdev_init_nofail(quiesce); + + return 0; +} + +static void init_event_facility_class(ObjectClass *klass, void *data) +{ + S390SCLPDeviceClass *k = SCLP_S390_DEVICE_CLASS(klass); + + k->init = init_event_facility; +} + +static TypeInfo s390_sclp_event_facility_info = { + .name = "s390-sclp-event-facility", + .parent = TYPE_DEVICE_S390_SCLP, + .instance_size = sizeof(S390SCLPDevice), + .class_init = init_event_facility_class, +}; + +static int event_qdev_init(DeviceState *qdev) +{ + SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev); + SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event); + + return child->init(event); +} + +static int event_qdev_exit(DeviceState *qdev) +{ + SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev); + SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event); + if (child->exit) { + child->exit(event); + } + return 0; +} + +static void event_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->bus_type = TYPE_SCLP_EVENTS_BUS; + dc->unplug = qdev_simple_unplug_cb; + dc->init = event_qdev_init; + dc->exit = event_qdev_exit; +} + +static TypeInfo s390_sclp_event_type_info = { + .name = TYPE_SCLP_EVENT, + .parent = TYPE_DEVICE, + .instance_size = sizeof(SCLPEvent), + .class_init = event_class_init, + .class_size = sizeof(SCLPEventClass), + .abstract = true, +}; + +static void register_types(void) +{ + type_register_static(&s390_sclp_events_bus_info); + type_register_static(&s390_sclp_event_facility_info); + type_register_static(&s390_sclp_event_type_info); +} + +type_init(register_types) diff --git a/hw/s390x/event-facility.h b/hw/s390x/event-facility.h new file mode 100644 index 0000000000..791ab2a6de --- /dev/null +++ b/hw/s390x/event-facility.h @@ -0,0 +1,96 @@ +/* + * SCLP + * Event Facility definitions + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Heinz Graalfs <graalfs@de.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at your + * option) any later version. See the COPYING file in the top-level directory. + * + */ + +#ifndef HW_S390_SCLP_EVENT_FACILITY_H +#define HW_S390_SCLP_EVENT_FACILITY_H + +#include <hw/qdev.h> +#include "qemu/thread.h" + +/* SCLP event types */ +#define SCLP_EVENT_ASCII_CONSOLE_DATA 0x1a +#define SCLP_EVENT_SIGNAL_QUIESCE 0x1d + +/* SCLP event masks */ +#define SCLP_EVENT_MASK_SIGNAL_QUIESCE 0x00000008 +#define SCLP_EVENT_MASK_MSG_ASCII 0x00000040 + +#define SCLP_UNCONDITIONAL_READ 0x00 +#define SCLP_SELECTIVE_READ 0x01 + +#define TYPE_SCLP_EVENT "s390-sclp-event-type" +#define SCLP_EVENT(obj) \ + OBJECT_CHECK(SCLPEvent, (obj), TYPE_SCLP_EVENT) +#define SCLP_EVENT_CLASS(klass) \ + OBJECT_CLASS_CHECK(SCLPEventClass, (klass), TYPE_SCLP_EVENT) +#define SCLP_EVENT_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SCLPEventClass, (obj), TYPE_SCLP_EVENT) + +typedef struct WriteEventMask { + SCCBHeader h; + uint16_t _reserved; + uint16_t mask_length; + uint32_t cp_receive_mask; + uint32_t cp_send_mask; + uint32_t send_mask; + uint32_t receive_mask; +} QEMU_PACKED WriteEventMask; + +typedef struct EventBufferHeader { + uint16_t length; + uint8_t type; + uint8_t flags; + uint16_t _reserved; +} QEMU_PACKED EventBufferHeader; + +typedef struct WriteEventData { + SCCBHeader h; + EventBufferHeader ebh; +} QEMU_PACKED WriteEventData; + +typedef struct ReadEventData { + SCCBHeader h; + EventBufferHeader ebh; + uint32_t mask; +} QEMU_PACKED ReadEventData; + +typedef struct SCLPEvent { + DeviceState qdev; + bool event_pending; + uint32_t event_type; + char *name; +} SCLPEvent; + +typedef struct SCLPEventClass { + DeviceClass parent_class; + int (*init)(SCLPEvent *event); + int (*exit)(SCLPEvent *event); + + /* get SCLP's send mask */ + unsigned int (*get_send_mask)(void); + + /* get SCLP's receive mask */ + unsigned int (*get_receive_mask)(void); + + int (*read_event_data)(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, + int *slen); + + int (*write_event_data)(SCLPEvent *event, EventBufferHeader *evt_buf_hdr); + + /* returns the supported event type */ + int (*event_type)(void); + +} SCLPEventClass; + +#endif diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c new file mode 100644 index 0000000000..7ad791d5e3 --- /dev/null +++ b/hw/s390x/sclp.c @@ -0,0 +1,163 @@ +/* + * SCLP Support + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Christian Borntraeger <borntraeger@de.ibm.com> + * Heinz Graalfs <graalfs@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at your + * option) any later version. See the COPYING file in the top-level directory. + * + */ + +#include "cpu.h" +#include "sysemu/kvm.h" +#include "exec/memory.h" + +#include "sclp.h" + +static inline S390SCLPDevice *get_event_facility(void) +{ + ObjectProperty *op = object_property_find(qdev_get_machine(), + "s390-sclp-event-facility", + NULL); + assert(op); + return op->opaque; +} + +/* Provide information about the configuration, CPUs and storage */ +static void read_SCP_info(SCCB *sccb) +{ + ReadInfo *read_info = (ReadInfo *) sccb; + int shift = 0; + + while ((ram_size >> (20 + shift)) > 65535) { + shift++; + } + read_info->rnmax = cpu_to_be16(ram_size >> (20 + shift)); + read_info->rnsize = 1 << shift; + sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); +} + +static void sclp_execute(SCCB *sccb, uint64_t code) +{ + S390SCLPDevice *sdev = get_event_facility(); + + switch (code) { + case SCLP_CMDW_READ_SCP_INFO: + case SCLP_CMDW_READ_SCP_INFO_FORCED: + read_SCP_info(sccb); + break; + default: + sdev->sclp_command_handler(sdev->ef, sccb, code); + break; + } +} + +int sclp_service_call(uint32_t sccb, uint64_t code) +{ + int r = 0; + SCCB work_sccb; + + hwaddr sccb_len = sizeof(SCCB); + + /* first some basic checks on program checks */ + if (cpu_physical_memory_is_io(sccb)) { + r = -PGM_ADDRESSING; + goto out; + } + if (sccb & ~0x7ffffff8ul) { + r = -PGM_SPECIFICATION; + goto out; + } + + /* + * we want to work on a private copy of the sccb, to prevent guests + * from playing dirty tricks by modifying the memory content after + * the host has checked the values + */ + cpu_physical_memory_read(sccb, &work_sccb, sccb_len); + + /* Valid sccb sizes */ + if (be16_to_cpu(work_sccb.h.length) < sizeof(SCCBHeader) || + be16_to_cpu(work_sccb.h.length) > SCCB_SIZE) { + r = -PGM_SPECIFICATION; + goto out; + } + + sclp_execute((SCCB *)&work_sccb, code); + + cpu_physical_memory_write(sccb, &work_sccb, + be16_to_cpu(work_sccb.h.length)); + + sclp_service_interrupt(sccb); + +out: + return r; +} + +void sclp_service_interrupt(uint32_t sccb) +{ + S390SCLPDevice *sdev = get_event_facility(); + uint32_t param = sccb & ~3; + + /* Indicate whether an event is still pending */ + param |= sdev->event_pending(sdev->ef) ? 1 : 0; + + if (!param) { + /* No need to send an interrupt, there's nothing to be notified about */ + return; + } + s390_sclp_extint(param); +} + +/* qemu object creation and initialization functions */ + +void s390_sclp_init(void) +{ + DeviceState *dev = qdev_create(NULL, "s390-sclp-event-facility"); + + object_property_add_child(qdev_get_machine(), "s390-sclp-event-facility", + OBJECT(dev), NULL); + qdev_init_nofail(dev); +} + +static int s390_sclp_dev_init(SysBusDevice *dev) +{ + int r; + S390SCLPDevice *sdev = (S390SCLPDevice *)dev; + S390SCLPDeviceClass *sclp = SCLP_S390_DEVICE_GET_CLASS(dev); + + r = sclp->init(sdev); + if (!r) { + assert(sdev->event_pending); + assert(sdev->sclp_command_handler); + } + + return r; +} + +static void s390_sclp_device_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *dc = SYS_BUS_DEVICE_CLASS(klass); + + dc->init = s390_sclp_dev_init; +} + +static TypeInfo s390_sclp_device_info = { + .name = TYPE_DEVICE_S390_SCLP, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(S390SCLPDevice), + .class_init = s390_sclp_device_class_init, + .class_size = sizeof(S390SCLPDeviceClass), + .abstract = true, +}; + +static void s390_sclp_register_types(void) +{ + type_register_static(&s390_sclp_device_info); +} + +type_init(s390_sclp_register_types) diff --git a/hw/s390x/sclp.h b/hw/s390x/sclp.h new file mode 100644 index 0000000000..231a38aa09 --- /dev/null +++ b/hw/s390x/sclp.h @@ -0,0 +1,118 @@ +/* + * SCLP Support + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Christian Borntraeger <borntraeger@de.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at your + * option) any later version. See the COPYING file in the top-level directory. + * + */ + +#ifndef HW_S390_SCLP_H +#define HW_S390_SCLP_H + +#include <hw/sysbus.h> +#include <hw/qdev.h> + +/* SCLP command codes */ +#define SCLP_CMDW_READ_SCP_INFO 0x00020001 +#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 +#define SCLP_CMD_READ_EVENT_DATA 0x00770005 +#define SCLP_CMD_WRITE_EVENT_DATA 0x00760005 +#define SCLP_CMD_READ_EVENT_DATA 0x00770005 +#define SCLP_CMD_WRITE_EVENT_DATA 0x00760005 +#define SCLP_CMD_WRITE_EVENT_MASK 0x00780005 + +/* SCLP response codes */ +#define SCLP_RC_NORMAL_READ_COMPLETION 0x0010 +#define SCLP_RC_NORMAL_COMPLETION 0x0020 +#define SCLP_RC_INVALID_SCLP_COMMAND 0x01f0 +#define SCLP_RC_CONTAINED_EQUIPMENT_CHECK 0x0340 +#define SCLP_RC_INSUFFICIENT_SCCB_LENGTH 0x0300 +#define SCLP_RC_INVALID_FUNCTION 0x40f0 +#define SCLP_RC_NO_EVENT_BUFFERS_STORED 0x60f0 +#define SCLP_RC_INVALID_SELECTION_MASK 0x70f0 +#define SCLP_RC_INCONSISTENT_LENGTHS 0x72f0 +#define SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR 0x73f0 +#define SCLP_RC_INVALID_MASK_LENGTH 0x74f0 + + +/* Service Call Control Block (SCCB) and its elements */ + +#define SCCB_SIZE 4096 + +#define SCLP_VARIABLE_LENGTH_RESPONSE 0x80 +#define SCLP_EVENT_BUFFER_ACCEPTED 0x80 + +#define SCLP_FC_NORMAL_WRITE 0 + +/* + * Normally packed structures are not the right thing to do, since all code + * must take care of endianness. We cannot use ldl_phys and friends for two + * reasons, though: + * - some of the embedded structures below the SCCB can appear multiple times + * at different locations, so there is no fixed offset + * - we work on a private copy of the SCCB, since there are several length + * fields, that would cause a security nightmare if we allow the guest to + * alter the structure while we parse it. We cannot use ldl_p and friends + * either without doing pointer arithmetics + * So we have to double check that all users of sclp data structures use the + * right endianness wrappers. + */ +typedef struct SCCBHeader { + uint16_t length; + uint8_t function_code; + uint8_t control_mask[3]; + uint16_t response_code; +} QEMU_PACKED SCCBHeader; + +#define SCCB_DATA_LEN (SCCB_SIZE - sizeof(SCCBHeader)) + +typedef struct ReadInfo { + SCCBHeader h; + uint16_t rnmax; + uint8_t rnsize; +} QEMU_PACKED ReadInfo; + +typedef struct SCCB { + SCCBHeader h; + char data[SCCB_DATA_LEN]; + } QEMU_PACKED SCCB; + +static inline int sccb_data_len(SCCB *sccb) +{ + return be16_to_cpu(sccb->h.length) - sizeof(sccb->h); +} + +#define TYPE_DEVICE_S390_SCLP "s390-sclp-device" +#define SCLP_S390_DEVICE(obj) \ + OBJECT_CHECK(S390SCLPDevice, (obj), TYPE_DEVICE_S390_SCLP) +#define SCLP_S390_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(S390SCLPDeviceClass, (klass), \ + TYPE_DEVICE_S390_SCLP) +#define SCLP_S390_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(S390SCLPDeviceClass, (obj), \ + TYPE_DEVICE_S390_SCLP) + +typedef struct SCLPEventFacility SCLPEventFacility; + +typedef struct S390SCLPDevice { + SysBusDevice busdev; + SCLPEventFacility *ef; + void (*sclp_command_handler)(SCLPEventFacility *ef, SCCB *sccb, + uint64_t code); + bool (*event_pending)(SCLPEventFacility *ef); +} S390SCLPDevice; + +typedef struct S390SCLPDeviceClass { + DeviceClass qdev; + int (*init)(S390SCLPDevice *sdev); +} S390SCLPDeviceClass; + +void s390_sclp_init(void); +void sclp_service_interrupt(uint32_t sccb); + +#endif diff --git a/hw/s390x/sclpconsole.c b/hw/s390x/sclpconsole.c new file mode 100644 index 0000000000..aa70e16665 --- /dev/null +++ b/hw/s390x/sclpconsole.c @@ -0,0 +1,307 @@ +/* + * SCLP event type + * Ascii Console Data (VT220 Console) + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Heinz Graalfs <graalfs@de.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at your + * option) any later version. See the COPYING file in the top-level directory. + * + */ + +#include <hw/qdev.h> +#include "qemu/thread.h" + +#include "sclp.h" +#include "event-facility.h" +#include "char/char.h" + +typedef struct ASCIIConsoleData { + EventBufferHeader ebh; + char data[0]; +} QEMU_PACKED ASCIIConsoleData; + +/* max size for ASCII data in 4K SCCB page */ +#define SIZE_BUFFER_VT220 4080 + +typedef struct SCLPConsole { + SCLPEvent event; + CharDriverState *chr; + /* io vector */ + uint8_t *iov; /* iov buffer pointer */ + uint8_t *iov_sclp; /* pointer to SCLP read offset */ + uint8_t *iov_bs; /* pointer byte stream read offset */ + uint32_t iov_data_len; /* length of byte stream in buffer */ + uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */ + qemu_irq irq_read_vt220; +} SCLPConsole; + +/* character layer call-back functions */ + +/* Return number of bytes that fit into iov buffer */ +static int chr_can_read(void *opaque) +{ + int can_read; + SCLPConsole *scon = opaque; + + can_read = SIZE_BUFFER_VT220 - scon->iov_data_len; + + return can_read; +} + +/* Receive n bytes from character layer, save in iov buffer, + * and set event pending */ +static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf, + int size) +{ + assert(scon->iov); + + /* read data must fit into current buffer */ + assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len); + + /* put byte-stream from character layer into buffer */ + memcpy(scon->iov_bs, buf, size); + scon->iov_data_len += size; + scon->iov_sclp_rest += size; + scon->iov_bs += size; + scon->event.event_pending = true; +} + +/* Send data from a char device over to the guest */ +static void chr_read(void *opaque, const uint8_t *buf, int size) +{ + SCLPConsole *scon = opaque; + + assert(scon); + + receive_from_chr_layer(scon, buf, size); + /* trigger SCLP read operation */ + qemu_irq_raise(scon->irq_read_vt220); +} + +static void chr_event(void *opaque, int event) +{ + SCLPConsole *scon = opaque; + + switch (event) { + case CHR_EVENT_OPENED: + if (!scon->iov) { + scon->iov = g_malloc0(SIZE_BUFFER_VT220); + scon->iov_sclp = scon->iov; + scon->iov_bs = scon->iov; + scon->iov_data_len = 0; + scon->iov_sclp_rest = 0; + } + break; + case CHR_EVENT_CLOSED: + if (scon->iov) { + g_free(scon->iov); + scon->iov = NULL; + } + break; + } +} + +/* functions to be called by event facility */ + +static int event_type(void) +{ + return SCLP_EVENT_ASCII_CONSOLE_DATA; +} + +static unsigned int send_mask(void) +{ + return SCLP_EVENT_MASK_MSG_ASCII; +} + +static unsigned int receive_mask(void) +{ + return SCLP_EVENT_MASK_MSG_ASCII; +} + +/* triggered by SCLP's read_event_data - + * copy console data byte-stream into provided (SCLP) buffer + */ +static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size, + int avail) +{ + SCLPConsole *cons = DO_UPCAST(SCLPConsole, event, event); + + /* first byte is hex 0 saying an ascii string follows */ + *buf++ = '\0'; + avail--; + /* if all data fit into provided SCLP buffer */ + if (avail >= cons->iov_sclp_rest) { + /* copy character byte-stream to SCLP buffer */ + memcpy(buf, cons->iov_sclp, cons->iov_sclp_rest); + *size = cons->iov_sclp_rest + 1; + cons->iov_sclp = cons->iov; + cons->iov_bs = cons->iov; + cons->iov_data_len = 0; + cons->iov_sclp_rest = 0; + event->event_pending = false; + /* data provided and no more data pending */ + } else { + /* if provided buffer is too small, just copy part */ + memcpy(buf, cons->iov_sclp, avail); + *size = avail + 1; + cons->iov_sclp_rest -= avail; + cons->iov_sclp += avail; + /* more data pending */ + } +} + +static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, + int *slen) +{ + int avail; + size_t src_len; + uint8_t *to; + ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr; + + if (!event->event_pending) { + /* no data pending */ + return 0; + } + + to = (uint8_t *)&acd->data; + avail = *slen - sizeof(ASCIIConsoleData); + get_console_data(event, to, &src_len, avail); + + acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len); + acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; + acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED; + *slen = avail - src_len; + + return 1; +} + +/* triggered by SCLP's write_event_data + * - write console data to character layer + * returns < 0 if an error occurred + */ +static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf, + size_t len) +{ + ssize_t ret = 0; + const uint8_t *iov_offset; + SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event); + + if (!scon->chr) { + /* If there's no backend, we can just say we consumed all data. */ + return len; + } + + iov_offset = buf; + while (len > 0) { + ret = qemu_chr_fe_write(scon->chr, buf, len); + if (ret == 0) { + /* a pty doesn't seem to be connected - no error */ + len = 0; + } else if (ret == -EAGAIN || (ret > 0 && ret < len)) { + len -= ret; + iov_offset += ret; + } else { + len = 0; + } + } + + return ret; +} + +static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr) +{ + int rc; + int length; + ssize_t written; + ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr; + + length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader); + written = write_console_data(event, (uint8_t *)acd->data, length); + + rc = SCLP_RC_NORMAL_COMPLETION; + /* set event buffer accepted flag */ + evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED; + + /* written will be zero if a pty is not connected - don't treat as error */ + if (written < 0) { + /* event buffer not accepted due to error in character layer */ + evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED); + rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK; + } + + return rc; +} + +static void trigger_ascii_console_data(void *env, int n, int level) +{ + sclp_service_interrupt(0); +} + +/* qemu object creation and initialization functions */ + +/* tell character layer our call-back functions */ +static int console_init(SCLPEvent *event) +{ + static bool console_available; + + SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event); + + if (console_available) { + error_report("Multiple VT220 operator consoles are not supported"); + return -1; + } + console_available = true; + event->event_type = SCLP_EVENT_ASCII_CONSOLE_DATA; + if (scon->chr) { + qemu_chr_add_handlers(scon->chr, chr_can_read, + chr_read, chr_event, scon); + } + scon->irq_read_vt220 = *qemu_allocate_irqs(trigger_ascii_console_data, + NULL, 1); + + return 0; +} + +static int console_exit(SCLPEvent *event) +{ + return 0; +} + +static Property console_properties[] = { + DEFINE_PROP_CHR("chardev", SCLPConsole, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void console_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SCLPEventClass *ec = SCLP_EVENT_CLASS(klass); + + dc->props = console_properties; + ec->init = console_init; + ec->exit = console_exit; + ec->get_send_mask = send_mask; + ec->get_receive_mask = receive_mask; + ec->event_type = event_type; + ec->read_event_data = read_event_data; + ec->write_event_data = write_event_data; +} + +static TypeInfo sclp_console_info = { + .name = "sclpconsole", + .parent = TYPE_SCLP_EVENT, + .instance_size = sizeof(SCLPConsole), + .class_init = console_class_init, + .class_size = sizeof(SCLPEventClass), +}; + +static void register_types(void) +{ + type_register_static(&sclp_console_info); +} + +type_init(register_types) diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c new file mode 100644 index 0000000000..6e6f5624df --- /dev/null +++ b/hw/s390x/sclpquiesce.c @@ -0,0 +1,123 @@ +/* + * SCLP event type + * Signal Quiesce - trigger system powerdown request + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Heinz Graalfs <graalfs@de.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at your + * option) any later version. See the COPYING file in the top-level directory. + * + */ +#include <hw/qdev.h> +#include "sysemu/sysemu.h" +#include "sclp.h" +#include "event-facility.h" + +typedef struct SignalQuiesce { + EventBufferHeader ebh; + uint16_t timeout; + uint8_t unit; +} QEMU_PACKED SignalQuiesce; + +static int event_type(void) +{ + return SCLP_EVENT_SIGNAL_QUIESCE; +} + +static unsigned int send_mask(void) +{ + return SCLP_EVENT_MASK_SIGNAL_QUIESCE; +} + +static unsigned int receive_mask(void) +{ + return 0; +} + +static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, + int *slen) +{ + SignalQuiesce *sq = (SignalQuiesce *) evt_buf_hdr; + + if (*slen < sizeof(SignalQuiesce)) { + return 0; + } + + if (!event->event_pending) { + return 0; + } + event->event_pending = false; + + sq->ebh.length = cpu_to_be16(sizeof(SignalQuiesce)); + sq->ebh.type = SCLP_EVENT_SIGNAL_QUIESCE; + sq->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED; + /* + * system_powerdown does not have a timeout. Fortunately the + * timeout value is currently ignored by Linux, anyway + */ + sq->timeout = cpu_to_be16(0); + sq->unit = cpu_to_be16(0); + *slen -= sizeof(SignalQuiesce); + + return 1; +} + +typedef struct QuiesceNotifier QuiesceNotifier; + +static struct QuiesceNotifier { + Notifier notifier; + SCLPEvent *event; +} qn; + +static void quiesce_powerdown_req(Notifier *n, void *opaque) +{ + QuiesceNotifier *qn = container_of(n, QuiesceNotifier, notifier); + SCLPEvent *event = qn->event; + + event->event_pending = true; + /* trigger SCLP read operation */ + sclp_service_interrupt(0); +} + +static int quiesce_init(SCLPEvent *event) +{ + event->event_type = SCLP_EVENT_SIGNAL_QUIESCE; + + qn.notifier.notify = quiesce_powerdown_req; + qn.event = event; + + qemu_register_powerdown_notifier(&qn.notifier); + + return 0; +} + +static void quiesce_class_init(ObjectClass *klass, void *data) +{ + SCLPEventClass *k = SCLP_EVENT_CLASS(klass); + + k->init = quiesce_init; + + k->get_send_mask = send_mask; + k->get_receive_mask = receive_mask; + k->event_type = event_type; + k->read_event_data = read_event_data; + k->write_event_data = NULL; +} + +static TypeInfo sclp_quiesce_info = { + .name = "sclpquiesce", + .parent = TYPE_SCLP_EVENT, + .instance_size = sizeof(SCLPEvent), + .class_init = quiesce_class_init, + .class_size = sizeof(SCLPEventClass), +}; + +static void register_types(void) +{ + type_register_static(&sclp_quiesce_info); +} + +type_init(register_types) @@ -26,8 +26,8 @@ #include "audio/audio.h" #include "isa.h" #include "qdev.h" -#include "qemu-timer.h" -#include "host-utils.h" +#include "qemu/timer.h" +#include "qemu/host-utils.h" #define dolog(...) AUD_log ("sb16", __VA_ARGS__) @@ -822,7 +822,6 @@ static void complete (SB16State *s) ldebug ("\n"); s->cmd = -1; - return; } static void legacy_reset (SB16State *s) @@ -52,7 +52,7 @@ static void sbi_set_irq(void *opaque, int irq, int level) { } -static uint64_t sbi_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t sbi_mem_read(void *opaque, hwaddr addr, unsigned size) { SBIState *s = opaque; @@ -69,7 +69,7 @@ static uint64_t sbi_mem_read(void *opaque, target_phys_addr_t addr, return ret; } -static void sbi_mem_write(void *opaque, target_phys_addr_t addr, +static void sbi_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned dize) { SBIState *s = opaque; diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index b8a857d145..970c1fc01b 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -1,11 +1,11 @@ #include "hw.h" -#include "qemu-error.h" +#include "qemu/error-report.h" #include "scsi.h" #include "scsi-defs.h" #include "qdev.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "trace.h" -#include "dma.h" +#include "sysemu/dma.h" static char *scsibus_get_dev_path(DeviceState *dev); static char *scsibus_get_fw_dev_path(DeviceState *dev); @@ -761,6 +761,7 @@ static int ata_passthrough_12_xfer_size(SCSIDevice *dev, uint8_t *buf) switch (length) { case 0: case 3: /* USB-specific. */ + default: xfer = 0; break; case 1: @@ -784,6 +785,7 @@ static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf) switch (length) { case 0: case 3: /* USB-specific. */ + default: xfer = 0; break; case 1: @@ -799,26 +801,39 @@ static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf) return xfer * unit; } -static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) +uint32_t scsi_data_cdb_length(uint8_t *buf) +{ + if ((buf[0] >> 5) == 0 && buf[4] == 0) { + return 256; + } else { + return scsi_cdb_length(buf); + } +} + +uint32_t scsi_cdb_length(uint8_t *buf) { switch (buf[0] >> 5) { case 0: - cmd->xfer = buf[4]; + return buf[4]; break; case 1: case 2: - cmd->xfer = lduw_be_p(&buf[7]); + return lduw_be_p(&buf[7]); break; case 4: - cmd->xfer = ldl_be_p(&buf[10]) & 0xffffffffULL; + return ldl_be_p(&buf[10]) & 0xffffffffULL; break; case 5: - cmd->xfer = ldl_be_p(&buf[6]) & 0xffffffffULL; + return ldl_be_p(&buf[6]) & 0xffffffffULL; break; default: return -1; } +} +static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) +{ + cmd->xfer = scsi_cdb_length(buf); switch (buf[0]) { case TEST_UNIT_READY: case REWIND: @@ -1708,12 +1723,8 @@ static char *scsibus_get_dev_path(DeviceState *dev) static char *scsibus_get_fw_dev_path(DeviceState *dev) { SCSIDevice *d = SCSI_DEVICE(dev); - char path[100]; - - snprintf(path, sizeof(path), "channel@%x/%s@%x,%x", d->channel, - qdev_fw_name(dev), d->id, d->lun); - - return strdup(path); + return g_strdup_printf("channel@%x/%s@%x,%x", d->channel, + qdev_fw_name(dev), d->id, d->lun); } SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun) diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h index d7a401912b..9ab045b613 100644 --- a/hw/scsi-defs.h +++ b/hw/scsi-defs.h @@ -19,6 +19,8 @@ * This header file contains public constants and structures used by * the scsi code for linux. */ +#ifndef HW_SCSI_DEFS_H +#define HW_SCSI_DEFS_H 1 /* * SCSI opcodes @@ -301,3 +303,5 @@ #define MMC_PROFILE_HDDVD_R_DL 0x0058 #define MMC_PROFILE_HDDVD_RW_DL 0x005A #define MMC_PROFILE_INVALID 0xFFFF + +#endif diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 409f760ef7..a69735b0a6 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -29,13 +29,13 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #endif #include "qemu-common.h" -#include "qemu-error.h" +#include "qemu/error-report.h" #include "scsi.h" #include "scsi-defs.h" -#include "sysemu.h" -#include "blockdev.h" +#include "sysemu/sysemu.h" +#include "sysemu/blockdev.h" #include "hw/block-common.h" -#include "dma.h" +#include "sysemu/dma.h" #ifdef __linux #include <scsi/sg.h> @@ -386,23 +386,11 @@ static void scsi_read_data(SCSIRequest *req) */ static int scsi_handle_rw_error(SCSIDiskReq *r, int error) { - int is_read = (r->req.cmd.xfer == SCSI_XFER_FROM_DEV); + bool is_read = (r->req.cmd.xfer == SCSI_XFER_FROM_DEV); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - BlockErrorAction action = bdrv_get_on_error(s->qdev.conf.bs, is_read); + BlockErrorAction action = bdrv_get_error_action(s->qdev.conf.bs, is_read, error); - if (action == BLOCK_ERR_IGNORE) { - bdrv_emit_qmp_error_event(s->qdev.conf.bs, BDRV_ACTION_IGNORE, is_read); - return 0; - } - - if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) - || action == BLOCK_ERR_STOP_ANY) { - - bdrv_emit_qmp_error_event(s->qdev.conf.bs, BDRV_ACTION_STOP, is_read); - vm_stop(RUN_STATE_IO_ERROR); - bdrv_iostatus_set_err(s->qdev.conf.bs, error); - scsi_req_retry(&r->req); - } else { + if (action == BDRV_ACTION_REPORT) { switch (error) { case ENOMEDIUM: scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); @@ -417,9 +405,12 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error) scsi_check_condition(r, SENSE_CODE(IO_ERROR)); break; } - bdrv_emit_qmp_error_event(s->qdev.conf.bs, BDRV_ACTION_REPORT, is_read); } - return 1; + bdrv_error_action(s->qdev.conf.bs, action, is_read, error); + if (action == BDRV_ACTION_STOP) { + scsi_req_retry(&r->req); + } + return action != BDRV_ACTION_IGNORE; } static void scsi_write_complete(void * opaque, int ret) @@ -661,7 +652,6 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) if (buflen > SCSI_MAX_INQUIRY_LEN) { buflen = SCSI_MAX_INQUIRY_LEN; } - memset(outbuf, 0, buflen); outbuf[0] = s->qdev.type & 0x1f; outbuf[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0; @@ -678,7 +668,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) * is actually implemented, but we're good enough. */ outbuf[2] = 5; - outbuf[3] = 2; /* Format 2 */ + outbuf[3] = 2 | 0x10; /* Format 2, HiSup */ if (buflen > 36) { outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */ @@ -1397,6 +1387,7 @@ invalid_param_len: static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf) { + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); uint8_t *p = inbuf; int cmd = r->req.cmd.buf[0]; int len = r->req.cmd.xfer; @@ -1433,6 +1424,14 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf) return; } } + if (!bdrv_enable_write_cache(s->qdev.conf.bs)) { + /* The request is used as the AIO opaque value, so add a ref. */ + scsi_req_ref(&r->req); + bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH); + r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r); + return; + } + scsi_req_complete(&r->req, GOOD); return; @@ -1446,7 +1445,22 @@ invalid_param_len: invalid_field: scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); - return; +} + +static inline bool check_lba_range(SCSIDiskState *s, + uint64_t sector_num, uint32_t nb_sectors) +{ + /* + * The first line tests that no overflow happens when computing the last + * sector. The second line tests that the last accessed sector is in + * range. + * + * Careful, the computations should not underflow for nb_sectors == 0, + * and a 0-block read to the first LBA beyond the end of device is + * valid. + */ + return (sector_num <= sector_num + nb_sectors && + sector_num + nb_sectors <= s->qdev.max_lba + 1); } typedef struct UnmapCBData { @@ -1461,7 +1475,7 @@ static void scsi_unmap_complete(void *opaque, int ret) SCSIDiskReq *r = data->r; SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); uint64_t sector_num; - uint32 nb_sectors; + uint32_t nb_sectors; r->req.aiocb = NULL; if (ret < 0) { @@ -1473,8 +1487,7 @@ static void scsi_unmap_complete(void *opaque, int ret) if (data->count > 0 && !r->req.io_canceled) { sector_num = ldq_be_p(&data->inbuf[0]); nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL; - if (sector_num > sector_num + nb_sectors || - sector_num + nb_sectors - 1 > s->qdev.max_lba) { + if (!check_lba_range(s, sector_num, nb_sectors)) { scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE)); goto done; } @@ -1529,7 +1542,6 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf) invalid_param_len: scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN)); - return; } static void scsi_disk_emulate_write_data(SCSIRequest *req) @@ -1592,24 +1604,26 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) break; } + /* + * FIXME: we shouldn't return anything bigger than 4k, but the code + * requires the buffer to be as big as req->cmd.xfer in several + * places. So, do not allow CDBs with a very large ALLOCATION + * LENGTH. The real fix would be to modify scsi_read_data and + * dma_buf_read, so that they return data beyond the buflen + * as all zeros. + */ + if (req->cmd.xfer > 65536) { + goto illegal_request; + } + r->buflen = MAX(4096, req->cmd.xfer); + if (!r->iov.iov_base) { - /* - * FIXME: we shouldn't return anything bigger than 4k, but the code - * requires the buffer to be as big as req->cmd.xfer in several - * places. So, do not allow CDBs with a very large ALLOCATION - * LENGTH. The real fix would be to modify scsi_read_data and - * dma_buf_read, so that they return data beyond the buflen - * as all zeros. - */ - if (req->cmd.xfer > 65536) { - goto illegal_request; - } - r->buflen = MAX(4096, req->cmd.xfer); r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen); } buflen = req->cmd.xfer; outbuf = r->iov.iov_base; + memset(outbuf, 0, r->buflen); switch (req->cmd.buf[0]) { case TEST_UNIT_READY: assert(!s->tray_open && bdrv_is_inserted(s->qdev.conf.bs)); @@ -1690,12 +1704,14 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) outbuf[5] = 0; outbuf[6] = s->qdev.blocksize >> 8; outbuf[7] = 0; - buflen = 8; break; case REQUEST_SENSE: /* Just return "NO SENSE". */ buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen, (req->cmd.buf[1] & 1) == 0); + if (buflen < 0) { + goto illegal_request; + } break; case MECHANISM_STATUS: buflen = scsi_emulate_mechanism_status(s, outbuf); @@ -1766,7 +1782,6 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) } /* Protection, exponent and lowest lba field left blank. */ - buflen = req->cmd.xfer; break; } DPRINTF("Unsupported Service Action In\n"); @@ -1793,17 +1808,13 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer); break; case WRITE_SAME_10: - nb_sectors = lduw_be_p(&req->cmd.buf[7]); - goto write_same; case WRITE_SAME_16: - nb_sectors = ldl_be_p(&req->cmd.buf[10]) & 0xffffffffULL; - write_same: + nb_sectors = scsi_data_cdb_length(r->req.cmd.buf); if (bdrv_is_read_only(s->qdev.conf.bs)) { scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); return 0; } - if (r->req.cmd.lba > r->req.cmd.lba + nb_sectors || - r->req.cmd.lba + nb_sectors - 1 > s->qdev.max_lba) { + if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) { goto illegal_lba; } @@ -1827,7 +1838,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) return 0; } assert(!r->req.aiocb); - r->iov.iov_len = MIN(buflen, req->cmd.xfer); + r->iov.iov_len = MIN(r->buflen, req->cmd.xfer); if (r->iov.iov_len == 0) { scsi_req_complete(&r->req, GOOD); } @@ -1858,7 +1869,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) { SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); - int32_t len; + uint32_t len; uint8_t command; command = buf[0]; @@ -1868,18 +1879,17 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) return 0; } + len = scsi_data_cdb_length(r->req.cmd.buf); switch (command) { case READ_6: case READ_10: case READ_12: case READ_16: - len = r->req.cmd.xfer / s->qdev.blocksize; - DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len); + DPRINTF("Read (sector %" PRId64 ", count %u)\n", r->req.cmd.lba, len); if (r->req.cmd.buf[1] & 0xe0) { goto illegal_request; } - if (r->req.cmd.lba > r->req.cmd.lba + len || - r->req.cmd.lba + len - 1 > s->qdev.max_lba) { + if (!check_lba_range(s, r->req.cmd.lba, len)) { goto illegal_lba; } r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512); @@ -1900,15 +1910,13 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) case VERIFY_10: case VERIFY_12: case VERIFY_16: - len = r->req.cmd.xfer / s->qdev.blocksize; - DPRINTF("Write %s(sector %" PRId64 ", count %d)\n", + DPRINTF("Write %s(sector %" PRId64 ", count %u)\n", (command & 0xe) == 0xe ? "And Verify " : "", r->req.cmd.lba, len); if (r->req.cmd.buf[1] & 0xe0) { goto illegal_request; } - if (r->req.cmd.lba > r->req.cmd.lba + len || - r->req.cmd.lba + len - 1 > s->qdev.max_lba) { + if (!check_lba_range(s, r->req.cmd.lba, len)) { goto illegal_lba; } r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512); @@ -1965,7 +1973,6 @@ static void scsi_disk_resize_cb(void *opaque) * direct-access devices. */ if (s->qdev.type == TYPE_DISK) { - scsi_device_set_ua(&s->qdev, SENSE_CODE(CAPACITY_CHANGED)); scsi_device_report_change(&s->qdev, SENSE_CODE(CAPACITY_CHANGED)); } } @@ -2421,6 +2428,7 @@ static TypeInfo scsi_cd_info = { #ifdef __linux__ static Property scsi_block_properties[] = { DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.bs), + DEFINE_PROP_INT32("bootindex", SCSIDiskState, qdev.conf.bootindex, -1), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 8d5106061e..4c702be19f 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -12,9 +12,9 @@ */ #include "qemu-common.h" -#include "qemu-error.h" +#include "qemu/error-report.h" #include "scsi.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" #ifdef __linux__ @@ -400,11 +400,11 @@ static int scsi_generic_initfn(SCSIDevice *s) return -1; } - if (bdrv_get_on_error(s->conf.bs, 0) != BLOCK_ERR_STOP_ENOSPC) { + if (bdrv_get_on_error(s->conf.bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) { error_report("Device doesn't support drive option werror"); return -1; } - if (bdrv_get_on_error(s->conf.bs, 1) != BLOCK_ERR_REPORT) { + if (bdrv_get_on_error(s->conf.bs, 1) != BLOCKDEV_ON_ERROR_REPORT) { error_report("Device doesn't support drive option rerror"); return -1; } @@ -479,7 +479,8 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, } static Property scsi_generic_properties[] = { - DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf), + DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.bs), + DEFINE_PROP_INT32("bootindex", SCSIDevice, conf.bootindex, -1), DEFINE_PROP_END_OF_LIST(), }; @@ -2,9 +2,9 @@ #define QEMU_HW_SCSI_H #include "qdev.h" -#include "block.h" +#include "block/block.h" #include "hw/block-common.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #define MAX_SCSI_DEVS 255 @@ -218,6 +218,8 @@ extern const struct SCSISense sense_code_WRITE_PROTECTED; #define SENSE_CODE(x) sense_code_ ## x +uint32_t scsi_data_cdb_length(uint8_t *buf); +uint32_t scsi_cdb_length(uint8_t *buf); int scsi_sense_valid(SCSISense sense); int scsi_build_sense(uint8_t *in_buf, int in_len, uint8_t *buf, int len, bool fixed); @@ -30,9 +30,9 @@ */ #include "hw.h" -#include "block.h" +#include "block/block.h" #include "sd.h" -#include "bitmap.h" +#include "qemu/bitmap.h" //#define DEBUG_SD 1 @@ -55,24 +55,28 @@ typedef enum { sd_illegal = -2, } sd_rsp_type_t; +enum SDCardModes { + sd_inactive, + sd_card_identification_mode, + sd_data_transfer_mode, +}; + +enum SDCardStates { + sd_inactive_state = -1, + sd_idle_state = 0, + sd_ready_state, + sd_identification_state, + sd_standby_state, + sd_transfer_state, + sd_sendingdata_state, + sd_receivingdata_state, + sd_programming_state, + sd_disconnect_state, +}; + struct SDState { - enum { - sd_inactive, - sd_card_identification_mode, - sd_data_transfer_mode, - } mode; - enum { - sd_inactive_state = -1, - sd_idle_state = 0, - sd_ready_state, - sd_identification_state, - sd_standby_state, - sd_transfer_state, - sd_sendingdata_state, - sd_receivingdata_state, - sd_programming_state, - sd_disconnect_state, - } state; + uint32_t mode; /* current card mode, one of SDCardModes */ + int32_t state; /* current card state, one of SDCardStates */ uint32_t ocr; uint8_t scr[8]; uint8_t cid[16]; @@ -83,21 +87,22 @@ struct SDState { uint32_t vhs; bool wp_switch; unsigned long *wp_groups; + int32_t wpgrps_size; uint64_t size; - int blk_len; + uint32_t blk_len; uint32_t erase_start; uint32_t erase_end; uint8_t pwd[16]; - int pwd_len; - int function_group[6]; + uint32_t pwd_len; + uint8_t function_group[6]; bool spi; - int current_cmd; + uint8_t current_cmd; /* True if we will handle the next command as an ACMD. Note that this does * *not* track the APP_CMD status bit! */ bool expecting_acmd; - int blk_written; + uint32_t blk_written; uint64_t data_start; uint32_t data_offset; uint8_t data[512]; @@ -421,8 +426,9 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv) if (sd->wp_groups) g_free(sd->wp_groups); sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : false; - sd->wp_groups = bitmap_new(sect); - memset(sd->function_group, 0, sizeof(int) * 6); + sd->wpgrps_size = sect; + sd->wp_groups = bitmap_new(sd->wpgrps_size); + memset(sd->function_group, 0, sizeof(sd->function_group)); sd->erase_start = 0; sd->erase_end = 0; sd->size = size; @@ -446,6 +452,38 @@ static const BlockDevOps sd_block_ops = { .change_media_cb = sd_cardchange, }; +static const VMStateDescription sd_vmstate = { + .name = "sd-card", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(mode, SDState), + VMSTATE_INT32(state, SDState), + VMSTATE_UINT8_ARRAY(cid, SDState, 16), + VMSTATE_UINT8_ARRAY(csd, SDState, 16), + VMSTATE_UINT16(rca, SDState), + VMSTATE_UINT32(card_status, SDState), + VMSTATE_PARTIAL_BUFFER(sd_status, SDState, 1), + VMSTATE_UINT32(vhs, SDState), + VMSTATE_BITMAP(wp_groups, SDState, 0, wpgrps_size), + VMSTATE_UINT32(blk_len, SDState), + VMSTATE_UINT32(erase_start, SDState), + VMSTATE_UINT32(erase_end, SDState), + VMSTATE_UINT8_ARRAY(pwd, SDState, 16), + VMSTATE_UINT32(pwd_len, SDState), + VMSTATE_UINT8_ARRAY(function_group, SDState, 6), + VMSTATE_UINT8(current_cmd, SDState), + VMSTATE_BOOL(expecting_acmd, SDState), + VMSTATE_UINT32(blk_written, SDState), + VMSTATE_UINT64(data_start, SDState), + VMSTATE_UINT32(data_offset, SDState), + VMSTATE_UINT8_ARRAY(data, SDState, 512), + VMSTATE_BUFFER_UNSAFE(buf, SDState, 1, 512), + VMSTATE_BOOL(enable, SDState), + VMSTATE_END_OF_LIST() + } +}; + /* We do not model the chip select pin, so allow the board to select whether card should be in SSI or MMC/SD mode. It is also up to the board to ensure that ssi transfers only occur when the chip select @@ -463,6 +501,7 @@ SDState *sd_init(BlockDriverState *bs, bool is_spi) bdrv_attach_dev_nofail(sd->bdrv, sd); bdrv_set_dev_ops(sd->bdrv, &sd_block_ops, sd); } + vmstate_register(NULL, -1, &sd_vmstate, sd); return sd; } @@ -476,19 +515,28 @@ void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert) static void sd_erase(SDState *sd) { - int i, start, end; + int i; + uint64_t erase_start = sd->erase_start; + uint64_t erase_end = sd->erase_end; + if (!sd->erase_start || !sd->erase_end) { sd->card_status |= ERASE_SEQ_ERROR; return; } - start = sd_addr_to_wpnum(sd->erase_start); - end = sd_addr_to_wpnum(sd->erase_end); + if (extract32(sd->ocr, OCR_CCS_BITN, 1)) { + /* High capacity memory card: erase units are 512 byte blocks */ + erase_start *= 512; + erase_end *= 512; + } + + erase_start = sd_addr_to_wpnum(erase_start); + erase_end = sd_addr_to_wpnum(erase_end); sd->erase_start = 0; sd->erase_end = 0; sd->csd[14] |= 0x40; - for (i = start; i <= end; i++) { + for (i = erase_start; i <= erase_end; i++) { if (test_bit(i, sd->wp_groups)) { sd->card_status |= WP_ERASE_SKIP; } @@ -567,7 +615,7 @@ static void sd_lock_command(SDState *sd) sd->card_status |= LOCK_UNLOCK_FAILED; return; } - bitmap_zero(sd->wp_groups, sd_addr_to_wpnum(sd->size) + 1); + bitmap_zero(sd->wp_groups, sd->wpgrps_size); sd->csd[14] &= ~0x10; sd->card_status &= ~CARD_IS_LOCKED; sd->pwd_len = 0; @@ -1391,8 +1439,8 @@ send_response: int i; DPRINTF("Response:"); for (i = 0; i < rsplen; i++) - printf(" %02x", response[i]); - printf(" state %d\n", sd->state); + fprintf(stderr, " %02x", response[i]); + fprintf(stderr, " state %d\n", sd->state); } else { DPRINTF("No response %d\n", sd->state); } @@ -1407,7 +1455,7 @@ static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len) DPRINTF("sd_blk_read: addr = 0x%08llx, len = %d\n", (unsigned long long) addr, len); - if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) == -1) { + if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) < 0) { fprintf(stderr, "sd_blk_read: read error on host side\n"); return; } @@ -1415,7 +1463,7 @@ static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len) if (end > (addr & ~511) + 512) { memcpy(sd->data, sd->buf + (addr & 511), 512 - (addr & 511)); - if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) == -1) { + if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) < 0) { fprintf(stderr, "sd_blk_read: read error on host side\n"); return; } @@ -1429,29 +1477,31 @@ static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len) uint64_t end = addr + len; if ((addr & 511) || len < 512) - if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) == -1) { + if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) < 0) { fprintf(stderr, "sd_blk_write: read error on host side\n"); return; } if (end > (addr & ~511) + 512) { memcpy(sd->buf + (addr & 511), sd->data, 512 - (addr & 511)); - if (bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) == -1) { + if (bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) < 0) { fprintf(stderr, "sd_blk_write: write error on host side\n"); return; } - if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) == -1) { + if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) < 0) { fprintf(stderr, "sd_blk_write: read error on host side\n"); return; } memcpy(sd->buf, sd->data + 512 - (addr & 511), end & 511); - if (bdrv_write(sd->bdrv, end >> 9, sd->buf, 1) == -1) + if (bdrv_write(sd->bdrv, end >> 9, sd->buf, 1) < 0) { fprintf(stderr, "sd_blk_write: write error on host side\n"); + } } else { memcpy(sd->buf + (addr & 511), sd->data, len); - if (!sd->bdrv || bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) == -1) + if (!sd->bdrv || bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) < 0) { fprintf(stderr, "sd_blk_write: write error on host side\n"); + } } } @@ -50,6 +50,7 @@ #define READY_FOR_DATA (1 << 8) #define APP_CMD (1 << 5) #define AKE_SEQ_ERROR (1 << 3) +#define OCR_CCS_BITN 30 typedef enum { sd_none = -1, diff --git a/hw/serial-isa.c b/hw/serial-isa.c new file mode 100644 index 0000000000..96c78f7f8d --- /dev/null +++ b/hw/serial-isa.c @@ -0,0 +1,130 @@ +/* + * QEMU 16550A UART emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2008 Citrix Systems, Inc. + * + * 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. + */ + +#include "serial.h" +#include "isa.h" + +typedef struct ISASerialState { + ISADevice dev; + uint32_t index; + uint32_t iobase; + uint32_t isairq; + SerialState state; +} ISASerialState; + +static const int isa_serial_io[MAX_SERIAL_PORTS] = { + 0x3f8, 0x2f8, 0x3e8, 0x2e8 +}; +static const int isa_serial_irq[MAX_SERIAL_PORTS] = { + 4, 3, 4, 3 +}; + +static int serial_isa_initfn(ISADevice *dev) +{ + static int index; + ISASerialState *isa = DO_UPCAST(ISASerialState, dev, dev); + SerialState *s = &isa->state; + + if (isa->index == -1) { + isa->index = index; + } + if (isa->index >= MAX_SERIAL_PORTS) { + return -1; + } + if (isa->iobase == -1) { + isa->iobase = isa_serial_io[isa->index]; + } + if (isa->isairq == -1) { + isa->isairq = isa_serial_irq[isa->index]; + } + index++; + + s->baudbase = 115200; + isa_init_irq(dev, &s->irq, isa->isairq); + serial_init_core(s); + qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 3); + + memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8); + isa_register_ioport(dev, &s->io, isa->iobase); + return 0; +} + +static const VMStateDescription vmstate_isa_serial = { + .name = "serial", + .version_id = 3, + .minimum_version_id = 2, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(state, ISASerialState, 0, vmstate_serial, SerialState), + VMSTATE_END_OF_LIST() + } +}; + +static Property serial_isa_properties[] = { + DEFINE_PROP_UINT32("index", ISASerialState, index, -1), + DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1), + DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1), + DEFINE_PROP_CHR("chardev", ISASerialState, state.chr), + DEFINE_PROP_UINT32("wakeup", ISASerialState, state.wakeup, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void serial_isa_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = serial_isa_initfn; + dc->vmsd = &vmstate_isa_serial; + dc->props = serial_isa_properties; +} + +static TypeInfo serial_isa_info = { + .name = "isa-serial", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISASerialState), + .class_init = serial_isa_class_initfn, +}; + +static void serial_register_types(void) +{ + type_register_static(&serial_isa_info); +} + +type_init(serial_register_types) + +bool serial_isa_init(ISABus *bus, int index, CharDriverState *chr) +{ + ISADevice *dev; + + dev = isa_try_create(bus, "isa-serial"); + if (!dev) { + return false; + } + qdev_prop_set_uint32(&dev->qdev, "index", index); + qdev_prop_set_chr(&dev->qdev, "chardev", chr); + if (qdev_init(&dev->qdev) < 0) { + return false; + } + return true; +} diff --git a/hw/serial-pci.c b/hw/serial-pci.c new file mode 100644 index 0000000000..6a2548a515 --- /dev/null +++ b/hw/serial-pci.c @@ -0,0 +1,252 @@ +/* + * QEMU 16550A UART emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2008 Citrix Systems, Inc. + * + * 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. + */ + +/* see docs/specs/pci-serial.txt */ + +#include "serial.h" +#include "pci/pci.h" + +#define PCI_SERIAL_MAX_PORTS 4 + +typedef struct PCISerialState { + PCIDevice dev; + SerialState state; +} PCISerialState; + +typedef struct PCIMultiSerialState { + PCIDevice dev; + MemoryRegion iobar; + uint32_t ports; + char *name[PCI_SERIAL_MAX_PORTS]; + SerialState state[PCI_SERIAL_MAX_PORTS]; + uint32_t level[PCI_SERIAL_MAX_PORTS]; + qemu_irq *irqs; +} PCIMultiSerialState; + +static int serial_pci_init(PCIDevice *dev) +{ + PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); + SerialState *s = &pci->state; + + s->baudbase = 115200; + serial_init_core(s); + + pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; + s->irq = pci->dev.irq[0]; + + memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8); + pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io); + return 0; +} + +static void multi_serial_irq_mux(void *opaque, int n, int level) +{ + PCIMultiSerialState *pci = opaque; + int i, pending = 0; + + pci->level[n] = level; + for (i = 0; i < pci->ports; i++) { + if (pci->level[i]) { + pending = 1; + } + } + qemu_set_irq(pci->dev.irq[0], pending); +} + +static int multi_serial_pci_init(PCIDevice *dev) +{ + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); + PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev); + SerialState *s; + int i; + + switch (pc->device_id) { + case 0x0003: + pci->ports = 2; + break; + case 0x0004: + pci->ports = 4; + break; + } + assert(pci->ports > 0); + assert(pci->ports <= PCI_SERIAL_MAX_PORTS); + + pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; + memory_region_init(&pci->iobar, "multiserial", 8 * pci->ports); + pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar); + pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci, + pci->ports); + + for (i = 0; i < pci->ports; i++) { + s = pci->state + i; + s->baudbase = 115200; + serial_init_core(s); + s->irq = pci->irqs[i]; + pci->name[i] = g_strdup_printf("uart #%d", i+1); + memory_region_init_io(&s->io, &serial_io_ops, s, pci->name[i], 8); + memory_region_add_subregion(&pci->iobar, 8 * i, &s->io); + } + return 0; +} + +static void serial_pci_exit(PCIDevice *dev) +{ + PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); + SerialState *s = &pci->state; + + serial_exit_core(s); + memory_region_destroy(&s->io); +} + +static void multi_serial_pci_exit(PCIDevice *dev) +{ + PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev); + SerialState *s; + int i; + + for (i = 0; i < pci->ports; i++) { + s = pci->state + i; + serial_exit_core(s); + memory_region_destroy(&s->io); + g_free(pci->name[i]); + } + memory_region_destroy(&pci->iobar); + qemu_free_irqs(pci->irqs); +} + +static const VMStateDescription vmstate_pci_serial = { + .name = "pci-serial", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, PCISerialState), + VMSTATE_STRUCT(state, PCISerialState, 0, vmstate_serial, SerialState), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_pci_multi_serial = { + .name = "pci-serial-multi", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, PCIMultiSerialState), + VMSTATE_STRUCT_ARRAY(state, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS, + 0, vmstate_serial, SerialState), + VMSTATE_UINT32_ARRAY(level, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS), + VMSTATE_END_OF_LIST() + } +}; + +static Property serial_pci_properties[] = { + DEFINE_PROP_CHR("chardev", PCISerialState, state.chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static Property multi_2x_serial_pci_properties[] = { + DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr), + DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static Property multi_4x_serial_pci_properties[] = { + DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr), + DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), + DEFINE_PROP_CHR("chardev3", PCIMultiSerialState, state[2].chr), + DEFINE_PROP_CHR("chardev4", PCIMultiSerialState, state[3].chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void serial_pci_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); + pc->init = serial_pci_init; + pc->exit = serial_pci_exit; + pc->vendor_id = 0x1b36; /* Red Hat */ + pc->device_id = 0x0002; + pc->revision = 1; + pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; + dc->vmsd = &vmstate_pci_serial; + dc->props = serial_pci_properties; +} + +static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); + pc->init = multi_serial_pci_init; + pc->exit = multi_serial_pci_exit; + pc->vendor_id = 0x1b36; /* Red Hat */ + pc->device_id = 0x0003; + pc->revision = 1; + pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; + dc->vmsd = &vmstate_pci_multi_serial; + dc->props = multi_2x_serial_pci_properties; +} + +static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); + pc->init = multi_serial_pci_init; + pc->exit = multi_serial_pci_exit; + pc->vendor_id = 0x1b36; /* Red Hat */ + pc->device_id = 0x0004; + pc->revision = 1; + pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; + dc->vmsd = &vmstate_pci_multi_serial; + dc->props = multi_4x_serial_pci_properties; +} + +static TypeInfo serial_pci_info = { + .name = "pci-serial", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCISerialState), + .class_init = serial_pci_class_initfn, +}; + +static TypeInfo multi_2x_serial_pci_info = { + .name = "pci-serial-2x", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIMultiSerialState), + .class_init = multi_2x_serial_pci_class_initfn, +}; + +static TypeInfo multi_4x_serial_pci_info = { + .name = "pci-serial-4x", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIMultiSerialState), + .class_init = multi_4x_serial_pci_class_initfn, +}; + +static void serial_pci_register_types(void) +{ + type_register_static(&serial_pci_info); + type_register_static(&multi_2x_serial_pci_info); + type_register_static(&multi_4x_serial_pci_info); +} + +type_init(serial_pci_register_types) diff --git a/hw/serial.c b/hw/serial.c index a421d1e7bc..a5b2a0c609 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -22,12 +22,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "qemu-char.h" -#include "isa.h" -#include "pc.h" -#include "qemu-timer.h" -#include "sysemu.h" + +#include "serial.h" +#include "char/char.h" +#include "qemu/timer.h" +#include "exec/address-spaces.h" //#define DEBUG_SERIAL @@ -93,8 +92,6 @@ #define UART_FCR_RFR 0x02 /* RCVR Fifo Reset */ #define UART_FCR_FE 0x01 /* FIFO Enable */ -#define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */ - #define XMIT_FIFO 0 #define RECV_FIFO 1 #define MAX_XMIT_RETRY 4 @@ -107,64 +104,6 @@ do { fprintf(stderr, "serial: " fmt , ## __VA_ARGS__); } while (0) do {} while (0) #endif -typedef struct SerialFIFO { - uint8_t data[UART_FIFO_LENGTH]; - uint8_t count; - uint8_t itl; /* Interrupt Trigger Level */ - uint8_t tail; - uint8_t head; -} SerialFIFO; - -struct SerialState { - uint16_t divider; - uint8_t rbr; /* receive register */ - uint8_t thr; /* transmit holding register */ - uint8_t tsr; /* transmit shift register */ - uint8_t ier; - uint8_t iir; /* read only */ - uint8_t lcr; - uint8_t mcr; - uint8_t lsr; /* read only */ - uint8_t msr; /* read only */ - uint8_t scr; - uint8_t fcr; - uint8_t fcr_vmstate; /* we can't write directly this value - it has side effects */ - /* NOTE: this hidden state is necessary for tx irq generation as - it can be reset while reading iir */ - int thr_ipending; - qemu_irq irq; - CharDriverState *chr; - int last_break_enable; - int it_shift; - int baudbase; - int tsr_retry; - uint32_t wakeup; - - uint64_t last_xmit_ts; /* Time when the last byte was successfully sent out of the tsr */ - SerialFIFO recv_fifo; - SerialFIFO xmit_fifo; - - struct QEMUTimer *fifo_timeout_timer; - int timeout_ipending; /* timeout interrupt pending state */ - struct QEMUTimer *transmit_timer; - - - uint64_t char_transmit_time; /* time to transmit a char in ticks*/ - int poll_msl; - - struct QEMUTimer *modem_status_poll; - MemoryRegion io; -}; - -typedef struct ISASerialState { - ISADevice dev; - uint32_t index; - uint32_t iobase; - uint32_t isairq; - SerialState state; -} ISASerialState; - static void serial_receive1(void *opaque, const uint8_t *buf, int size); static void fifo_clear(SerialState *s, int fifo) @@ -367,7 +306,8 @@ static void serial_xmit(void *opaque) } -static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) { SerialState *s = opaque; @@ -513,7 +453,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t serial_ioport_read(void *opaque, uint32_t addr) +static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size) { SerialState *s = opaque; uint32_t ret; @@ -682,12 +622,12 @@ static int serial_post_load(void *opaque, int version_id) s->fcr_vmstate = 0; } /* Initialize fcr via setter to perform essential side-effects */ - serial_ioport_write(s, 0x02, s->fcr_vmstate); + serial_ioport_write(s, 0x02, s->fcr_vmstate, 1); serial_update_parameters(s); return 0; } -static const VMStateDescription vmstate_serial = { +const VMStateDescription vmstate_serial = { .name = "serial", .version_id = 3, .minimum_version_id = 2, @@ -736,7 +676,7 @@ static void serial_reset(void *opaque) qemu_irq_lower(s->irq); } -static void serial_init_core(SerialState *s) +void serial_init_core(SerialState *s) { if (!s->chr) { fprintf(stderr, "Can't create serial device, empty char device\n"); @@ -754,6 +694,12 @@ static void serial_init_core(SerialState *s) serial_event, s); } +void serial_exit_core(SerialState *s) +{ + qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL); + qemu_unregister_reset(serial_reset, s); +} + /* Change the main reference oscillator frequency. */ void serial_set_frequency(SerialState *s, uint32_t frequency) { @@ -761,56 +707,18 @@ void serial_set_frequency(SerialState *s, uint32_t frequency) serial_update_parameters(s); } -static const int isa_serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; -static const int isa_serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; - -static const MemoryRegionPortio serial_portio[] = { - { 0, 8, 1, .read = serial_ioport_read, .write = serial_ioport_write }, - PORTIO_END_OF_LIST() -}; - -static const MemoryRegionOps serial_io_ops = { - .old_portio = serial_portio -}; - -static int serial_isa_initfn(ISADevice *dev) -{ - static int index; - ISASerialState *isa = DO_UPCAST(ISASerialState, dev, dev); - SerialState *s = &isa->state; - - if (isa->index == -1) - isa->index = index; - if (isa->index >= MAX_SERIAL_PORTS) - return -1; - if (isa->iobase == -1) - isa->iobase = isa_serial_io[isa->index]; - if (isa->isairq == -1) - isa->isairq = isa_serial_irq[isa->index]; - index++; - - s->baudbase = 115200; - isa_init_irq(dev, &s->irq, isa->isairq); - serial_init_core(s); - qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 3); - - memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8); - isa_register_ioport(dev, &s->io, isa->iobase); - return 0; -} - -static const VMStateDescription vmstate_isa_serial = { - .name = "serial", - .version_id = 3, - .minimum_version_id = 2, - .fields = (VMStateField []) { - VMSTATE_STRUCT(state, ISASerialState, 0, vmstate_serial, SerialState), - VMSTATE_END_OF_LIST() - } +const MemoryRegionOps serial_io_ops = { + .read = serial_ioport_read, + .write = serial_ioport_write, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; SerialState *serial_init(int base, qemu_irq irq, int baudbase, - CharDriverState *chr) + CharDriverState *chr, MemoryRegion *system_io) { SerialState *s; @@ -823,25 +731,26 @@ SerialState *serial_init(int base, qemu_irq irq, int baudbase, vmstate_register(NULL, base, &vmstate_serial, s); - register_ioport_write(base, 8, 1, serial_ioport_write, s); - register_ioport_read(base, 8, 1, serial_ioport_read, s); + memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8); + memory_region_add_subregion(system_io, base, &s->io); + return s; } /* Memory mapped interface */ -static uint64_t serial_mm_read(void *opaque, target_phys_addr_t addr, +static uint64_t serial_mm_read(void *opaque, hwaddr addr, unsigned size) { SerialState *s = opaque; - return serial_ioport_read(s, addr >> s->it_shift); + return serial_ioport_read(s, addr >> s->it_shift, 1); } -static void serial_mm_write(void *opaque, target_phys_addr_t addr, +static void serial_mm_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { SerialState *s = opaque; value &= ~0u >> (32 - (size * 8)); - serial_ioport_write(s, addr >> s->it_shift, value); + serial_ioport_write(s, addr >> s->it_shift, value, 1); } static const MemoryRegionOps serial_mm_ops[3] = { @@ -863,7 +772,7 @@ static const MemoryRegionOps serial_mm_ops[3] = { }; SerialState *serial_mm_init(MemoryRegion *address_space, - target_phys_addr_t base, int it_shift, + hwaddr base, int it_shift, qemu_irq irq, int baudbase, CharDriverState *chr, enum device_endian end) { @@ -886,35 +795,3 @@ SerialState *serial_mm_init(MemoryRegion *address_space, serial_update_msl(s); return s; } - -static Property serial_isa_properties[] = { - DEFINE_PROP_UINT32("index", ISASerialState, index, -1), - DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1), - DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1), - DEFINE_PROP_CHR("chardev", ISASerialState, state.chr), - DEFINE_PROP_UINT32("wakeup", ISASerialState, state.wakeup, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void serial_isa_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); - ic->init = serial_isa_initfn; - dc->vmsd = &vmstate_isa_serial; - dc->props = serial_isa_properties; -} - -static TypeInfo serial_isa_info = { - .name = "isa-serial", - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(ISASerialState), - .class_init = serial_isa_class_initfn, -}; - -static void serial_register_types(void) -{ - type_register_static(&serial_isa_info); -} - -type_init(serial_register_types) diff --git a/hw/serial.h b/hw/serial.h new file mode 100644 index 0000000000..98ee4241be --- /dev/null +++ b/hw/serial.h @@ -0,0 +1,103 @@ +/* + * QEMU 16550A UART emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2008 Citrix Systems, Inc. + * + * 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. + */ +#ifndef HW_SERIAL_H +#define HW_SERIAL_H 1 + +#include "hw.h" +#include "sysemu/sysemu.h" +#include "exec/memory.h" + +#define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */ + +typedef struct SerialFIFO { + uint8_t data[UART_FIFO_LENGTH]; + uint8_t count; + uint8_t itl; /* Interrupt Trigger Level */ + uint8_t tail; + uint8_t head; +} SerialFIFO; + +struct SerialState { + uint16_t divider; + uint8_t rbr; /* receive register */ + uint8_t thr; /* transmit holding register */ + uint8_t tsr; /* transmit shift register */ + uint8_t ier; + uint8_t iir; /* read only */ + uint8_t lcr; + uint8_t mcr; + uint8_t lsr; /* read only */ + uint8_t msr; /* read only */ + uint8_t scr; + uint8_t fcr; + uint8_t fcr_vmstate; /* we can't write directly this value + it has side effects */ + /* NOTE: this hidden state is necessary for tx irq generation as + it can be reset while reading iir */ + int thr_ipending; + qemu_irq irq; + CharDriverState *chr; + int last_break_enable; + int it_shift; + int baudbase; + int tsr_retry; + uint32_t wakeup; + + /* Time when the last byte was successfully sent out of the tsr */ + uint64_t last_xmit_ts; + SerialFIFO recv_fifo; + SerialFIFO xmit_fifo; + + struct QEMUTimer *fifo_timeout_timer; + int timeout_ipending; /* timeout interrupt pending state */ + struct QEMUTimer *transmit_timer; + + + uint64_t char_transmit_time; /* time to transmit a char in ticks */ + int poll_msl; + + struct QEMUTimer *modem_status_poll; + MemoryRegion io; +}; + +extern const VMStateDescription vmstate_serial; +extern const MemoryRegionOps serial_io_ops; + +void serial_init_core(SerialState *s); +void serial_exit_core(SerialState *s); +void serial_set_frequency(SerialState *s, uint32_t frequency); + +/* legacy pre qom */ +SerialState *serial_init(int base, qemu_irq irq, int baudbase, + CharDriverState *chr, MemoryRegion *system_io); +SerialState *serial_mm_init(MemoryRegion *address_space, + hwaddr base, int it_shift, + qemu_irq irq, int baudbase, + CharDriverState *chr, enum device_endian end); + +/* serial-isa.c */ +bool serial_isa_init(ISABus *bus, int index, CharDriverState *chr); + +#endif @@ -24,10 +24,10 @@ * sgabios code originally available at code.google.com/p/sgabios * */ -#include "pci.h" +#include "pci/pci.h" #include "pc.h" #include "loader.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #define SGABIOS_FILENAME "sgabios.bin" @@ -31,7 +31,7 @@ int sh7750_register_io_device(struct SH7750State *s, #define TMU012_FEAT_TOCR (1 << 0) #define TMU012_FEAT_3CHAN (1 << 1) #define TMU012_FEAT_EXTCLK (1 << 2) -void tmu012_init(struct MemoryRegion *sysmem, target_phys_addr_t base, +void tmu012_init(struct MemoryRegion *sysmem, hwaddr base, int feat, uint32_t freq, qemu_irq ch0_irq, qemu_irq ch1_irq, qemu_irq ch2_irq0, qemu_irq ch2_irq1); @@ -40,7 +40,7 @@ void tmu012_init(struct MemoryRegion *sysmem, target_phys_addr_t base, /* sh_serial.c */ #define SH_SERIAL_FEAT_SCIF (1 << 0) void sh_serial_init(MemoryRegion *sysmem, - target_phys_addr_t base, int feat, + hwaddr base, int feat, uint32_t freq, CharDriverState *chr, qemu_irq eri_source, qemu_irq rxi_source, diff --git a/hw/sh7750.c b/hw/sh7750.c index e7129283d1..666f8655ed 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -25,12 +25,12 @@ #include <stdio.h> #include "hw.h" #include "sh.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "sh7750_regs.h" #include "sh7750_regnames.h" #include "sh_intc.h" #include "cpu.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #define NB_DEVICES 4 @@ -197,19 +197,19 @@ static void portb_changed(SH7750State * s, uint16_t prev) Memory **********************************************************************/ -static void error_access(const char *kind, target_phys_addr_t addr) +static void error_access(const char *kind, hwaddr addr) { fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") not supported\n", kind, regname(addr), addr); } -static void ignore_access(const char *kind, target_phys_addr_t addr) +static void ignore_access(const char *kind, hwaddr addr) { fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") ignored\n", kind, regname(addr), addr); } -static uint32_t sh7750_mem_readb(void *opaque, target_phys_addr_t addr) +static uint32_t sh7750_mem_readb(void *opaque, hwaddr addr) { switch (addr) { default: @@ -218,7 +218,7 @@ static uint32_t sh7750_mem_readb(void *opaque, target_phys_addr_t addr) } } -static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr) +static uint32_t sh7750_mem_readw(void *opaque, hwaddr addr) { SH7750State *s = opaque; @@ -252,7 +252,7 @@ static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr) } } -static uint32_t sh7750_mem_readl(void *opaque, target_phys_addr_t addr) +static uint32_t sh7750_mem_readl(void *opaque, hwaddr addr) { SH7750State *s = opaque; @@ -301,7 +301,7 @@ static uint32_t sh7750_mem_readl(void *opaque, target_phys_addr_t addr) #define is_in_sdrmx(a, x) (a >= SH7750_SDMR ## x ## _A7 \ && a <= (SH7750_SDMR ## x ## _A7 + SH7750_SDMR ## x ## _REGNB)) -static void sh7750_mem_writeb(void *opaque, target_phys_addr_t addr, +static void sh7750_mem_writeb(void *opaque, hwaddr addr, uint32_t mem_value) { @@ -314,7 +314,7 @@ static void sh7750_mem_writeb(void *opaque, target_phys_addr_t addr, abort(); } -static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr, +static void sh7750_mem_writew(void *opaque, hwaddr addr, uint32_t mem_value) { SH7750State *s = opaque; @@ -366,7 +366,7 @@ static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr, } } -static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr, +static void sh7750_mem_writel(void *opaque, hwaddr addr, uint32_t mem_value) { SH7750State *s = opaque; @@ -624,14 +624,14 @@ static struct intc_group groups_irl[] = { #define MM_UTLB_DATA (7) #define MM_REGION_TYPE(addr) ((addr & MM_REGION_MASK) >> 24) -static uint64_t invalid_read(void *opaque, target_phys_addr_t addr) +static uint64_t invalid_read(void *opaque, hwaddr addr) { abort(); return 0; } -static uint64_t sh7750_mmct_read(void *opaque, target_phys_addr_t addr, +static uint64_t sh7750_mmct_read(void *opaque, hwaddr addr, unsigned size) { SH7750State *s = opaque; @@ -669,13 +669,13 @@ static uint64_t sh7750_mmct_read(void *opaque, target_phys_addr_t addr, return ret; } -static void invalid_write(void *opaque, target_phys_addr_t addr, +static void invalid_write(void *opaque, hwaddr addr, uint64_t mem_value) { abort(); } -static void sh7750_mmct_write(void *opaque, target_phys_addr_t addr, +static void sh7750_mmct_write(void *opaque, hwaddr addr, uint64_t mem_value, unsigned size) { SH7750State *s = opaque; diff --git a/hw/sh_intc.c b/hw/sh_intc.c index 7d31ced858..c3f77d5092 100644 --- a/hw/sh_intc.c +++ b/hw/sh_intc.c @@ -219,7 +219,7 @@ static void sh_intc_toggle_mask(struct intc_desc *desc, intc_enum id, #endif } -static uint64_t sh_intc_read(void *opaque, target_phys_addr_t offset, +static uint64_t sh_intc_read(void *opaque, hwaddr offset, unsigned size) { struct intc_desc *desc = opaque; @@ -238,7 +238,7 @@ static uint64_t sh_intc_read(void *opaque, target_phys_addr_t offset, return *valuep; } -static void sh_intc_write(void *opaque, target_phys_addr_t offset, +static void sh_intc_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { struct intc_desc *desc = opaque; diff --git a/hw/sh_intc.h b/hw/sh_intc.h index 80c9430577..6f11beeddd 100644 --- a/hw/sh_intc.h +++ b/hw/sh_intc.h @@ -3,7 +3,7 @@ #include "qemu-common.h" #include "irq.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" typedef unsigned char intc_enum; diff --git a/hw/sh_pci.c b/hw/sh_pci.c index 0cfac46f7f..018b1c198b 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -23,10 +23,10 @@ */ #include "sysbus.h" #include "sh.h" -#include "pci.h" -#include "pci_host.h" -#include "bswap.h" -#include "exec-memory.h" +#include "pci/pci.h" +#include "pci/pci_host.h" +#include "qemu/bswap.h" +#include "exec/address-spaces.h" typedef struct SHPCIState { SysBusDevice busdev; @@ -41,7 +41,7 @@ typedef struct SHPCIState { uint32_t iobr; } SHPCIState; -static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint64_t val, +static void sh_pci_reg_write (void *p, hwaddr addr, uint64_t val, unsigned size) { SHPCIState *pcic = p; @@ -69,7 +69,7 @@ static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint64_t val, } } -static uint64_t sh_pci_reg_read (void *p, target_phys_addr_t addr, +static uint64_t sh_pci_reg_read (void *p, hwaddr addr, unsigned size) { SHPCIState *pcic = p; diff --git a/hw/sh_serial.c b/hw/sh_serial.c index 1d1883dd20..21c5b1362d 100644 --- a/hw/sh_serial.c +++ b/hw/sh_serial.c @@ -26,8 +26,8 @@ */ #include "hw.h" #include "sh.h" -#include "qemu-char.h" -#include "exec-memory.h" +#include "char/char.h" +#include "exec/address-spaces.h" //#define DEBUG_SERIAL @@ -78,7 +78,7 @@ static void sh_serial_clear_fifo(sh_serial_state * s) s->rx_tail = 0; } -static void sh_serial_write(void *opaque, target_phys_addr_t offs, +static void sh_serial_write(void *opaque, hwaddr offs, uint64_t val, unsigned size) { sh_serial_state *s = opaque; @@ -187,11 +187,11 @@ static void sh_serial_write(void *opaque, target_phys_addr_t offs, } fprintf(stderr, "sh_serial: unsupported write to 0x%02" - TARGET_PRIxPHYS "\n", offs); + HWADDR_PRIx "\n", offs); abort(); } -static uint64_t sh_serial_read(void *opaque, target_phys_addr_t offs, +static uint64_t sh_serial_read(void *opaque, hwaddr offs, unsigned size) { sh_serial_state *s = opaque; @@ -289,7 +289,7 @@ static uint64_t sh_serial_read(void *opaque, target_phys_addr_t offs, if (ret & ~((1 << 16) - 1)) { fprintf(stderr, "sh_serial: unsupported read from 0x%02" - TARGET_PRIxPHYS "\n", offs); + HWADDR_PRIx "\n", offs); abort(); } @@ -353,7 +353,7 @@ static const MemoryRegionOps sh_serial_ops = { }; void sh_serial_init(MemoryRegion *sysmem, - target_phys_addr_t base, int feat, + hwaddr base, int feat, uint32_t freq, CharDriverState *chr, qemu_irq eri_source, qemu_irq rxi_source, diff --git a/hw/sh_timer.c b/hw/sh_timer.c index 64bf604ba4..64ea23fce6 100644 --- a/hw/sh_timer.c +++ b/hw/sh_timer.c @@ -10,8 +10,8 @@ #include "hw.h" #include "sh.h" -#include "qemu-timer.h" -#include "exec-memory.h" +#include "qemu/timer.h" +#include "exec/address-spaces.h" #include "ptimer.h" //#define DEBUG_TIMER @@ -59,7 +59,7 @@ static void sh_timer_update(sh_timer_state *s) s->int_level = new_level; } -static uint32_t sh_timer_read(void *opaque, target_phys_addr_t offset) +static uint32_t sh_timer_read(void *opaque, hwaddr offset) { sh_timer_state *s = (sh_timer_state *)opaque; @@ -79,7 +79,7 @@ static uint32_t sh_timer_read(void *opaque, target_phys_addr_t offset) } } -static void sh_timer_write(void *opaque, target_phys_addr_t offset, +static void sh_timer_write(void *opaque, hwaddr offset, uint32_t value) { sh_timer_state *s = (sh_timer_state *)opaque; @@ -222,7 +222,7 @@ typedef struct { int feat; } tmu012_state; -static uint64_t tmu012_read(void *opaque, target_phys_addr_t offset, +static uint64_t tmu012_read(void *opaque, hwaddr offset, unsigned size) { tmu012_state *s = (tmu012_state *)opaque; @@ -253,7 +253,7 @@ static uint64_t tmu012_read(void *opaque, target_phys_addr_t offset, return 0; } -static void tmu012_write(void *opaque, target_phys_addr_t offset, +static void tmu012_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { tmu012_state *s = (tmu012_state *)opaque; @@ -303,7 +303,7 @@ static const MemoryRegionOps tmu012_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -void tmu012_init(MemoryRegion *sysmem, target_phys_addr_t base, +void tmu012_init(MemoryRegion *sysmem, hwaddr base, int feat, uint32_t freq, qemu_irq ch0_irq, qemu_irq ch1_irq, qemu_irq ch2_irq0, qemu_irq ch2_irq1) diff --git a/hw/sharpsl.h b/hw/sharpsl.h index 0b3a774f2f..13981a6d03 100644 --- a/hw/sharpsl.h +++ b/hw/sharpsl.h @@ -12,6 +12,6 @@ /* zaurus.c */ #define SL_PXA_PARAM_BASE 0xa0000a00 -void sl_bootparam_write(target_phys_addr_t ptr); +void sl_bootparam_write(hwaddr ptr); #endif @@ -29,19 +29,17 @@ */ #include "hw.h" #include "sh.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "boards.h" #include "loader.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #define BIOS_FILENAME "shix_bios.bin" #define BIOS_ADDRESS 0xA0000000 -static void shix_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void shix_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; int ret; CPUSH4State *env; struct SH7750State *s; diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 7fdc3be086..a44ce95c1f 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -23,7 +23,7 @@ */ #include "sun4m.h" -#include "monitor.h" +#include "monitor/monitor.h" #include "sysbus.h" #include "trace.h" @@ -78,7 +78,7 @@ typedef struct SLAVIO_INTCTLState { static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs); // per-cpu interrupt controller -static uint64_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr, +static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr, unsigned size) { SLAVIO_CPUINTCTLState *s = opaque; @@ -98,7 +98,7 @@ static uint64_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr, return ret; } -static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, +static void slavio_intctl_mem_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { SLAVIO_CPUINTCTLState *s = opaque; @@ -135,7 +135,7 @@ static const MemoryRegionOps slavio_intctl_mem_ops = { }; // master system interrupt controller -static uint64_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr, +static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr, unsigned size) { SLAVIO_INTCTLState *s = opaque; @@ -161,7 +161,7 @@ static uint64_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr, return ret; } -static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, +static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { SLAVIO_INTCTLState *s = opaque; diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 944835e880..704f2b173b 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "sysbus.h" #include "trace.h" @@ -107,7 +107,7 @@ static void slavio_set_power_fail(void *opaque, int irq, int power_failing) slavio_misc_update_irq(s); } -static void slavio_cfg_mem_writeb(void *opaque, target_phys_addr_t addr, +static void slavio_cfg_mem_writeb(void *opaque, hwaddr addr, uint64_t val, unsigned size) { MiscState *s = opaque; @@ -117,7 +117,7 @@ static void slavio_cfg_mem_writeb(void *opaque, target_phys_addr_t addr, slavio_misc_update_irq(s); } -static uint64_t slavio_cfg_mem_readb(void *opaque, target_phys_addr_t addr, +static uint64_t slavio_cfg_mem_readb(void *opaque, hwaddr addr, unsigned size) { MiscState *s = opaque; @@ -138,7 +138,7 @@ static const MemoryRegionOps slavio_cfg_mem_ops = { }, }; -static void slavio_diag_mem_writeb(void *opaque, target_phys_addr_t addr, +static void slavio_diag_mem_writeb(void *opaque, hwaddr addr, uint64_t val, unsigned size) { MiscState *s = opaque; @@ -147,7 +147,7 @@ static void slavio_diag_mem_writeb(void *opaque, target_phys_addr_t addr, s->diag = val & 0xff; } -static uint64_t slavio_diag_mem_readb(void *opaque, target_phys_addr_t addr, +static uint64_t slavio_diag_mem_readb(void *opaque, hwaddr addr, unsigned size) { MiscState *s = opaque; @@ -168,7 +168,7 @@ static const MemoryRegionOps slavio_diag_mem_ops = { }, }; -static void slavio_mdm_mem_writeb(void *opaque, target_phys_addr_t addr, +static void slavio_mdm_mem_writeb(void *opaque, hwaddr addr, uint64_t val, unsigned size) { MiscState *s = opaque; @@ -177,7 +177,7 @@ static void slavio_mdm_mem_writeb(void *opaque, target_phys_addr_t addr, s->mctrl = val & 0xff; } -static uint64_t slavio_mdm_mem_readb(void *opaque, target_phys_addr_t addr, +static uint64_t slavio_mdm_mem_readb(void *opaque, hwaddr addr, unsigned size) { MiscState *s = opaque; @@ -198,7 +198,7 @@ static const MemoryRegionOps slavio_mdm_mem_ops = { }, }; -static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr, +static void slavio_aux1_mem_writeb(void *opaque, hwaddr addr, uint64_t val, unsigned size) { MiscState *s = opaque; @@ -215,7 +215,7 @@ static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr, s->aux1 = val & 0xff; } -static uint64_t slavio_aux1_mem_readb(void *opaque, target_phys_addr_t addr, +static uint64_t slavio_aux1_mem_readb(void *opaque, hwaddr addr, unsigned size) { MiscState *s = opaque; @@ -236,7 +236,7 @@ static const MemoryRegionOps slavio_aux1_mem_ops = { }, }; -static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr, +static void slavio_aux2_mem_writeb(void *opaque, hwaddr addr, uint64_t val, unsigned size) { MiscState *s = opaque; @@ -252,7 +252,7 @@ static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr, slavio_misc_update_irq(s); } -static uint64_t slavio_aux2_mem_readb(void *opaque, target_phys_addr_t addr, +static uint64_t slavio_aux2_mem_readb(void *opaque, hwaddr addr, unsigned size) { MiscState *s = opaque; @@ -273,7 +273,7 @@ static const MemoryRegionOps slavio_aux2_mem_ops = { }, }; -static void apc_mem_writeb(void *opaque, target_phys_addr_t addr, +static void apc_mem_writeb(void *opaque, hwaddr addr, uint64_t val, unsigned size) { APCState *s = opaque; @@ -282,7 +282,7 @@ static void apc_mem_writeb(void *opaque, target_phys_addr_t addr, qemu_irq_raise(s->cpu_halt); } -static uint64_t apc_mem_readb(void *opaque, target_phys_addr_t addr, +static uint64_t apc_mem_readb(void *opaque, hwaddr addr, unsigned size) { uint32_t ret = 0; @@ -301,7 +301,7 @@ static const MemoryRegionOps apc_mem_ops = { } }; -static uint64_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr, +static uint64_t slavio_sysctrl_mem_readl(void *opaque, hwaddr addr, unsigned size) { MiscState *s = opaque; @@ -318,7 +318,7 @@ static uint64_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr, return ret; } -static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr, +static void slavio_sysctrl_mem_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { MiscState *s = opaque; @@ -346,7 +346,7 @@ static const MemoryRegionOps slavio_sysctrl_mem_ops = { }, }; -static uint64_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr, +static uint64_t slavio_led_mem_readw(void *opaque, hwaddr addr, unsigned size) { MiscState *s = opaque; @@ -363,7 +363,7 @@ static uint64_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr, return ret; } -static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr, +static void slavio_led_mem_writew(void *opaque, hwaddr addr, uint64_t val, unsigned size) { MiscState *s = opaque; diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 97edebb3ba..584629f1a5 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -23,7 +23,7 @@ */ #include "sun4m.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "ptimer.h" #include "sysbus.h" #include "trace.h" @@ -130,7 +130,7 @@ static void slavio_timer_irq(void *opaque) } } -static uint64_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr, +static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr, unsigned size) { TimerContext *tc = opaque; @@ -190,7 +190,7 @@ static uint64_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr, return ret; } -static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, +static void slavio_timer_mem_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { TimerContext *tc = opaque; diff --git a/hw/sm501.c b/hw/sm501.c index 786e07629c..dd186aa7f2 100644 --- a/hw/sm501.c +++ b/hw/sm501.c @@ -24,12 +24,13 @@ #include <stdio.h> #include "hw.h" -#include "pc.h" -#include "console.h" +#include "serial.h" +#include "ui/console.h" #include "devices.h" #include "sysbus.h" #include "qdev-addr.h" -#include "range.h" +#include "qemu/range.h" +#include "ui/pixel_ops.h" /* * Status: 2010/05/07 @@ -456,7 +457,7 @@ typedef struct SM501State { DisplayState *ds; /* status & internal resources */ - target_phys_addr_t base; + hwaddr base; uint32_t local_mem_size_index; uint8_t * local_mem; MemoryRegion local_mem_region; @@ -726,7 +727,7 @@ static void sm501_2d_operation(SM501State * s) } } -static uint64_t sm501_system_config_read(void *opaque, target_phys_addr_t addr, +static uint64_t sm501_system_config_read(void *opaque, hwaddr addr, unsigned size) { SM501State * s = (SM501State *)opaque; @@ -779,7 +780,7 @@ static uint64_t sm501_system_config_read(void *opaque, target_phys_addr_t addr, return ret; } -static void sm501_system_config_write(void *opaque, target_phys_addr_t addr, +static void sm501_system_config_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { SM501State * s = (SM501State *)opaque; @@ -837,7 +838,7 @@ static const MemoryRegionOps sm501_system_config_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint32_t sm501_palette_read(void *opaque, target_phys_addr_t addr) +static uint32_t sm501_palette_read(void *opaque, hwaddr addr) { SM501State * s = (SM501State *)opaque; SM501_DPRINTF("sm501 palette read addr=%x\n", (int)addr); @@ -850,7 +851,7 @@ static uint32_t sm501_palette_read(void *opaque, target_phys_addr_t addr) } static void sm501_palette_write(void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { SM501State * s = (SM501State *)opaque; SM501_DPRINTF("sm501 palette write addr=%x, val=%x\n", @@ -863,7 +864,7 @@ static void sm501_palette_write(void *opaque, *(uint32_t*)&s->dc_palette[addr] = value; } -static uint64_t sm501_disp_ctrl_read(void *opaque, target_phys_addr_t addr, +static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr, unsigned size) { SM501State * s = (SM501State *)opaque; @@ -958,7 +959,7 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, target_phys_addr_t addr, return ret; } -static void sm501_disp_ctrl_write(void *opaque, target_phys_addr_t addr, +static void sm501_disp_ctrl_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { SM501State * s = (SM501State *)opaque; @@ -1073,7 +1074,7 @@ static const MemoryRegionOps sm501_disp_ctrl_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint64_t sm501_2d_engine_read(void *opaque, target_phys_addr_t addr, +static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr, unsigned size) { SM501State * s = (SM501State *)opaque; @@ -1093,7 +1094,7 @@ static uint64_t sm501_2d_engine_read(void *opaque, target_phys_addr_t addr, return ret; } -static void sm501_2d_engine_write(void *opaque, target_phys_addr_t addr, +static void sm501_2d_engine_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { SM501State * s = (SM501State *)opaque; @@ -1163,8 +1164,6 @@ static const MemoryRegionOps sm501_2d_engine_ops = { /* draw line functions for all console modes */ -#include "pixel_ops.h" - typedef void draw_line_func(uint8_t *d, const uint8_t *s, int width, const uint32_t *pal); @@ -1351,7 +1350,7 @@ static void sm501_draw_crt(SM501State * s) } else { if (y_start >= 0) { /* flush to display */ - dpy_update(s->ds, 0, y_start, width, y - y_start); + dpy_gfx_update(s->ds, 0, y_start, width, y - y_start); y_start = -1; } } @@ -1362,7 +1361,7 @@ static void sm501_draw_crt(SM501State * s) /* complete flush to display */ if (y_start >= 0) - dpy_update(s->ds, 0, y_start, width, y - y_start); + dpy_gfx_update(s->ds, 0, y_start, width, y - y_start); /* clear dirty flags */ if (page_min != ~0l) { diff --git a/hw/smbios.c b/hw/smbios.c index c57237d279..a7b8bfc383 100644 --- a/hw/smbios.c +++ b/hw/smbios.c @@ -13,7 +13,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "smbios.h" #include "loader.h" diff --git a/hw/smbus_ich9.c b/hw/smbus_ich9.c new file mode 100644 index 0000000000..16db3a743c --- /dev/null +++ b/hw/smbus_ich9.c @@ -0,0 +1,127 @@ +/* + * ACPI implementation + * + * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * Copyright (C) 2012 Jason Baron <jbaron@redhat.com> + * + * This is based on acpi.c, but heavily rewritten. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/> + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + * + */ +#include "hw.h" +#include "pc.h" +#include "pm_smbus.h" +#include "pci/pci.h" +#include "sysemu/sysemu.h" +#include "i2c.h" +#include "smbus.h" + +#include "ich9.h" + +#define TYPE_ICH9_SMB_DEVICE "ICH9 SMB" +#define ICH9_SMB_DEVICE(obj) \ + OBJECT_CHECK(ICH9SMBState, (obj), TYPE_ICH9_SMB_DEVICE) + +typedef struct ICH9SMBState { + PCIDevice dev; + + PMSMBus smb; +} ICH9SMBState; + +static const VMStateDescription vmstate_ich9_smbus = { + .name = "ich9_smb", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, struct ICH9SMBState), + VMSTATE_END_OF_LIST() + } +}; + +static void ich9_smbus_write_config(PCIDevice *d, uint32_t address, + uint32_t val, int len) +{ + ICH9SMBState *s = ICH9_SMB_DEVICE(d); + + pci_default_write_config(d, address, val, len); + if (range_covers_byte(address, len, ICH9_SMB_HOSTC)) { + uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC]; + if ((hostc & ICH9_SMB_HOSTC_HST_EN) && + !(hostc & ICH9_SMB_HOSTC_I2C_EN)) { + memory_region_set_enabled(&s->smb.io, true); + } else { + memory_region_set_enabled(&s->smb.io, false); + } + } +} + +static int ich9_smbus_initfn(PCIDevice *d) +{ + ICH9SMBState *s = ICH9_SMB_DEVICE(d); + + /* TODO? D31IP.SMIP in chipset configuration space */ + pci_config_set_interrupt_pin(d->config, 0x01); /* interrupt pin 1 */ + + pci_set_byte(d->config + ICH9_SMB_HOSTC, 0); + /* TODO bar0, bar1: 64bit BAR support*/ + + pm_smbus_init(&d->qdev, &s->smb); + pci_register_bar(d, ICH9_SMB_SMB_BASE_BAR, PCI_BASE_ADDRESS_SPACE_IO, + &s->smb.io); + return 0; +} + +static void ich9_smb_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_ICH9_6; + k->revision = ICH9_A2_SMB_REVISION; + k->class_id = PCI_CLASS_SERIAL_SMBUS; + dc->no_user = 1; + dc->vmsd = &vmstate_ich9_smbus; + dc->desc = "ICH9 SMBUS Bridge"; + k->init = ich9_smbus_initfn; + k->config_write = ich9_smbus_write_config; +} + +i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base) +{ + PCIDevice *d = + pci_create_simple_multifunction(bus, devfn, true, TYPE_ICH9_SMB_DEVICE); + ICH9SMBState *s = ICH9_SMB_DEVICE(d); + return s->smb.smbus; +} + +static const TypeInfo ich9_smb_info = { + .name = TYPE_ICH9_SMB_DEVICE, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(ICH9SMBState), + .class_init = ich9_smb_class_init, +}; + +static void ich9_smb_register(void) +{ + type_register_static(&ich9_smb_info); +} + +type_init(ich9_smb_register); diff --git a/hw/smc91c111.c b/hw/smc91c111.c index d6ef302c6d..2161b4af7a 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -8,7 +8,7 @@ */ #include "sysbus.h" -#include "net.h" +#include "net/net.h" #include "devices.h" /* For crc32 */ #include <zlib.h> @@ -276,7 +276,7 @@ static void smc91c111_reset(DeviceState *dev) #define SET_LOW(name, val) s->name = (s->name & 0xff00) | val #define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8) -static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, +static void smc91c111_writeb(void *opaque, hwaddr offset, uint32_t value) { smc91c111_state *s = (smc91c111_state *)opaque; @@ -451,7 +451,7 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset, hw_error("smc91c111_write: Bad reg %d:%x\n", s->bank, (int)offset); } -static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) +static uint32_t smc91c111_readb(void *opaque, hwaddr offset) { smc91c111_state *s = (smc91c111_state *)opaque; @@ -595,14 +595,14 @@ static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset) return 0; } -static void smc91c111_writew(void *opaque, target_phys_addr_t offset, +static void smc91c111_writew(void *opaque, hwaddr offset, uint32_t value) { smc91c111_writeb(opaque, offset, value & 0xff); smc91c111_writeb(opaque, offset + 1, value >> 8); } -static void smc91c111_writel(void *opaque, target_phys_addr_t offset, +static void smc91c111_writel(void *opaque, hwaddr offset, uint32_t value) { /* 32-bit writes to offset 0xc only actually write to the bank select @@ -612,7 +612,7 @@ static void smc91c111_writel(void *opaque, target_phys_addr_t offset, smc91c111_writew(opaque, offset + 2, value >> 16); } -static uint32_t smc91c111_readw(void *opaque, target_phys_addr_t offset) +static uint32_t smc91c111_readw(void *opaque, hwaddr offset) { uint32_t val; val = smc91c111_readb(opaque, offset); @@ -620,7 +620,7 @@ static uint32_t smc91c111_readw(void *opaque, target_phys_addr_t offset) return val; } -static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset) +static uint32_t smc91c111_readl(void *opaque, hwaddr offset) { uint32_t val; val = smc91c111_readw(opaque, offset); diff --git a/hw/soc_dma.c b/hw/soc_dma.c index 03bc8468dd..64e8ee1d13 100644 --- a/hw/soc_dma.c +++ b/hw/soc_dma.c @@ -18,7 +18,7 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "qemu-common.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "soc_dma.h" static void transfer_mem2mem(struct soc_dma_ch_s *ch) @@ -64,7 +64,7 @@ struct dma_s { struct memmap_entry_s { enum soc_dma_port_type type; - target_phys_addr_t addr; + hwaddr addr; union { struct { void *opaque; @@ -105,7 +105,7 @@ static void soc_dma_ch_run(void *opaque) } static inline struct memmap_entry_s *soc_dma_lookup(struct dma_s *dma, - target_phys_addr_t addr) + hwaddr addr) { struct memmap_entry_s *lo; int hi; @@ -255,7 +255,7 @@ struct soc_dma_s *soc_dma_init(int n) return &s->soc; } -void soc_dma_port_add_fifo(struct soc_dma_s *soc, target_phys_addr_t virt_base, +void soc_dma_port_add_fifo(struct soc_dma_s *soc, hwaddr virt_base, soc_dma_io_t fn, void *opaque, int out) { struct memmap_entry_s *entry; @@ -308,7 +308,7 @@ void soc_dma_port_add_fifo(struct soc_dma_s *soc, target_phys_addr_t virt_base, } void soc_dma_port_add_mem(struct soc_dma_s *soc, uint8_t *phys_base, - target_phys_addr_t virt_base, size_t size) + hwaddr virt_base, size_t size) { struct memmap_entry_s *entry; struct dma_s *dma = (struct dma_s *) soc; diff --git a/hw/soc_dma.h b/hw/soc_dma.h index 904b26c5a8..7379731afd 100644 --- a/hw/soc_dma.h +++ b/hw/soc_dma.h @@ -18,7 +18,12 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "memory.h" +#ifndef HW_SOC_DMA_H +#define HW_SOC_DMA_H 1 + + +#include "exec/memory.h" +#include "hw/irq.h" struct soc_dma_s; struct soc_dma_ch_s; @@ -51,7 +56,7 @@ struct soc_dma_ch_s { int bytes; /* Initialised by the DMA module, call soc_dma_ch_update after writing. */ enum soc_dma_access_type type[2]; - target_phys_addr_t vaddr[2]; /* Updated by .transfer_fn(). */ + hwaddr vaddr[2]; /* Updated by .transfer_fn(). */ /* Private */ void *paddr[2]; soc_dma_io_t io_fn[2]; @@ -91,19 +96,21 @@ void soc_dma_ch_update(struct soc_dma_ch_s *ch); void soc_dma_reset(struct soc_dma_s *s); struct soc_dma_s *soc_dma_init(int n); -void soc_dma_port_add_fifo(struct soc_dma_s *dma, target_phys_addr_t virt_base, +void soc_dma_port_add_fifo(struct soc_dma_s *dma, hwaddr virt_base, soc_dma_io_t fn, void *opaque, int out); void soc_dma_port_add_mem(struct soc_dma_s *dma, uint8_t *phys_base, - target_phys_addr_t virt_base, size_t size); + hwaddr virt_base, size_t size); static inline void soc_dma_port_add_fifo_in(struct soc_dma_s *dma, - target_phys_addr_t virt_base, soc_dma_io_t fn, void *opaque) + hwaddr virt_base, soc_dma_io_t fn, void *opaque) { return soc_dma_port_add_fifo(dma, virt_base, fn, opaque, 0); } static inline void soc_dma_port_add_fifo_out(struct soc_dma_s *dma, - target_phys_addr_t virt_base, soc_dma_io_t fn, void *opaque) + hwaddr virt_base, soc_dma_io_t fn, void *opaque) { return soc_dma_port_add_fifo(dma, virt_base, fn, opaque, 1); } + +#endif diff --git a/hw/spapr.c b/hw/spapr.c index 81c9343ca5..b5e15b884a 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -24,13 +24,13 @@ * THE SOFTWARE. * */ -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "hw.h" #include "elf.h" -#include "net.h" -#include "blockdev.h" -#include "cpus.h" -#include "kvm.h" +#include "net/net.h" +#include "sysemu/blockdev.h" +#include "sysemu/cpus.h" +#include "sysemu/kvm.h" #include "kvm_ppc.h" #include "hw/boards.h" @@ -41,12 +41,15 @@ #include "hw/spapr_vio.h" #include "hw/spapr_pci.h" #include "hw/xics.h" +#include "hw/pci/msi.h" -#include "kvm.h" +#include "sysemu/kvm.h" #include "kvm_ppc.h" -#include "pci.h" +#include "pci/pci.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" +#include "hw/usb.h" +#include "qemu/config-file.h" #include <libfdt.h> @@ -78,16 +81,17 @@ #define SPAPR_PCI_MEM_WIN_ADDR (0x10000000000ULL + 0xA0000000) #define SPAPR_PCI_MEM_WIN_SIZE 0x20000000 #define SPAPR_PCI_IO_WIN_ADDR (0x10000000000ULL + 0x80000000) +#define SPAPR_PCI_MSI_WIN_ADDR (0x10000000000ULL + 0x90000000) #define PHANDLE_XICP 0x00001111 +#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) + sPAPREnvironment *spapr; -qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num, - enum xics_irq_type type) +int spapr_allocate_irq(int hint, bool lsi) { - uint32_t irq; - qemu_irq qirq; + int irq; if (hint) { irq = hint; @@ -96,24 +100,49 @@ qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num, irq = spapr->next_irq++; } - qirq = xics_assign_irq(spapr->icp, irq, type); - if (!qirq) { - return NULL; + /* Configure irq type */ + if (!xics_get_qirq(spapr->icp, irq)) { + return 0; } - if (irq_num) { - *irq_num = irq; + xics_set_irq_type(spapr->icp, irq, lsi); + + return irq; +} + +/* Allocate block of consequtive IRQs, returns a number of the first */ +int spapr_allocate_irq_block(int num, bool lsi) +{ + int first = -1; + int i; + + for (i = 0; i < num; ++i) { + int irq; + + irq = spapr_allocate_irq(0, lsi); + if (!irq) { + return -1; + } + + if (0 == i) { + first = irq; + } + + /* If the above doesn't create a consecutive block then that's + * an internal bug */ + assert(irq == (first + i)); } - return qirq; + return first; } -static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr) +static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) { int ret = 0, offset; CPUPPCState *env; char cpu_model[32]; int smt = kvmppc_smt_threads(); + uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; assert(spapr->cpu_model); @@ -137,8 +166,16 @@ static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr) return offset; } - ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity, - sizeof(associativity)); + if (nb_numa_nodes > 1) { + ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity, + sizeof(associativity)); + if (ret < 0) { + return ret; + } + } + + ret = fdt_setprop(fdt, offset, "ibm,pft-size", + pft_size_prop, sizeof(pft_size_prop)); if (ret < 0) { return ret; } @@ -180,45 +217,37 @@ static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop, return (p - prop) * sizeof(uint32_t); } +#define _FDT(exp) \ + do { \ + int ret = (exp); \ + if (ret < 0) { \ + fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ + #exp, fdt_strerror(ret)); \ + exit(1); \ + } \ + } while (0) + + static void *spapr_create_fdt_skel(const char *cpu_model, - target_phys_addr_t rma_size, - target_phys_addr_t initrd_base, - target_phys_addr_t initrd_size, - target_phys_addr_t kernel_size, + hwaddr initrd_base, + hwaddr initrd_size, + hwaddr kernel_size, const char *boot_device, const char *kernel_cmdline, - long hash_shift) + uint32_t epow_irq) { void *fdt; CPUPPCState *env; - uint64_t mem_reg_property[2]; uint32_t start_prop = cpu_to_be32(initrd_base); uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); - uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt" "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk"; char qemu_hypertas_prop[] = "hcall-memop1"; + uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)}; uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; - int i; char *modelname; - int smt = kvmppc_smt_threads(); + int i, smt = kvmppc_smt_threads(); unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80}; - uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)}; - uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0), - cpu_to_be32(0x0), cpu_to_be32(0x0), - cpu_to_be32(0x0)}; - char mem_name[32]; - target_phys_addr_t node0_size, mem_start; - -#define _FDT(exp) \ - do { \ - int ret = (exp); \ - if (ret < 0) { \ - fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ - #exp, fdt_strerror(ret)); \ - exit(1); \ - } \ - } while (0) fdt = g_malloc0(FDT_MAX_SIZE); _FDT((fdt_create(fdt, FDT_MAX_SIZE))); @@ -257,58 +286,12 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop)))); } _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device))); + _FDT((fdt_property_cell(fdt, "qemu,graphic-width", graphic_width))); + _FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height))); + _FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth))); _FDT((fdt_end_node(fdt))); - /* memory node(s) */ - node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; - if (rma_size > node0_size) { - rma_size = node0_size; - } - - /* RMA */ - mem_reg_property[0] = 0; - mem_reg_property[1] = cpu_to_be64(rma_size); - _FDT((fdt_begin_node(fdt, "memory@0"))); - _FDT((fdt_property_string(fdt, "device_type", "memory"))); - _FDT((fdt_property(fdt, "reg", mem_reg_property, - sizeof(mem_reg_property)))); - _FDT((fdt_property(fdt, "ibm,associativity", associativity, - sizeof(associativity)))); - _FDT((fdt_end_node(fdt))); - - /* RAM: Node 0 */ - if (node0_size > rma_size) { - mem_reg_property[0] = cpu_to_be64(rma_size); - mem_reg_property[1] = cpu_to_be64(node0_size - rma_size); - - sprintf(mem_name, "memory@" TARGET_FMT_lx, rma_size); - _FDT((fdt_begin_node(fdt, mem_name))); - _FDT((fdt_property_string(fdt, "device_type", "memory"))); - _FDT((fdt_property(fdt, "reg", mem_reg_property, - sizeof(mem_reg_property)))); - _FDT((fdt_property(fdt, "ibm,associativity", associativity, - sizeof(associativity)))); - _FDT((fdt_end_node(fdt))); - } - - /* RAM: Node 1 and beyond */ - mem_start = node0_size; - for (i = 1; i < nb_numa_nodes; i++) { - mem_reg_property[0] = cpu_to_be64(mem_start); - mem_reg_property[1] = cpu_to_be64(node_mem[i]); - associativity[3] = associativity[4] = cpu_to_be32(i); - sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start); - _FDT((fdt_begin_node(fdt, mem_name))); - _FDT((fdt_property_string(fdt, "device_type", "memory"))); - _FDT((fdt_property(fdt, "reg", mem_reg_property, - sizeof(mem_reg_property)))); - _FDT((fdt_property(fdt, "ibm,associativity", associativity, - sizeof(associativity)))); - _FDT((fdt_end_node(fdt))); - mem_start += node_mem[i]; - } - /* cpus */ _FDT((fdt_begin_node(fdt, "cpus"))); @@ -360,8 +343,6 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property_cell(fdt, "timebase-frequency", tbfreq))); _FDT((fdt_property_cell(fdt, "clock-frequency", cpufreq))); _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr))); - _FDT((fdt_property(fdt, "ibm,pft-size", - pft_size_prop, sizeof(pft_size_prop)))); _FDT((fdt_property_string(fdt, "status", "okay"))); _FDT((fdt_property(fdt, "64-bit", NULL, 0))); @@ -424,6 +405,8 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property(fdt, "ibm,associativity-reference-points", refpoints, sizeof(refpoints)))); + _FDT((fdt_property_cell(fdt, "rtas-error-log-max", RTAS_ERROR_LOG_MAX))); + _FDT((fdt_end_node(fdt))); /* interrupt controller */ @@ -454,16 +437,81 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_end_node(fdt))); + /* event-sources */ + spapr_events_fdt_skel(fdt, epow_irq); + _FDT((fdt_end_node(fdt))); /* close root node */ _FDT((fdt_finish(fdt))); return fdt; } +static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt) +{ + uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0), + cpu_to_be32(0x0), cpu_to_be32(0x0), + cpu_to_be32(0x0)}; + char mem_name[32]; + hwaddr node0_size, mem_start; + uint64_t mem_reg_property[2]; + int i, off; + + /* memory node(s) */ + node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; + if (spapr->rma_size > node0_size) { + spapr->rma_size = node0_size; + } + + /* RMA */ + mem_reg_property[0] = 0; + mem_reg_property[1] = cpu_to_be64(spapr->rma_size); + off = fdt_add_subnode(fdt, 0, "memory@0"); + _FDT(off); + _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); + _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, + sizeof(associativity)))); + + /* RAM: Node 0 */ + if (node0_size > spapr->rma_size) { + mem_reg_property[0] = cpu_to_be64(spapr->rma_size); + mem_reg_property[1] = cpu_to_be64(node0_size - spapr->rma_size); + + sprintf(mem_name, "memory@" TARGET_FMT_lx, spapr->rma_size); + off = fdt_add_subnode(fdt, 0, mem_name); + _FDT(off); + _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); + _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, + sizeof(associativity)))); + } + + /* RAM: Node 1 and beyond */ + mem_start = node0_size; + for (i = 1; i < nb_numa_nodes; i++) { + mem_reg_property[0] = cpu_to_be64(mem_start); + mem_reg_property[1] = cpu_to_be64(node_mem[i]); + associativity[3] = associativity[4] = cpu_to_be32(i); + sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start); + off = fdt_add_subnode(fdt, 0, mem_name); + _FDT(off); + _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); + _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, + sizeof(associativity)))); + mem_start += node_mem[i]; + } + + return 0; +} + static void spapr_finalize_fdt(sPAPREnvironment *spapr, - target_phys_addr_t fdt_addr, - target_phys_addr_t rtas_addr, - target_phys_addr_t rtas_size) + hwaddr fdt_addr, + hwaddr rtas_addr, + hwaddr rtas_size) { int ret; void *fdt; @@ -474,6 +522,12 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, /* open out the base tree into a temp buffer for the final tweaks */ _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE))); + ret = spapr_populate_memory(spapr, fdt); + if (ret < 0) { + fprintf(stderr, "couldn't setup memory nodes in fdt\n"); + exit(1); + } + ret = spapr_populate_vdevice(spapr->vio_bus, fdt); if (ret < 0) { fprintf(stderr, "couldn't setup vio devices in fdt\n"); @@ -481,7 +535,7 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, } QLIST_FOREACH(phb, &spapr->phbs, list) { - ret = spapr_populate_pci_devices(phb, PHANDLE_XICP, fdt); + ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt); } if (ret < 0) { @@ -496,14 +550,14 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, } /* Advertise NUMA via ibm,associativity */ - if (nb_numa_nodes > 1) { - ret = spapr_set_associativity(fdt, spapr); - if (ret < 0) { - fprintf(stderr, "Couldn't set up NUMA device tree properties\n"); - } + ret = spapr_fixup_cpu_dt(fdt, spapr); + if (ret < 0) { + fprintf(stderr, "Couldn't finalize CPU device tree properties\n"); } - spapr_populate_chosen_stdout(fdt, spapr->vio_bus); + if (!spapr->has_graphics) { + spapr_populate_chosen_stdout(fdt, spapr->vio_bus); + } _FDT((fdt_pack(fdt))); @@ -523,19 +577,53 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR; } -static void emulate_spapr_hypercall(CPUPPCState *env) +static void emulate_spapr_hypercall(PowerPCCPU *cpu) { - env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); + CPUPPCState *env = &cpu->env; + + if (msr_pr) { + hcall_dprintf("Hypercall made with MSR[PR]=1\n"); + env->gpr[3] = H_PRIVILEGE; + } else { + env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]); + } } -static void spapr_reset(void *opaque) +static void spapr_reset_htab(sPAPREnvironment *spapr) { - sPAPREnvironment *spapr = (sPAPREnvironment *)opaque; + long shift; + + /* allocate hash page table. For now we always make this 16mb, + * later we should probably make it scale to the size of guest + * RAM */ + + shift = kvmppc_reset_htab(spapr->htab_shift); - fprintf(stderr, "sPAPR reset\n"); + if (shift > 0) { + /* Kernel handles htab, we don't need to allocate one */ + spapr->htab_shift = shift; + } else { + if (!spapr->htab) { + /* Allocate an htab if we don't yet have one */ + spapr->htab = qemu_memalign(HTAB_SIZE(spapr), HTAB_SIZE(spapr)); + } + + /* And clear it */ + memset(spapr->htab, 0, HTAB_SIZE(spapr)); + } + + /* Update the RMA size if necessary */ + if (spapr->vrma_adjust) { + spapr->rma_size = kvmppc_rma_size(ram_size, spapr->htab_shift); + } +} + +static void ppc_spapr_reset(void) +{ + /* Reset the hash table & recalc the RMA */ + spapr_reset_htab(spapr); - /* flush out the hash table */ - memset(spapr->htab, 0, spapr->htab_size); + qemu_devices_reset(); /* Load the fdt */ spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr, @@ -552,30 +640,92 @@ static void spapr_reset(void *opaque) static void spapr_cpu_reset(void *opaque) { PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; cpu_reset(CPU(cpu)); + + /* All CPUs start halted. CPU0 is unhalted from the machine level + * reset code and the rest are explicitly started up by the guest + * using an RTAS call */ + env->halted = 1; + + env->spr[SPR_HIOR] = 0; + + env->external_htab = spapr->htab; + env->htab_base = -1; + env->htab_mask = HTAB_SIZE(spapr) - 1; + env->spr[SPR_SDR1] = (unsigned long)spapr->htab | + (spapr->htab_shift - 18); +} + +static void spapr_create_nvram(sPAPREnvironment *spapr) +{ + QemuOpts *machine_opts; + DeviceState *dev; + + dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram"); + + machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (machine_opts) { + const char *drivename; + + drivename = qemu_opt_get(machine_opts, "nvram"); + if (drivename) { + BlockDriverState *bs; + + bs = bdrv_find(drivename); + if (!bs) { + fprintf(stderr, "No such block device \"%s\" for nvram\n", + drivename); + exit(1); + } + qdev_prop_set_drive_nofail(dev, "drive", bs); + } + } + + qdev_init_nofail(dev); + + spapr->nvram = (struct sPAPRNVRAM *)dev; +} + +/* Returns whether we want to use VGA or not */ +static int spapr_vga_init(PCIBus *pci_bus) +{ + switch (vga_interface_type) { + case VGA_NONE: + case VGA_STD: + return pci_vga_init(pci_bus) != NULL; + default: + fprintf(stderr, "This vga model is not supported," + "currently it only supports -vga std\n"); + exit(0); + break; + } } /* pSeries LPAR / sPAPR hardware init */ -static void ppc_spapr_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void ppc_spapr_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; PowerPCCPU *cpu; CPUPPCState *env; + PCIHostState *phb; int i; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); - target_phys_addr_t rma_alloc_size, rma_size; + hwaddr rma_alloc_size; uint32_t initrd_base = 0; long kernel_size = 0, initrd_size = 0; long load_limit, rtas_limit, fw_size; - long pteg_shift = 17; char *filename; + msi_supported = true; + spapr = g_malloc0(sizeof(*spapr)); QLIST_INIT(&spapr->phbs); @@ -588,20 +738,46 @@ static void ppc_spapr_init(ram_addr_t ram_size, hw_error("qemu: Unable to create RMA\n"); exit(1); } + if (rma_alloc_size && (rma_alloc_size < ram_size)) { - rma_size = rma_alloc_size; + spapr->rma_size = rma_alloc_size; } else { - rma_size = ram_size; + spapr->rma_size = ram_size; + + /* With KVM, we don't actually know whether KVM supports an + * unbounded RMA (PR KVM) or is limited by the hash table size + * (HV KVM using VRMA), so we always assume the latter + * + * In that case, we also limit the initial allocations for RTAS + * etc... to 256M since we have no way to know what the VRMA size + * is going to be as it depends on the size of the hash table + * isn't determined yet. + */ + if (kvm_enabled()) { + spapr->vrma_adjust = 1; + spapr->rma_size = MIN(spapr->rma_size, 0x10000000); + } } /* We place the device tree and RTAS just below either the top of the RMA, * or just below 2GB, whichever is lowere, so that it can be * processed with 32-bit real mode code if necessary */ - rtas_limit = MIN(rma_size, 0x80000000); + rtas_limit = MIN(spapr->rma_size, 0x80000000); spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE; spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE; load_limit = spapr->fdt_addr - FW_OVERHEAD; + /* We aim for a hash table of size 1/128 the size of RAM. The + * normal rule of thumb is 1/64 the size of RAM, but that's much + * more than needed for the Linux guests we support. */ + spapr->htab_shift = 18; /* Minimum architected size */ + while (spapr->htab_shift <= 46) { + if ((1ULL << (spapr->htab_shift + 7)) >= ram_size) { + break; + } + spapr->htab_shift++; + } + /* init CPUs */ if (cpu_model == NULL) { cpu_model = kvm_enabled() ? "host" : "POWER7"; @@ -616,11 +792,16 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init(env, TIMEBASE_FREQ); - qemu_register_reset(spapr_cpu_reset, cpu); - env->hreset_vector = 0x60; + /* PAPR always has exception vectors in RAM not ROM */ env->hreset_excp_prefix = 0; - env->gpr[3] = env->cpu_index; + + /* Tell KVM that we're in PAPR mode */ + if (kvm_enabled()) { + kvmppc_set_papr(cpu); + } + + qemu_register_reset(spapr_cpu_reset, cpu); } /* allocate RAM */ @@ -634,27 +815,6 @@ static void ppc_spapr_init(ram_addr_t ram_size, memory_region_add_subregion(sysmem, nonrma_base, ram); } - /* allocate hash page table. For now we always make this 16mb, - * later we should probably make it scale to the size of guest - * RAM */ - spapr->htab_size = 1ULL << (pteg_shift + 7); - spapr->htab = qemu_memalign(spapr->htab_size, spapr->htab_size); - - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->external_htab = spapr->htab; - env->htab_base = -1; - env->htab_mask = spapr->htab_size - 1; - - /* Tell KVM that we're in PAPR mode */ - env->spr[SPR_SDR1] = (unsigned long)spapr->htab | - ((pteg_shift + 7) - 18); - env->spr[SPR_HIOR] = 0; - - if (kvm_enabled()) { - kvmppc_set_papr(env); - } - } - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr, rtas_limit - spapr->rtas_addr); @@ -672,7 +832,10 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* Set up Interrupt Controller */ spapr->icp = xics_system_init(XICS_IRQS); - spapr->next_irq = 16; + spapr->next_irq = XICS_IRQ_BASE; + + /* Set up EPOW events infrastructure */ + spapr_events_init(spapr); /* Set up IOMMU */ spapr_iommu_init(); @@ -686,11 +849,18 @@ static void ppc_spapr_init(ram_addr_t ram_size, } } + /* We always have at least the nvram device on VIO */ + spapr_create_nvram(spapr); + /* Set up PCI */ + spapr_pci_rtas_init(); + spapr_create_phb(spapr, "pci", SPAPR_PCI_BUID, SPAPR_PCI_MEM_WIN_ADDR, SPAPR_PCI_MEM_WIN_SIZE, - SPAPR_PCI_IO_WIN_ADDR); + SPAPR_PCI_IO_WIN_ADDR, + SPAPR_PCI_MSI_WIN_ADDR); + phb = PCI_HOST_BRIDGE(QLIST_FIRST(&spapr->phbs)); for (i = 0; i < nb_nics; i++) { NICInfo *nd = &nd_table[i]; @@ -710,20 +880,25 @@ static void ppc_spapr_init(ram_addr_t ram_size, spapr_vscsi_create(spapr->vio_bus); } - if (rma_size < (MIN_RMA_SLOF << 20)) { + /* Graphics */ + if (spapr_vga_init(phb->bus)) { + spapr->has_graphics = true; + } + + if (usb_enabled(spapr->has_graphics)) { + pci_create_simple(phb->bus, -1, "pci-ohci"); + if (spapr->has_graphics) { + usbdevice_create("keyboard"); + usbdevice_create("mouse"); + } + } + + if (spapr->rma_size < (MIN_RMA_SLOF << 20)) { fprintf(stderr, "qemu: pSeries SLOF firmware requires >= " "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF); exit(1); } - fprintf(stderr, "sPAPR memory map:\n"); - fprintf(stderr, "RTAS : 0x%08lx..%08lx\n", - (unsigned long)spapr->rtas_addr, - (unsigned long)(spapr->rtas_addr + spapr->rtas_size - 1)); - fprintf(stderr, "FDT : 0x%08lx..%08lx\n", - (unsigned long)spapr->fdt_addr, - (unsigned long)(spapr->fdt_addr + FDT_MAX_SIZE - 1)); - if (kernel_filename) { uint64_t lowaddr = 0; @@ -739,8 +914,6 @@ static void ppc_spapr_init(ram_addr_t ram_size, kernel_filename); exit(1); } - fprintf(stderr, "Kernel : 0x%08x..%08lx\n", - KERNEL_LOAD_ADDR, KERNEL_LOAD_ADDR + kernel_size - 1); /* load initrd */ if (initrd_filename) { @@ -755,8 +928,6 @@ static void ppc_spapr_init(ram_addr_t ram_size, initrd_filename); exit(1); } - fprintf(stderr, "Ramdisk : 0x%08lx..%08lx\n", - (long)initrd_base, (long)(initrd_base + initrd_size - 1)); } else { initrd_base = 0; initrd_size = 0; @@ -770,36 +941,26 @@ static void ppc_spapr_init(ram_addr_t ram_size, exit(1); } g_free(filename); - fprintf(stderr, "Firmware load : 0x%08x..%08lx\n", - 0, fw_size); - fprintf(stderr, "Firmware runtime : 0x%08lx..%08lx\n", - load_limit, (unsigned long)spapr->fdt_addr); spapr->entry_point = 0x100; - /* SLOF will startup the secondary CPUs using RTAS */ - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->halted = 1; - } - /* Prepare the device tree */ - spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, rma_size, + spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, initrd_base, initrd_size, kernel_size, boot_device, kernel_cmdline, - pteg_shift + 7); + spapr->epow_irq); assert(spapr->fdt_skel != NULL); - - qemu_register_reset(spapr_reset, spapr); } static QEMUMachine spapr_machine = { .name = "pseries", .desc = "pSeries Logical Partition (PAPR compliant)", .init = ppc_spapr_init, + .reset = ppc_spapr_reset, + .block_default_type = IF_SCSI, .max_cpus = MAX_CPUS, .no_parallel = 1, - .use_scsi = 1, }; static void spapr_machine_init(void) diff --git a/hw/spapr.h b/hw/spapr.h index 9153f29a60..3a1f69f2a9 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -1,28 +1,36 @@ #if !defined(__HW_SPAPR_H__) #define __HW_SPAPR_H__ -#include "dma.h" +#include "sysemu/dma.h" #include "hw/xics.h" struct VIOsPAPRBus; struct sPAPRPHBState; +struct sPAPRNVRAM; struct icp_state; typedef struct sPAPREnvironment { struct VIOsPAPRBus *vio_bus; QLIST_HEAD(, sPAPRPHBState) phbs; + struct sPAPRNVRAM *nvram; struct icp_state *icp; - target_phys_addr_t ram_limit; + hwaddr ram_limit; void *htab; - long htab_size; - target_phys_addr_t fdt_addr, rtas_addr; + long htab_shift; + hwaddr rma_size; + int vrma_adjust; + hwaddr fdt_addr, rtas_addr; long rtas_size; void *fdt_skel; target_ulong entry_point; int next_irq; int rtc_offset; char *cpu_model; + bool has_graphics; + + uint32_t epow_irq; + Notifier epow_notifier; } sPAPREnvironment; #define H_SUCCESS 0 @@ -280,25 +288,25 @@ extern sPAPREnvironment *spapr; do { } while (0) #endif -typedef target_ulong (*spapr_hcall_fn)(CPUPPCState *env, sPAPREnvironment *spapr, +typedef target_ulong (*spapr_hcall_fn)(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args); void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn); -target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode, +target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, target_ulong *args); -qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num, - enum xics_irq_type type); +int spapr_allocate_irq(int hint, bool lsi); +int spapr_allocate_irq_block(int num, bool lsi); -static inline qemu_irq spapr_allocate_msi(uint32_t hint, uint32_t *irq_num) +static inline int spapr_allocate_msi(int hint) { - return spapr_allocate_irq(hint, irq_num, XICS_MSI); + return spapr_allocate_irq(hint, false); } -static inline qemu_irq spapr_allocate_lsi(uint32_t hint, uint32_t *irq_num) +static inline int spapr_allocate_lsi(int hint) { - return spapr_allocate_irq(hint, irq_num, XICS_LSI); + return spapr_allocate_irq(hint, true); } static inline uint32_t rtas_ld(target_ulong phys, int n) @@ -314,12 +322,12 @@ static inline void rtas_st(target_ulong phys, int n, uint32_t val) typedef void (*spapr_rtas_fn)(sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets); -void spapr_rtas_register(const char *name, spapr_rtas_fn fn); +int spapr_rtas_register(const char *name, spapr_rtas_fn fn); target_ulong spapr_rtas_call(sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets); -int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr, - target_phys_addr_t rtas_size); +int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, + hwaddr rtas_size); #define SPAPR_TCE_PAGE_SHIFT 12 #define SPAPR_TCE_PAGE_SIZE (1ULL << SPAPR_TCE_PAGE_SHIFT) @@ -332,10 +340,19 @@ typedef struct sPAPRTCE { #define SPAPR_VIO_BASE_LIOBN 0x00000000 #define SPAPR_PCI_BASE_LIOBN 0x80000000 +#define RTAS_ERROR_LOG_MAX 2048 + + void spapr_iommu_init(void); +void spapr_events_init(sPAPREnvironment *spapr); +void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq); DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size); void spapr_tce_free(DMAContext *dma); +void spapr_tce_reset(DMAContext *dma); +void spapr_tce_set_bypass(DMAContext *dma, bool bypass); int spapr_dma_dt(void *fdt, int node_off, const char *propname, - DMAContext *dma); + uint32_t liobn, uint64_t window, uint32_t size); +int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, + DMAContext *dma); #endif /* !defined (__HW_SPAPR_H__) */ diff --git a/hw/spapr_events.c b/hw/spapr_events.c new file mode 100644 index 0000000000..ce78f0922e --- /dev/null +++ b/hw/spapr_events.c @@ -0,0 +1,321 @@ +/* + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator + * + * RTAS events handling + * + * Copyright (c) 2012 David Gibson, IBM Corporation. + * + * 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. + * + */ +#include "cpu.h" +#include "sysemu/sysemu.h" +#include "char/char.h" +#include "hw/qdev.h" +#include "sysemu/device_tree.h" + +#include "hw/spapr.h" +#include "hw/spapr_vio.h" + +#include <libfdt.h> + +struct rtas_error_log { + uint32_t summary; +#define RTAS_LOG_VERSION_MASK 0xff000000 +#define RTAS_LOG_VERSION_6 0x06000000 +#define RTAS_LOG_SEVERITY_MASK 0x00e00000 +#define RTAS_LOG_SEVERITY_ALREADY_REPORTED 0x00c00000 +#define RTAS_LOG_SEVERITY_FATAL 0x00a00000 +#define RTAS_LOG_SEVERITY_ERROR 0x00800000 +#define RTAS_LOG_SEVERITY_ERROR_SYNC 0x00600000 +#define RTAS_LOG_SEVERITY_WARNING 0x00400000 +#define RTAS_LOG_SEVERITY_EVENT 0x00200000 +#define RTAS_LOG_SEVERITY_NO_ERROR 0x00000000 +#define RTAS_LOG_DISPOSITION_MASK 0x00180000 +#define RTAS_LOG_DISPOSITION_FULLY_RECOVERED 0x00000000 +#define RTAS_LOG_DISPOSITION_LIMITED_RECOVERY 0x00080000 +#define RTAS_LOG_DISPOSITION_NOT_RECOVERED 0x00100000 +#define RTAS_LOG_OPTIONAL_PART_PRESENT 0x00040000 +#define RTAS_LOG_INITIATOR_MASK 0x0000f000 +#define RTAS_LOG_INITIATOR_UNKNOWN 0x00000000 +#define RTAS_LOG_INITIATOR_CPU 0x00001000 +#define RTAS_LOG_INITIATOR_PCI 0x00002000 +#define RTAS_LOG_INITIATOR_MEMORY 0x00004000 +#define RTAS_LOG_INITIATOR_HOTPLUG 0x00006000 +#define RTAS_LOG_TARGET_MASK 0x00000f00 +#define RTAS_LOG_TARGET_UNKNOWN 0x00000000 +#define RTAS_LOG_TARGET_CPU 0x00000100 +#define RTAS_LOG_TARGET_PCI 0x00000200 +#define RTAS_LOG_TARGET_MEMORY 0x00000400 +#define RTAS_LOG_TARGET_HOTPLUG 0x00000600 +#define RTAS_LOG_TYPE_MASK 0x000000ff +#define RTAS_LOG_TYPE_OTHER 0x00000000 +#define RTAS_LOG_TYPE_RETRY 0x00000001 +#define RTAS_LOG_TYPE_TCE_ERR 0x00000002 +#define RTAS_LOG_TYPE_INTERN_DEV_FAIL 0x00000003 +#define RTAS_LOG_TYPE_TIMEOUT 0x00000004 +#define RTAS_LOG_TYPE_DATA_PARITY 0x00000005 +#define RTAS_LOG_TYPE_ADDR_PARITY 0x00000006 +#define RTAS_LOG_TYPE_CACHE_PARITY 0x00000007 +#define RTAS_LOG_TYPE_ADDR_INVALID 0x00000008 +#define RTAS_LOG_TYPE_ECC_UNCORR 0x00000009 +#define RTAS_LOG_TYPE_ECC_CORR 0x0000000a +#define RTAS_LOG_TYPE_EPOW 0x00000040 + uint32_t extended_length; +} QEMU_PACKED; + +struct rtas_event_log_v6 { + uint8_t b0; +#define RTAS_LOG_V6_B0_VALID 0x80 +#define RTAS_LOG_V6_B0_UNRECOVERABLE_ERROR 0x40 +#define RTAS_LOG_V6_B0_RECOVERABLE_ERROR 0x20 +#define RTAS_LOG_V6_B0_DEGRADED_OPERATION 0x10 +#define RTAS_LOG_V6_B0_PREDICTIVE_ERROR 0x08 +#define RTAS_LOG_V6_B0_NEW_LOG 0x04 +#define RTAS_LOG_V6_B0_BIGENDIAN 0x02 + uint8_t _resv1; + uint8_t b2; +#define RTAS_LOG_V6_B2_POWERPC_FORMAT 0x80 +#define RTAS_LOG_V6_B2_LOG_FORMAT_MASK 0x0f +#define RTAS_LOG_V6_B2_LOG_FORMAT_PLATFORM_EVENT 0x0e + uint8_t _resv2[9]; + uint32_t company; +#define RTAS_LOG_V6_COMPANY_IBM 0x49424d00 /* IBM<null> */ +} QEMU_PACKED; + +struct rtas_event_log_v6_section_header { + uint16_t section_id; + uint16_t section_length; + uint8_t section_version; + uint8_t section_subtype; + uint16_t creator_component_id; +} QEMU_PACKED; + +struct rtas_event_log_v6_maina { +#define RTAS_LOG_V6_SECTION_ID_MAINA 0x5048 /* PH */ + struct rtas_event_log_v6_section_header hdr; + uint32_t creation_date; /* BCD: YYYYMMDD */ + uint32_t creation_time; /* BCD: HHMMSS00 */ + uint8_t _platform1[8]; + char creator_id; + uint8_t _resv1[2]; + uint8_t section_count; + uint8_t _resv2[4]; + uint8_t _platform2[8]; + uint32_t plid; + uint8_t _platform3[4]; +} QEMU_PACKED; + +struct rtas_event_log_v6_mainb { +#define RTAS_LOG_V6_SECTION_ID_MAINB 0x5548 /* UH */ + struct rtas_event_log_v6_section_header hdr; + uint8_t subsystem_id; + uint8_t _platform1; + uint8_t event_severity; + uint8_t event_subtype; + uint8_t _platform2[4]; + uint8_t _resv1[2]; + uint16_t action_flags; + uint8_t _resv2[4]; +} QEMU_PACKED; + +struct rtas_event_log_v6_epow { +#define RTAS_LOG_V6_SECTION_ID_EPOW 0x4550 /* EP */ + struct rtas_event_log_v6_section_header hdr; + uint8_t sensor_value; +#define RTAS_LOG_V6_EPOW_ACTION_RESET 0 +#define RTAS_LOG_V6_EPOW_ACTION_WARN_COOLING 1 +#define RTAS_LOG_V6_EPOW_ACTION_WARN_POWER 2 +#define RTAS_LOG_V6_EPOW_ACTION_SYSTEM_SHUTDOWN 3 +#define RTAS_LOG_V6_EPOW_ACTION_SYSTEM_HALT 4 +#define RTAS_LOG_V6_EPOW_ACTION_MAIN_ENCLOSURE 5 +#define RTAS_LOG_V6_EPOW_ACTION_POWER_OFF 7 + uint8_t event_modifier; +#define RTAS_LOG_V6_EPOW_MODIFIER_NORMAL 1 +#define RTAS_LOG_V6_EPOW_MODIFIER_ON_UPS 2 +#define RTAS_LOG_V6_EPOW_MODIFIER_CRITICAL 3 +#define RTAS_LOG_V6_EPOW_MODIFIER_TEMPERATURE 4 + uint8_t extended_modifier; +#define RTAS_LOG_V6_EPOW_XMODIFIER_SYSTEM_WIDE 0 +#define RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC 1 + uint8_t _resv; + uint64_t reason_code; +} QEMU_PACKED; + +struct epow_log_full { + struct rtas_error_log hdr; + struct rtas_event_log_v6 v6hdr; + struct rtas_event_log_v6_maina maina; + struct rtas_event_log_v6_mainb mainb; + struct rtas_event_log_v6_epow epow; +} QEMU_PACKED; + +#define EVENT_MASK_INTERNAL_ERRORS 0x80000000 +#define EVENT_MASK_EPOW 0x40000000 +#define EVENT_MASK_HOTPLUG 0x10000000 +#define EVENT_MASK_IO 0x08000000 + +#define _FDT(exp) \ + do { \ + int ret = (exp); \ + if (ret < 0) { \ + fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ + #exp, fdt_strerror(ret)); \ + exit(1); \ + } \ + } while (0) + +void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq) +{ + uint32_t epow_irq_ranges[] = {cpu_to_be32(epow_irq), cpu_to_be32(1)}; + uint32_t epow_interrupts[] = {cpu_to_be32(epow_irq), 0}; + + _FDT((fdt_begin_node(fdt, "event-sources"))); + + _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0))); + _FDT((fdt_property_cell(fdt, "#interrupt-cells", 2))); + _FDT((fdt_property(fdt, "interrupt-ranges", + epow_irq_ranges, sizeof(epow_irq_ranges)))); + + _FDT((fdt_begin_node(fdt, "epow-events"))); + _FDT((fdt_property(fdt, "interrupts", + epow_interrupts, sizeof(epow_interrupts)))); + _FDT((fdt_end_node(fdt))); + + _FDT((fdt_end_node(fdt))); +} + +static struct epow_log_full *pending_epow; +static uint32_t next_plid; + +static void spapr_powerdown_req(Notifier *n, void *opaque) +{ + sPAPREnvironment *spapr = container_of(n, sPAPREnvironment, epow_notifier); + struct rtas_error_log *hdr; + struct rtas_event_log_v6 *v6hdr; + struct rtas_event_log_v6_maina *maina; + struct rtas_event_log_v6_mainb *mainb; + struct rtas_event_log_v6_epow *epow; + struct tm tm; + int year; + + if (pending_epow) { + /* For now, we just throw away earlier events if two come + * along before any are consumed. This is sufficient for our + * powerdown messages, but we'll need more if we do more + * general error/event logging */ + g_free(pending_epow); + } + pending_epow = g_malloc0(sizeof(*pending_epow)); + hdr = &pending_epow->hdr; + v6hdr = &pending_epow->v6hdr; + maina = &pending_epow->maina; + mainb = &pending_epow->mainb; + epow = &pending_epow->epow; + + hdr->summary = cpu_to_be32(RTAS_LOG_VERSION_6 + | RTAS_LOG_SEVERITY_EVENT + | RTAS_LOG_DISPOSITION_NOT_RECOVERED + | RTAS_LOG_OPTIONAL_PART_PRESENT + | RTAS_LOG_TYPE_EPOW); + hdr->extended_length = cpu_to_be32(sizeof(*pending_epow) + - sizeof(pending_epow->hdr)); + + v6hdr->b0 = RTAS_LOG_V6_B0_VALID | RTAS_LOG_V6_B0_NEW_LOG + | RTAS_LOG_V6_B0_BIGENDIAN; + v6hdr->b2 = RTAS_LOG_V6_B2_POWERPC_FORMAT + | RTAS_LOG_V6_B2_LOG_FORMAT_PLATFORM_EVENT; + v6hdr->company = cpu_to_be32(RTAS_LOG_V6_COMPANY_IBM); + + maina->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINA); + maina->hdr.section_length = cpu_to_be16(sizeof(*maina)); + /* FIXME: section version, subtype and creator id? */ + qemu_get_timedate(&tm, spapr->rtc_offset); + year = tm.tm_year + 1900; + maina->creation_date = cpu_to_be32((to_bcd(year / 100) << 24) + | (to_bcd(year % 100) << 16) + | (to_bcd(tm.tm_mon + 1) << 8) + | to_bcd(tm.tm_mday)); + maina->creation_time = cpu_to_be32((to_bcd(tm.tm_hour) << 24) + | (to_bcd(tm.tm_min) << 16) + | (to_bcd(tm.tm_sec) << 8)); + maina->creator_id = 'H'; /* Hypervisor */ + maina->section_count = 3; /* Main-A, Main-B and EPOW */ + maina->plid = next_plid++; + + mainb->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_MAINB); + mainb->hdr.section_length = cpu_to_be16(sizeof(*mainb)); + /* FIXME: section version, subtype and creator id? */ + mainb->subsystem_id = 0xa0; /* External environment */ + mainb->event_severity = 0x00; /* Informational / non-error */ + mainb->event_subtype = 0xd0; /* Normal shutdown */ + + epow->hdr.section_id = cpu_to_be16(RTAS_LOG_V6_SECTION_ID_EPOW); + epow->hdr.section_length = cpu_to_be16(sizeof(*epow)); + epow->hdr.section_version = 2; /* includes extended modifier */ + /* FIXME: section subtype and creator id? */ + epow->sensor_value = RTAS_LOG_V6_EPOW_ACTION_SYSTEM_SHUTDOWN; + epow->event_modifier = RTAS_LOG_V6_EPOW_MODIFIER_NORMAL; + epow->extended_modifier = RTAS_LOG_V6_EPOW_XMODIFIER_PARTITION_SPECIFIC; + + qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->epow_irq)); +} + +static void check_exception(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + uint32_t mask, buf, len; + uint64_t xinfo; + + if ((nargs < 6) || (nargs > 7) || nret != 1) { + rtas_st(rets, 0, -3); + return; + } + + xinfo = rtas_ld(args, 1); + mask = rtas_ld(args, 2); + buf = rtas_ld(args, 4); + len = rtas_ld(args, 5); + if (nargs == 7) { + xinfo |= (uint64_t)rtas_ld(args, 6) << 32; + } + + if ((mask & EVENT_MASK_EPOW) && pending_epow) { + if (sizeof(*pending_epow) < len) { + len = sizeof(*pending_epow); + } + + cpu_physical_memory_write(buf, pending_epow, len); + g_free(pending_epow); + pending_epow = NULL; + rtas_st(rets, 0, 0); + } else { + rtas_st(rets, 0, 1); + } +} + +void spapr_events_init(sPAPREnvironment *spapr) +{ + spapr->epow_irq = spapr_allocate_msi(0); + spapr->epow_notifier.notify = spapr_powerdown_req; + qemu_register_powerdown_notifier(&spapr->epow_notifier); + spapr_rtas_register("check-exception", check_exception); +} diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index a5990a9617..afb12973f2 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -1,9 +1,6 @@ -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "cpu.h" -#include "dyngen-exec.h" -#include "qemu-char.h" -#include "sysemu.h" -#include "qemu-char.h" +#include "sysemu/sysemu.h" #include "helper_regs.h" #include "hw/spapr.h" @@ -40,22 +37,6 @@ #define HPTE_V_1TB_SEG 0x4000000000000000ULL #define HPTE_V_VRMA_MASK 0x4001ffffff000000ULL -#define HPTE_V_HVLOCK 0x40ULL - -static inline int lock_hpte(void *hpte, target_ulong bits) -{ - uint64_t pteh; - - pteh = ldq_p(hpte); - - /* We're protected by qemu's global lock here */ - if (pteh & bits) { - return 0; - } - stq_p(hpte, pteh | HPTE_V_HVLOCK); - return 1; -} - static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r, target_ulong pte_index) { @@ -92,9 +73,10 @@ static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r, return rb; } -static target_ulong h_enter(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { + CPUPPCState *env = &cpu->env; target_ulong flags = args[0]; target_ulong pte_index = args[1]; target_ulong pteh = args[2]; @@ -152,8 +134,7 @@ static target_ulong h_enter(CPUPPCState *env, sPAPREnvironment *spapr, if (i == 8) { return H_PTEG_FULL; } - if (((ldq_p(hpte) & HPTE_V_VALID) == 0) && - lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) { + if ((ldq_p(hpte) & HPTE_V_VALID) == 0) { break; } hpte += HASH_PTE_SIZE_64; @@ -161,7 +142,7 @@ static target_ulong h_enter(CPUPPCState *env, sPAPREnvironment *spapr, } else { i = 0; hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); - if (!lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) { + if (ldq_p(hpte) & HPTE_V_VALID) { return H_PTEG_FULL; } } @@ -169,7 +150,6 @@ static target_ulong h_enter(CPUPPCState *env, sPAPREnvironment *spapr, /* eieio(); FIXME: need some sort of barrier for smp? */ stq_p(hpte, pteh); - assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); args[0] = pte_index + i; return H_SUCCESS; } @@ -194,11 +174,6 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex, } hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64); - while (!lock_hpte(hpte, HPTE_V_HVLOCK)) { - /* We have no real concurrency in qemu soft-emulation, so we - * will never actually have a contested lock */ - assert(0); - } v = ldq_p(hpte); r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); @@ -206,22 +181,20 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex, if ((v & HPTE_V_VALID) == 0 || ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || ((flags & H_ANDCOND) && (v & avpn) != 0)) { - stq_p(hpte, v & ~HPTE_V_HVLOCK); - assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); return REMOVE_NOT_FOUND; } - *vp = v & ~HPTE_V_HVLOCK; + *vp = v; *rp = r; stq_p(hpte, 0); rb = compute_tlbie_rb(v, r, ptex); ppc_tlb_invalidate_one(env, rb); - assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); return REMOVE_SUCCESS; } -static target_ulong h_remove(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { + CPUPPCState *env = &cpu->env; target_ulong flags = args[0]; target_ulong pte_index = args[1]; target_ulong avpn = args[2]; @@ -265,9 +238,10 @@ static target_ulong h_remove(CPUPPCState *env, sPAPREnvironment *spapr, #define H_BULK_REMOVE_MAX_BATCH 4 -static target_ulong h_bulk_remove(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { + CPUPPCState *env = &cpu->env; int i; for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) { @@ -311,9 +285,10 @@ static target_ulong h_bulk_remove(CPUPPCState *env, sPAPREnvironment *spapr, return H_SUCCESS; } -static target_ulong h_protect(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { + CPUPPCState *env = &cpu->env; target_ulong flags = args[0]; target_ulong pte_index = args[1]; target_ulong avpn = args[2]; @@ -325,19 +300,12 @@ static target_ulong h_protect(CPUPPCState *env, sPAPREnvironment *spapr, } hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); - while (!lock_hpte(hpte, HPTE_V_HVLOCK)) { - /* We have no real concurrency in qemu soft-emulation, so we - * will never actually have a contested lock */ - assert(0); - } v = ldq_p(hpte); r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); if ((v & HPTE_V_VALID) == 0 || ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { - stq_p(hpte, v & ~HPTE_V_HVLOCK); - assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); return H_NOT_FOUND; } @@ -351,12 +319,11 @@ static target_ulong h_protect(CPUPPCState *env, sPAPREnvironment *spapr, ppc_tlb_invalidate_one(env, rb); stq_p(hpte + (HASH_PTE_SIZE_64/2), r); /* Don't need a memory barrier, due to qemu's global lock */ - stq_p(hpte, v & ~HPTE_V_HVLOCK); - assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); + stq_p(hpte, v); return H_SUCCESS; } -static target_ulong h_set_dabr(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { /* FIXME: actually implement this */ @@ -401,26 +368,26 @@ static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa) return H_PARAMETER; } - env->vpa = vpa; + env->vpa_addr = vpa; - tmp = ldub_phys(env->vpa + VPA_SHARED_PROC_OFFSET); + tmp = ldub_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET); tmp |= VPA_SHARED_PROC_VAL; - stb_phys(env->vpa + VPA_SHARED_PROC_OFFSET, tmp); + stb_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET, tmp); return H_SUCCESS; } static target_ulong deregister_vpa(CPUPPCState *env, target_ulong vpa) { - if (env->slb_shadow) { + if (env->slb_shadow_addr) { return H_RESOURCE; } - if (env->dispatch_trace_log) { + if (env->dtl_addr) { return H_RESOURCE; } - env->vpa = 0; + env->vpa_addr = 0; return H_SUCCESS; } @@ -442,18 +409,20 @@ static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr) return H_PARAMETER; } - if (!env->vpa) { + if (!env->vpa_addr) { return H_RESOURCE; } - env->slb_shadow = addr; + env->slb_shadow_addr = addr; + env->slb_shadow_size = size; return H_SUCCESS; } static target_ulong deregister_slb_shadow(CPUPPCState *env, target_ulong addr) { - env->slb_shadow = 0; + env->slb_shadow_addr = 0; + env->slb_shadow_size = 0; return H_SUCCESS; } @@ -472,11 +441,11 @@ static target_ulong register_dtl(CPUPPCState *env, target_ulong addr) return H_PARAMETER; } - if (!env->vpa) { + if (!env->vpa_addr) { return H_RESOURCE; } - env->dispatch_trace_log = addr; + env->dtl_addr = addr; env->dtl_size = size; return H_SUCCESS; @@ -484,13 +453,13 @@ static target_ulong register_dtl(CPUPPCState *env, target_ulong addr) static target_ulong deregister_dtl(CPUPPCState *env, target_ulong addr) { - env->dispatch_trace_log = 0; + env->dtl_addr = 0; env->dtl_size = 0; return H_SUCCESS; } -static target_ulong h_register_vpa(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong flags = args[0]; @@ -538,18 +507,22 @@ static target_ulong h_register_vpa(CPUPPCState *env, sPAPREnvironment *spapr, return ret; } -static target_ulong h_cede(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_cede(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { + CPUPPCState *env = &cpu->env; + env->msr |= (1ULL << MSR_EE); hreg_compute_hflags(env); - if (!cpu_has_work(env)) { + if (!cpu_has_work(CPU(cpu))) { env->halted = 1; + env->exception_index = EXCP_HLT; + env->exit_request = 1; } return H_SUCCESS; } -static target_ulong h_rtas(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_rtas(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong rtas_r3 = args[0]; @@ -561,7 +534,7 @@ static target_ulong h_rtas(CPUPPCState *env, sPAPREnvironment *spapr, nret, rtas_r3 + 12 + 4*nargs); } -static target_ulong h_logical_load(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong size = args[0]; @@ -584,7 +557,7 @@ static target_ulong h_logical_load(CPUPPCState *env, sPAPREnvironment *spapr, return H_PARAMETER; } -static target_ulong h_logical_store(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong size = args[0]; @@ -608,7 +581,7 @@ static target_ulong h_logical_store(CPUPPCState *env, sPAPREnvironment *spapr, return H_PARAMETER; } -static target_ulong h_logical_memop(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong dst = args[0]; /* Destination address */ @@ -675,14 +648,14 @@ static target_ulong h_logical_memop(CPUPPCState *env, sPAPREnvironment *spapr, return H_SUCCESS; } -static target_ulong h_logical_icbi(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_logical_icbi(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { /* Nothing to do on emulation, KVM will trap this in the kernel */ return H_SUCCESS; } -static target_ulong h_logical_dcbf(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { /* Nothing to do on emulation, KVM will trap this in the kernel */ @@ -703,35 +676,29 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn) } else { assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX)); - slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE]; } - assert(!(*slot) || (fn == *slot)); + assert(!(*slot)); *slot = fn; } -target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode, +target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, target_ulong *args) { - if (msr_pr) { - hcall_dprintf("Hypercall made with MSR[PR]=1\n"); - return H_PRIVILEGE; - } - if ((opcode <= MAX_HCALL_OPCODE) && ((opcode & 0x3) == 0)) { spapr_hcall_fn fn = papr_hypercall_table[opcode / 4]; if (fn) { - return fn(env, spapr, opcode, args); + return fn(cpu, spapr, opcode, args); } } else if ((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX)) { spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE]; if (fn) { - return fn(env, spapr, opcode, args); + return fn(cpu, spapr, opcode, args); } } diff --git a/hw/spapr_iommu.c b/hw/spapr_iommu.c index 388ffa4b22..d8a098cb1b 100644 --- a/hw/spapr_iommu.c +++ b/hw/spapr_iommu.c @@ -17,10 +17,11 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include "hw.h" -#include "kvm.h" +#include "sysemu/kvm.h" #include "qdev.h" #include "kvm_ppc.h" -#include "dma.h" +#include "sysemu/dma.h" +#include "exec/address-spaces.h" #include "hw/spapr.h" @@ -42,6 +43,7 @@ struct sPAPRTCETable { uint32_t liobn; uint32_t window_size; sPAPRTCE *table; + bool bypass; int fd; QLIST_ENTRY(sPAPRTCETable) list; }; @@ -64,8 +66,8 @@ static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn) static int spapr_tce_translate(DMAContext *dma, dma_addr_t addr, - target_phys_addr_t *paddr, - target_phys_addr_t *len, + hwaddr *paddr, + hwaddr *len, DMADirection dir) { sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); @@ -78,6 +80,12 @@ static int spapr_tce_translate(DMAContext *dma, DMA_ADDR_FMT "\n", tcet->liobn, addr); #endif + if (tcet->bypass) { + *paddr = addr; + *len = (hwaddr)-1; + return 0; + } + /* Check if we are in bound */ if (addr >= tcet->window_size) { #ifdef DEBUG_TCE @@ -112,12 +120,18 @@ DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size) { sPAPRTCETable *tcet; + if (spapr_tce_find_by_liobn(liobn)) { + fprintf(stderr, "Attempted to create TCE table with duplicate" + " LIOBN 0x%x\n", liobn); + return NULL; + } + if (!window_size) { return NULL; } tcet = g_malloc0(sizeof(*tcet)); - dma_context_init(&tcet->dma, spapr_tce_translate, NULL, NULL); + dma_context_init(&tcet->dma, &address_space_memory, spapr_tce_translate, NULL, NULL); tcet->liobn = liobn; tcet->window_size = window_size; @@ -162,6 +176,23 @@ void spapr_tce_free(DMAContext *dma) } } +void spapr_tce_set_bypass(DMAContext *dma, bool bypass) +{ + sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); + + tcet->bypass = bypass; +} + +void spapr_tce_reset(DMAContext *dma) +{ + sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); + size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT) + * sizeof(sPAPRTCE); + + tcet->bypass = false; + memset(tcet->table, 0, table_size); +} + static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, target_ulong tce) { @@ -179,7 +210,7 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, return H_SUCCESS; } -static target_ulong h_put_tce(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong liobn = args[0]; @@ -216,31 +247,47 @@ void spapr_iommu_init(void) } int spapr_dma_dt(void *fdt, int node_off, const char *propname, - DMAContext *dma) + uint32_t liobn, uint64_t window, uint32_t size) { - if (dma) { - sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); - uint32_t dma_prop[] = {cpu_to_be32(tcet->liobn), - 0, 0, - 0, cpu_to_be32(tcet->window_size)}; - int ret; - - ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2); - if (ret < 0) { - return ret; - } + uint32_t dma_prop[5]; + int ret; + + dma_prop[0] = cpu_to_be32(liobn); + dma_prop[1] = cpu_to_be32(window >> 32); + dma_prop[2] = cpu_to_be32(window & 0xFFFFFFFF); + dma_prop[3] = 0; /* window size is 32 bits */ + dma_prop[4] = cpu_to_be32(size); + + ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2); + if (ret < 0) { + return ret; + } - ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2); - if (ret < 0) { - return ret; - } + ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2); + if (ret < 0) { + return ret; + } - ret = fdt_setprop(fdt, node_off, propname, dma_prop, - sizeof(dma_prop)); - if (ret < 0) { - return ret; - } + ret = fdt_setprop(fdt, node_off, propname, dma_prop, sizeof(dma_prop)); + if (ret < 0) { + return ret; } return 0; } + +int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, + DMAContext *iommu) +{ + if (!iommu) { + return 0; + } + + if (iommu->translate == spapr_tce_translate) { + sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, iommu); + return spapr_dma_dt(fdt, node_off, propname, + tcet->liobn, 0, tcet->window_size); + } + + return -1; +} diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index 01e54f3675..8077eb94bc 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -25,7 +25,7 @@ * */ #include "hw.h" -#include "net.h" +#include "net/net.h" #include "hw/qdev.h" #include "hw/spapr.h" #include "hw/spapr_vio.h" @@ -169,7 +169,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, } if (sdev->signal_state & 1) { - qemu_irq_pulse(sdev->qirq); + qemu_irq_pulse(spapr_vio_qirq(sdev)); } return size; @@ -264,7 +264,7 @@ static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd, return 0; } -static target_ulong h_register_logical_lan(CPUPPCState *env, +static target_ulong h_register_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) @@ -328,7 +328,7 @@ static target_ulong h_register_logical_lan(CPUPPCState *env, } -static target_ulong h_free_logical_lan(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_free_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong reg = args[0]; @@ -349,7 +349,7 @@ static target_ulong h_free_logical_lan(CPUPPCState *env, sPAPREnvironment *spapr return H_SUCCESS; } -static target_ulong h_add_logical_lan_buffer(CPUPPCState *env, +static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) @@ -398,7 +398,7 @@ static target_ulong h_add_logical_lan_buffer(CPUPPCState *env, return H_SUCCESS; } -static target_ulong h_send_logical_lan(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong reg = args[0]; @@ -467,7 +467,7 @@ static target_ulong h_send_logical_lan(CPUPPCState *env, sPAPREnvironment *spapr return H_SUCCESS; } -static target_ulong h_multicast_ctrl(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong reg = args[0]; diff --git a/hw/spapr_nvram.c b/hw/spapr_nvram.c new file mode 100644 index 0000000000..680cdba928 --- /dev/null +++ b/hw/spapr_nvram.c @@ -0,0 +1,196 @@ +/* + * QEMU sPAPR NVRAM emulation + * + * Copyright (C) 2012 David Gibson, IBM Corporation. + * + * 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. + */ + +#include <libfdt.h> + +#include "sysemu/device_tree.h" +#include "hw/sysbus.h" +#include "hw/spapr.h" +#include "hw/spapr_vio.h" + +typedef struct sPAPRNVRAM { + VIOsPAPRDevice sdev; + uint32_t size; + uint8_t *buf; + BlockDriverState *drive; +} sPAPRNVRAM; + +#define MIN_NVRAM_SIZE 8192 +#define DEFAULT_NVRAM_SIZE 65536 +#define MAX_NVRAM_SIZE (UINT16_MAX * 16) + +static void rtas_nvram_fetch(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + sPAPRNVRAM *nvram = spapr->nvram; + hwaddr offset, buffer, len; + int alen; + void *membuf; + + if ((nargs != 3) || (nret != 2)) { + rtas_st(rets, 0, -3); + return; + } + + if (!nvram) { + rtas_st(rets, 0, -1); + rtas_st(rets, 1, 0); + return; + } + + offset = rtas_ld(args, 0); + buffer = rtas_ld(args, 1); + len = rtas_ld(args, 2); + + if (((offset + len) < offset) + || ((offset + len) > nvram->size)) { + rtas_st(rets, 0, -3); + rtas_st(rets, 1, 0); + return; + } + + membuf = cpu_physical_memory_map(buffer, &len, 1); + if (nvram->drive) { + alen = bdrv_pread(nvram->drive, offset, membuf, len); + } else { + assert(nvram->buf); + + memcpy(membuf, nvram->buf + offset, len); + alen = len; + } + cpu_physical_memory_unmap(membuf, len, 1, len); + + rtas_st(rets, 0, (alen < len) ? -1 : 0); + rtas_st(rets, 1, (alen < 0) ? 0 : alen); +} + +static void rtas_nvram_store(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + sPAPRNVRAM *nvram = spapr->nvram; + hwaddr offset, buffer, len; + int alen; + void *membuf; + + if ((nargs != 3) || (nret != 2)) { + rtas_st(rets, 0, -3); + return; + } + + if (!nvram) { + rtas_st(rets, 0, -1); + return; + } + + offset = rtas_ld(args, 0); + buffer = rtas_ld(args, 1); + len = rtas_ld(args, 2); + + if (((offset + len) < offset) + || ((offset + len) > nvram->size)) { + rtas_st(rets, 0, -3); + return; + } + + membuf = cpu_physical_memory_map(buffer, &len, 0); + if (nvram->drive) { + alen = bdrv_pwrite(nvram->drive, offset, membuf, len); + } else { + assert(nvram->buf); + + memcpy(nvram->buf + offset, membuf, len); + alen = len; + } + cpu_physical_memory_unmap(membuf, len, 0, len); + + rtas_st(rets, 0, (alen < len) ? -1 : 0); + rtas_st(rets, 1, (alen < 0) ? 0 : alen); +} + +static int spapr_nvram_init(VIOsPAPRDevice *dev) +{ + sPAPRNVRAM *nvram = (sPAPRNVRAM *)dev; + + if (nvram->drive) { + nvram->size = bdrv_getlength(nvram->drive); + } else { + nvram->size = DEFAULT_NVRAM_SIZE; + nvram->buf = g_malloc0(nvram->size); + } + + if ((nvram->size < MIN_NVRAM_SIZE) || (nvram->size > MAX_NVRAM_SIZE)) { + fprintf(stderr, "spapr-nvram must be between %d and %d bytes in size\n", + MIN_NVRAM_SIZE, MAX_NVRAM_SIZE); + return -1; + } + + spapr_rtas_register("nvram-fetch", rtas_nvram_fetch); + spapr_rtas_register("nvram-store", rtas_nvram_store); + + return 0; +} + +static int spapr_nvram_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off) +{ + sPAPRNVRAM *nvram = (sPAPRNVRAM *)dev; + + return fdt_setprop_cell(fdt, node_off, "#bytes", nvram->size); +} + +static Property spapr_nvram_properties[] = { + DEFINE_SPAPR_PROPERTIES(sPAPRNVRAM, sdev), + DEFINE_PROP_DRIVE("drive", sPAPRNVRAM, drive), + DEFINE_PROP_END_OF_LIST(), +}; + +static void spapr_nvram_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); + + k->init = spapr_nvram_init; + k->devnode = spapr_nvram_devnode; + k->dt_name = "nvram"; + k->dt_type = "nvram"; + k->dt_compatible = "qemu,spapr-nvram"; + dc->props = spapr_nvram_properties; +} + +static const TypeInfo spapr_nvram_type_info = { + .name = "spapr-nvram", + .parent = TYPE_VIO_SPAPR_DEVICE, + .instance_size = sizeof(sPAPRNVRAM), + .class_init = spapr_nvram_class_init, +}; + +static void spapr_nvram_register_types(void) +{ + type_register_static(&spapr_nvram_type_info); +} + +type_init(spapr_nvram_register_types) diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index b2e4f785ea..27b3ad3d60 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -23,33 +23,60 @@ * THE SOFTWARE. */ #include "hw.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/msi.h" +#include "pci/msix.h" +#include "pci/pci_host.h" #include "hw/spapr.h" #include "hw/spapr_pci.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #include <libfdt.h> +#include "trace.h" -#include "hw/pci_internals.h" +#include "hw/pci/pci_bus.h" -static PCIDevice *find_dev(sPAPREnvironment *spapr, - uint64_t buid, uint32_t config_addr) -{ - int devfn = (config_addr >> 8) & 0xFF; - sPAPRPHBState *phb; +/* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */ +#define RTAS_QUERY_FN 0 +#define RTAS_CHANGE_FN 1 +#define RTAS_RESET_FN 2 +#define RTAS_CHANGE_MSI_FN 3 +#define RTAS_CHANGE_MSIX_FN 4 - QLIST_FOREACH(phb, &spapr->phbs, list) { - BusChild *kid; +/* Interrupt types to return on RTAS_CHANGE_* */ +#define RTAS_TYPE_MSI 1 +#define RTAS_TYPE_MSIX 2 + +static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid) +{ + sPAPRPHBState *sphb; - if (phb->buid != buid) { + QLIST_FOREACH(sphb, &spapr->phbs, list) { + if (sphb->buid != buid) { continue; } + return sphb; + } + + return NULL; +} + +static PCIDevice *find_dev(sPAPREnvironment *spapr, uint64_t buid, + uint32_t config_addr) +{ + sPAPRPHBState *sphb = find_phb(spapr, buid); + PCIHostState *phb = PCI_HOST_BRIDGE(sphb); + BusState *bus = BUS(phb->bus); + BusChild *kid; + int devfn = (config_addr >> 8) & 0xFF; + + if (!phb) { + return NULL; + } - QTAILQ_FOREACH(kid, &phb->host_state.bus->qbus.children, sibling) { - PCIDevice *dev = (PCIDevice *)kid->child; - if (dev->devfn == devfn) { - return dev; - } + QTAILQ_FOREACH(kid, &bus->children, sibling) { + PCIDevice *dev = (PCIDevice *)kid->child; + if (dev->devfn == devfn) { + return dev; } } @@ -199,6 +226,191 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr, finish_write_pci_config(spapr, 0, addr, size, val, rets); } +/* + * Find an entry with config_addr or returns the empty one if not found AND + * alloc_new is set. + * At the moment the msi_table entries are never released so there is + * no point to look till the end of the list if we need to find the free entry. + */ +static int spapr_msicfg_find(sPAPRPHBState *phb, uint32_t config_addr, + bool alloc_new) +{ + int i; + + for (i = 0; i < SPAPR_MSIX_MAX_DEVS; ++i) { + if (!phb->msi_table[i].nvec) { + break; + } + if (phb->msi_table[i].config_addr == config_addr) { + return i; + } + } + if ((i < SPAPR_MSIX_MAX_DEVS) && alloc_new) { + trace_spapr_pci_msi("Allocating new MSI config", i, config_addr); + return i; + } + + return -1; +} + +/* + * Set MSI/MSIX message data. + * This is required for msi_notify()/msix_notify() which + * will write at the addresses via spapr_msi_write(). + */ +static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr, + bool msix, unsigned req_num) +{ + unsigned i; + MSIMessage msg = { .address = addr, .data = 0 }; + + if (!msix) { + msi_set_message(pdev, msg); + trace_spapr_pci_msi_setup(pdev->name, 0, msg.address); + return; + } + + for (i = 0; i < req_num; ++i) { + msg.address = addr | (i << 2); + msix_set_message(pdev, i, msg); + trace_spapr_pci_msi_setup(pdev->name, i, msg.address); + } +} + +static void rtas_ibm_change_msi(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, uint32_t nret, + target_ulong rets) +{ + uint32_t config_addr = rtas_ld(args, 0); + uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); + unsigned int func = rtas_ld(args, 3); + unsigned int req_num = rtas_ld(args, 4); /* 0 == remove all */ + unsigned int seq_num = rtas_ld(args, 5); + unsigned int ret_intr_type; + int ndev, irq; + sPAPRPHBState *phb = NULL; + PCIDevice *pdev = NULL; + + switch (func) { + case RTAS_CHANGE_MSI_FN: + case RTAS_CHANGE_FN: + ret_intr_type = RTAS_TYPE_MSI; + break; + case RTAS_CHANGE_MSIX_FN: + ret_intr_type = RTAS_TYPE_MSIX; + break; + default: + fprintf(stderr, "rtas_ibm_change_msi(%u) is not implemented\n", func); + rtas_st(rets, 0, -3); /* Parameter error */ + return; + } + + /* Fins sPAPRPHBState */ + phb = find_phb(spapr, buid); + if (phb) { + pdev = find_dev(spapr, buid, config_addr); + } + if (!phb || !pdev) { + rtas_st(rets, 0, -3); /* Parameter error */ + return; + } + + /* Releasing MSIs */ + if (!req_num) { + ndev = spapr_msicfg_find(phb, config_addr, false); + if (ndev < 0) { + trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr); + rtas_st(rets, 0, -1); /* Hardware error */ + return; + } + trace_spapr_pci_msi("Released MSIs", ndev, config_addr); + rtas_st(rets, 0, 0); + rtas_st(rets, 1, 0); + return; + } + + /* Enabling MSI */ + + /* Find a device number in the map to add or reuse the existing one */ + ndev = spapr_msicfg_find(phb, config_addr, true); + if (ndev >= SPAPR_MSIX_MAX_DEVS || ndev < 0) { + fprintf(stderr, "No free entry for a new MSI device\n"); + rtas_st(rets, 0, -1); /* Hardware error */ + return; + } + trace_spapr_pci_msi("Configuring MSI", ndev, config_addr); + + /* Check if there is an old config and MSI number has not changed */ + if (phb->msi_table[ndev].nvec && (req_num != phb->msi_table[ndev].nvec)) { + /* Unexpected behaviour */ + fprintf(stderr, "Cannot reuse MSI config for device#%d", ndev); + rtas_st(rets, 0, -1); /* Hardware error */ + return; + } + + /* There is no cached config, allocate MSIs */ + if (!phb->msi_table[ndev].nvec) { + irq = spapr_allocate_irq_block(req_num, false); + if (irq < 0) { + fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev); + rtas_st(rets, 0, -1); /* Hardware error */ + return; + } + phb->msi_table[ndev].irq = irq; + phb->msi_table[ndev].nvec = req_num; + phb->msi_table[ndev].config_addr = config_addr; + } + + /* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */ + spapr_msi_setmsg(pdev, phb->msi_win_addr | (ndev << 16), + ret_intr_type == RTAS_TYPE_MSIX, req_num); + + rtas_st(rets, 0, 0); + rtas_st(rets, 1, req_num); + rtas_st(rets, 2, ++seq_num); + rtas_st(rets, 3, ret_intr_type); + + trace_spapr_pci_rtas_ibm_change_msi(func, req_num); +} + +static void rtas_ibm_query_interrupt_source_number(sPAPREnvironment *spapr, + uint32_t token, + uint32_t nargs, + target_ulong args, + uint32_t nret, + target_ulong rets) +{ + uint32_t config_addr = rtas_ld(args, 0); + uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); + unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3); + int ndev; + sPAPRPHBState *phb = NULL; + + /* Fins sPAPRPHBState */ + phb = find_phb(spapr, buid); + if (!phb) { + rtas_st(rets, 0, -3); /* Parameter error */ + return; + } + + /* Find device descriptor and start IRQ */ + ndev = spapr_msicfg_find(phb, config_addr, false); + if (ndev < 0) { + trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr); + rtas_st(rets, 0, -1); /* Hardware error */ + return; + } + + intr_src_num = phb->msi_table[ndev].irq + ioa_intr_num; + trace_spapr_pci_rtas_ibm_query_interrupt_source_number(ioa_intr_num, + intr_src_num); + + rtas_st(rets, 0, 0); + rtas_st(rets, 1, intr_src_num); + rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */ +} + static int pci_spapr_swizzle(int slot, int pin) { return (slot + pin) % PCI_NUM_PINS; @@ -223,10 +435,11 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level) */ sPAPRPHBState *phb = opaque; - qemu_set_irq(phb->lsi_table[irq_num].qirq, level); + trace_spapr_pci_lsi_set(phb->busname, irq_num, phb->lsi_table[irq_num].irq); + qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level); } -static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr, +static uint64_t spapr_io_read(void *opaque, hwaddr addr, unsigned size) { switch (size) { @@ -240,7 +453,7 @@ static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr, assert(0); } -static void spapr_io_write(void *opaque, target_phys_addr_t addr, +static void spapr_io_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { switch (size) { @@ -264,6 +477,33 @@ static const MemoryRegionOps spapr_io_ops = { }; /* + * MSI/MSIX memory region implementation. + * The handler handles both MSI and MSIX. + * For MSI-X, the vector number is encoded as a part of the address, + * data is set to 0. + * For MSI, the vector number is encoded in least bits in data. + */ +static void spapr_msi_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + sPAPRPHBState *phb = opaque; + int ndev = addr >> 16; + int vec = ((addr & 0xFFFF) >> 2) | data; + uint32_t irq = phb->msi_table[ndev].irq + vec; + + trace_spapr_pci_msi_write(addr, data, irq); + + qemu_irq_pulse(xics_get_qirq(spapr->icp, irq)); +} + +static const MemoryRegionOps spapr_msi_ops = { + /* There is no .read as the read result is undefined by PCI spec */ + .read = NULL, + .write = spapr_msi_write, + .endianness = DEVICE_LITTLE_ENDIAN +}; + +/* * PHB PCI device */ static DMAContext *spapr_pci_dma_context_fn(PCIBus *bus, void *opaque, @@ -276,24 +516,24 @@ static DMAContext *spapr_pci_dma_context_fn(PCIBus *bus, void *opaque, static int spapr_phb_init(SysBusDevice *s) { - sPAPRPHBState *phb = FROM_SYSBUS(sPAPRPHBState, s); + sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s); + PCIHostState *phb = PCI_HOST_BRIDGE(s); char *namebuf; int i; PCIBus *bus; - uint32_t liobn; - phb->dtbusname = g_strdup_printf("pci@%" PRIx64, phb->buid); - namebuf = alloca(strlen(phb->dtbusname) + 32); + sphb->dtbusname = g_strdup_printf("pci@%" PRIx64, sphb->buid); + namebuf = alloca(strlen(sphb->dtbusname) + 32); /* Initialize memory regions */ - sprintf(namebuf, "%s.mmio", phb->dtbusname); - memory_region_init(&phb->memspace, namebuf, INT64_MAX); + sprintf(namebuf, "%s.mmio", sphb->dtbusname); + memory_region_init(&sphb->memspace, namebuf, INT64_MAX); - sprintf(namebuf, "%s.mmio-alias", phb->dtbusname); - memory_region_init_alias(&phb->memwindow, namebuf, &phb->memspace, - SPAPR_PCI_MEM_WIN_BUS_OFFSET, phb->mem_win_size); - memory_region_add_subregion(get_system_memory(), phb->mem_win_addr, - &phb->memwindow); + sprintf(namebuf, "%s.mmio-alias", sphb->dtbusname); + memory_region_init_alias(&sphb->memwindow, namebuf, &sphb->memspace, + SPAPR_PCI_MEM_WIN_BUS_OFFSET, sphb->mem_win_size); + memory_region_add_subregion(get_system_memory(), sphb->mem_win_addr, + &sphb->memwindow); /* On ppc, we only have MMIO no specific IO space from the CPU * perspective. In theory we ought to be able to embed the PCI IO @@ -303,47 +543,67 @@ static int spapr_phb_init(SysBusDevice *s) * system io address space. This hack to bounce things via * system_io works around the problem until all the users of * old_portion are updated */ - sprintf(namebuf, "%s.io", phb->dtbusname); - memory_region_init(&phb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE); + sprintf(namebuf, "%s.io", sphb->dtbusname); + memory_region_init(&sphb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE); /* FIXME: fix to support multiple PHBs */ - memory_region_add_subregion(get_system_io(), 0, &phb->iospace); + memory_region_add_subregion(get_system_io(), 0, &sphb->iospace); - sprintf(namebuf, "%s.io-alias", phb->dtbusname); - memory_region_init_io(&phb->iowindow, &spapr_io_ops, phb, + sprintf(namebuf, "%s.io-alias", sphb->dtbusname); + memory_region_init_io(&sphb->iowindow, &spapr_io_ops, sphb, namebuf, SPAPR_PCI_IO_WIN_SIZE); - memory_region_add_subregion(get_system_memory(), phb->io_win_addr, - &phb->iowindow); + memory_region_add_subregion(get_system_memory(), sphb->io_win_addr, + &sphb->iowindow); + + /* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors, + * we need to allocate some memory to catch those writes coming + * from msi_notify()/msix_notify() */ + if (msi_supported) { + sprintf(namebuf, "%s.msi", sphb->dtbusname); + memory_region_init_io(&sphb->msiwindow, &spapr_msi_ops, sphb, + namebuf, SPAPR_MSIX_MAX_DEVS * 0x10000); + memory_region_add_subregion(get_system_memory(), sphb->msi_win_addr, + &sphb->msiwindow); + } - bus = pci_register_bus(&phb->busdev.qdev, - phb->busname ? phb->busname : phb->dtbusname, - pci_spapr_set_irq, pci_spapr_map_irq, phb, - &phb->memspace, &phb->iospace, + bus = pci_register_bus(DEVICE(s), + sphb->busname ? sphb->busname : sphb->dtbusname, + pci_spapr_set_irq, pci_spapr_map_irq, sphb, + &sphb->memspace, &sphb->iospace, PCI_DEVFN(0, 0), PCI_NUM_PINS); - phb->host_state.bus = bus; + phb->bus = bus; - liobn = SPAPR_PCI_BASE_LIOBN | (pci_find_domain(bus) << 16); - phb->dma = spapr_tce_new_dma_context(liobn, 0x40000000); - pci_setup_iommu(bus, spapr_pci_dma_context_fn, phb); + sphb->dma_liobn = SPAPR_PCI_BASE_LIOBN | (pci_find_domain(bus) << 16); + sphb->dma_window_start = 0; + sphb->dma_window_size = 0x40000000; + sphb->dma = spapr_tce_new_dma_context(sphb->dma_liobn, sphb->dma_window_size); + pci_setup_iommu(bus, spapr_pci_dma_context_fn, sphb); - QLIST_INSERT_HEAD(&spapr->phbs, phb, list); + QLIST_INSERT_HEAD(&spapr->phbs, sphb, list); /* Initialize the LSI table */ for (i = 0; i < PCI_NUM_PINS; i++) { - qemu_irq qirq; - uint32_t num; + uint32_t irq; - qirq = spapr_allocate_lsi(0, &num); - if (!qirq) { + irq = spapr_allocate_lsi(0); + if (!irq) { return -1; } - phb->lsi_table[i].dt_irq = num; - phb->lsi_table[i].qirq = qirq; + sphb->lsi_table[i].irq = irq; } return 0; } +static void spapr_phb_reset(DeviceState *qdev) +{ + SysBusDevice *s = sysbus_from_qdev(qdev); + sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s); + + /* Reset the IOMMU state */ + spapr_tce_reset(sphb->dma); +} + static Property spapr_phb_properties[] = { DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, 0), DEFINE_PROP_STRING("busname", sPAPRPHBState, busname), @@ -351,6 +611,7 @@ static Property spapr_phb_properties[] = { DEFINE_PROP_HEX64("mem_win_size", sPAPRPHBState, mem_win_size, 0x20000000), DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, 0), DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size, 0x10000), + DEFINE_PROP_HEX64("msi_win_addr", sPAPRPHBState, msi_win_addr, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -361,16 +622,12 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data) sdc->init = spapr_phb_init; dc->props = spapr_phb_properties; - - spapr_rtas_register("read-pci-config", rtas_read_pci_config); - spapr_rtas_register("write-pci-config", rtas_write_pci_config); - spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config); - spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config); + dc->reset = spapr_phb_reset; } -static TypeInfo spapr_phb_info = { - .name = "spapr-pci-host-bridge", - .parent = TYPE_SYS_BUS_DEVICE, +static const TypeInfo spapr_phb_info = { + .name = TYPE_SPAPR_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(sPAPRPHBState), .class_init = spapr_phb_class_init, }; @@ -378,11 +635,11 @@ static TypeInfo spapr_phb_info = { void spapr_create_phb(sPAPREnvironment *spapr, const char *busname, uint64_t buid, uint64_t mem_win_addr, uint64_t mem_win_size, - uint64_t io_win_addr) + uint64_t io_win_addr, uint64_t msi_win_addr) { DeviceState *dev; - dev = qdev_create(NULL, spapr_phb_info.name); + dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE); if (busname) { qdev_prop_set_string(dev, "busname", g_strdup(busname)); @@ -391,6 +648,7 @@ void spapr_create_phb(sPAPREnvironment *spapr, qdev_prop_set_uint64(dev, "mem_win_addr", mem_win_addr); qdev_prop_set_uint64(dev, "mem_win_size", mem_win_size); qdev_prop_set_uint64(dev, "io_win_addr", io_win_addr); + qdev_prop_set_uint64(dev, "msi_win_addr", msi_win_addr); qdev_init_nofail(dev); } @@ -406,9 +664,9 @@ void spapr_create_phb(sPAPREnvironment *spapr, #define b_fff(x) b_x((x), 8, 3) /* function number */ #define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */ -int spapr_populate_pci_devices(sPAPRPHBState *phb, - uint32_t xics_phandle, - void *fdt) +int spapr_populate_pci_dt(sPAPRPHBState *phb, + uint32_t xics_phandle, + void *fdt) { int bus_off, i, j; char nodename[256]; @@ -477,7 +735,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb, irqmap[2] = 0; irqmap[3] = cpu_to_be32(j+1); irqmap[4] = cpu_to_be32(xics_phandle); - irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].dt_irq); + irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].irq); irqmap[6] = cpu_to_be32(0x8); } } @@ -485,13 +743,29 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb, _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map, sizeof(interrupt_map))); - spapr_dma_dt(fdt, bus_off, "ibm,dma-window", phb->dma); + spapr_dma_dt(fdt, bus_off, "ibm,dma-window", + phb->dma_liobn, phb->dma_window_start, + phb->dma_window_size); return 0; } -static void register_types(void) +void spapr_pci_rtas_init(void) +{ + spapr_rtas_register("read-pci-config", rtas_read_pci_config); + spapr_rtas_register("write-pci-config", rtas_write_pci_config); + spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config); + spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config); + if (msi_supported) { + spapr_rtas_register("ibm,query-interrupt-source-number", + rtas_ibm_query_interrupt_source_number); + spapr_rtas_register("ibm,change-msi", rtas_ibm_change_msi); + } +} + +static void spapr_pci_register_types(void) { type_register_static(&spapr_phb_info); } -type_init(register_types) + +type_init(spapr_pci_register_types) diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h index d9e46e22e3..7b26ba1561 100644 --- a/hw/spapr_pci.h +++ b/hw/spapr_pci.h @@ -23,41 +23,64 @@ #if !defined(__HW_SPAPR_PCI_H__) #define __HW_SPAPR_PCI_H__ -#include "hw/pci.h" -#include "hw/pci_host.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" #include "hw/xics.h" +#define SPAPR_MSIX_MAX_DEVS 32 + +#define TYPE_SPAPR_PCI_HOST_BRIDGE "spapr-pci-host-bridge" + +#define SPAPR_PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(sPAPRPHBState, (obj), TYPE_SPAPR_PCI_HOST_BRIDGE) + typedef struct sPAPRPHBState { - SysBusDevice busdev; - PCIHostState host_state; + PCIHostState parent_obj; uint64_t buid; char *busname; char *dtbusname; MemoryRegion memspace, iospace; - target_phys_addr_t mem_win_addr, mem_win_size, io_win_addr, io_win_size; - MemoryRegion memwindow, iowindow; + hwaddr mem_win_addr, mem_win_size, io_win_addr, io_win_size; + hwaddr msi_win_addr; + MemoryRegion memwindow, iowindow, msiwindow; + + uint32_t dma_liobn; + uint64_t dma_window_start; + uint64_t dma_window_size; DMAContext *dma; struct { - uint32_t dt_irq; - qemu_irq qirq; + uint32_t irq; } lsi_table[PCI_NUM_PINS]; + struct { + uint32_t config_addr; + uint32_t irq; + int nvec; + } msi_table[SPAPR_MSIX_MAX_DEVS]; + QLIST_ENTRY(sPAPRPHBState) list; } sPAPRPHBState; +static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin) +{ + return xics_get_qirq(spapr->icp, phb->lsi_table[pin].irq); +} + #define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL #define SPAPR_PCI_IO_WIN_SIZE 0x10000 void spapr_create_phb(sPAPREnvironment *spapr, const char *busname, uint64_t buid, uint64_t mem_win_addr, uint64_t mem_win_size, - uint64_t io_win_addr); + uint64_t io_win_addr, uint64_t msi_win_addr); + +int spapr_populate_pci_dt(sPAPRPHBState *phb, + uint32_t xics_phandle, + void *fdt); -int spapr_populate_pci_devices(sPAPRPHBState *phb, - uint32_t xics_phandle, - void *fdt); +void spapr_pci_rtas_init(void); #endif /* __HW_SPAPR_PCI_H__ */ diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c index ae18595150..81eecd0940 100644 --- a/hw/spapr_rtas.c +++ b/hw/spapr_rtas.c @@ -25,10 +25,10 @@ * */ #include "cpu.h" -#include "sysemu.h" -#include "qemu-char.h" +#include "sysemu/sysemu.h" +#include "char/char.h" #include "hw/qdev.h" -#include "device_tree.h" +#include "sysemu/device_tree.h" #include "hw/spapr.h" #include "hw/spapr_vio.h" @@ -163,6 +163,7 @@ static void rtas_start_cpu(sPAPREnvironment *spapr, uint32_t nret, target_ulong rets) { target_ulong id, start, r3; + CPUState *cpu; CPUPPCState *env; if (nargs != 3 || nret != 1) { @@ -175,6 +176,8 @@ static void rtas_start_cpu(sPAPREnvironment *spapr, r3 = rtas_ld(args, 2); for (env = first_cpu; env; env = env->next_cpu) { + cpu = ENV_GET_CPU(env); + if (env->cpu_index != id) { continue; } @@ -184,12 +187,17 @@ static void rtas_start_cpu(sPAPREnvironment *spapr, return; } + /* This will make sure qemu state is up to date with kvm, and + * mark it dirty so our changes get flushed back before the + * new cpu enters */ + kvm_cpu_synchronize_state(env); + env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); env->nip = start; env->gpr[3] = r3; env->halted = 0; - qemu_cpu_kick(env); + qemu_cpu_kick(cpu); rtas_st(rets, 0, 0); return; @@ -234,18 +242,27 @@ target_ulong spapr_rtas_call(sPAPREnvironment *spapr, return H_PARAMETER; } -void spapr_rtas_register(const char *name, spapr_rtas_fn fn) +int spapr_rtas_register(const char *name, spapr_rtas_fn fn) { + int i; + + for (i = 0; i < (rtas_next - rtas_table); i++) { + if (strcmp(name, rtas_table[i].name) == 0) { + fprintf(stderr, "RTAS call \"%s\" registered twice\n", name); + exit(1); + } + } + assert(rtas_next < (rtas_table + TOKEN_MAX)); rtas_next->name = name; rtas_next->fn = fn; - rtas_next++; + return (rtas_next++ - rtas_table) + TOKEN_BASE; } -int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr, - target_phys_addr_t rtas_size) +int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, + hwaddr rtas_size) { int ret; int i; @@ -284,7 +301,7 @@ int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr, for (i = 0; i < TOKEN_MAX; i++) { struct rtas_call *call = &rtas_table[i]; - if (!call->fn) { + if (!call->name) { continue; } diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 05b55032a9..a58621d17e 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -20,14 +20,14 @@ */ #include "hw.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "boards.h" -#include "monitor.h" +#include "monitor/monitor.h" #include "loader.h" #include "elf.h" #include "hw/sysbus.h" -#include "kvm.h" -#include "device_tree.h" +#include "sysemu/kvm.h" +#include "sysemu/device_tree.h" #include "kvm_ppc.h" #include "hw/spapr.h" @@ -49,7 +49,7 @@ #endif static Property spapr_vio_props[] = { - DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, vio_irq_num, 0), \ + DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, irq, 0), \ DEFINE_PROP_END_OF_LIST(), }; @@ -132,8 +132,8 @@ static int vio_make_devnode(VIOsPAPRDevice *dev, } } - if (dev->qirq) { - uint32_t ints_prop[] = {cpu_to_be32(dev->vio_irq_num), 0}; + if (dev->irq) { + uint32_t ints_prop[] = {cpu_to_be32(dev->irq), 0}; ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop, sizeof(ints_prop)); @@ -142,7 +142,7 @@ static int vio_make_devnode(VIOsPAPRDevice *dev, } } - ret = spapr_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->dma); + ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->dma); if (ret < 0) { return ret; } @@ -161,7 +161,7 @@ static int vio_make_devnode(VIOsPAPRDevice *dev, /* * CRQ handling */ -static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_reg_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong reg = args[0]; @@ -219,7 +219,7 @@ static target_ulong free_crq(VIOsPAPRDevice *dev) return H_SUCCESS; } -static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_free_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong reg = args[0]; @@ -233,7 +233,7 @@ static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr, return free_crq(dev); } -static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_send_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong reg = args[0]; @@ -256,7 +256,7 @@ static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr, return H_HARDWARE; } -static target_ulong h_enable_crq(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_enable_crq(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong reg = args[0]; @@ -306,7 +306,7 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq) dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize; if (dev->signal_state & 1) { - qemu_irq_pulse(dev->qirq); + qemu_irq_pulse(spapr_vio_qirq(dev)); } return 0; @@ -316,17 +316,10 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq) static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev) { - VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; - if (dev->dma) { - spapr_tce_free(dev->dma); + spapr_tce_reset(dev->dma); } - dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); - - dev->crq.qladdr = 0; - dev->crq.qsize = 0; - dev->crq.qnext = 0; + free_crq(dev); } static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token, @@ -348,16 +341,14 @@ static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token, rtas_st(rets, 0, -3); return; } - if (enable) { - spapr_tce_free(dev->dma); - dev->dma = NULL; - } else { - VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; - dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); + if (!dev->dma) { + rtas_st(rets, 0, -3); + return; } + spapr_tce_set_bypass(dev->dma, !!enable); + rtas_st(rets, 0, 0); } @@ -409,9 +400,10 @@ static void spapr_vio_busdev_reset(DeviceState *qdev) VIOsPAPRDevice *dev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev); VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - if (dev->crq.qsize) { - free_crq(dev); - } + /* Shut down the request queue and TCEs if necessary */ + spapr_vio_quiesce_one(dev); + + dev->signal_state = 0; if (pc->reset) { pc->reset(dev); @@ -422,7 +414,6 @@ static int spapr_vio_busdev_init(DeviceState *qdev) { VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - uint32_t liobn; char *id; if (dev->reg != -1) { @@ -459,18 +450,20 @@ static int spapr_vio_busdev_init(DeviceState *qdev) dev->qdev.id = id; } - dev->qirq = spapr_allocate_msi(dev->vio_irq_num, &dev->vio_irq_num); - if (!dev->qirq) { + dev->irq = spapr_allocate_msi(dev->irq); + if (!dev->irq) { return -1; } - liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; - dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); + if (pc->rtce_window_size) { + uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; + dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); + } return pc->init(dev); } -static target_ulong h_vio_signal(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_vio_signal(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index 6f9a498ccd..f98ec0a2e5 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -21,7 +21,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "dma.h" +#include "sysemu/dma.h" #define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device" #define VIO_SPAPR_DEVICE(obj) \ @@ -60,9 +60,7 @@ typedef struct VIOsPAPRDeviceClass { struct VIOsPAPRDevice { DeviceState qdev; uint32_t reg; - uint32_t flags; - qemu_irq qirq; - uint32_t vio_irq_num; + uint32_t irq; target_ulong signal_state; VIOsPAPR_CRQ crq; DMAContext *dma; @@ -85,6 +83,11 @@ extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus); extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode); +static inline qemu_irq spapr_vio_qirq(VIOsPAPRDevice *dev) +{ + return xics_get_qirq(spapr->icp, dev->irq); +} + static inline bool spapr_vio_dma_valid(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t size, DMADirection dir) { @@ -128,7 +131,6 @@ void spapr_vscsi_create(VIOsPAPRBus *bus); VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus); -int spapr_tce_set_bypass(uint32_t unit, uint32_t enable); void spapr_vio_quiesce(void); #endif /* _HW_SPAPR_VIO_H */ diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 3cf5844e0f..2d811320ca 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -34,7 +34,6 @@ #include "hw.h" #include "scsi.h" #include "scsi-defs.h" -#include "net.h" /* Remove that when we can */ #include "srp.h" #include "hw/qdev.h" #include "hw/spapr.h" @@ -737,7 +736,7 @@ static int vscsi_send_adapter_info(VSCSIState *s, vscsi_req *req) #endif memset(&info, 0, sizeof(info)); strcpy(info.srp_version, SRP_VERSION); - strncpy(info.partition_name, "qemu", sizeof("qemu")); + memcpy(info.partition_name, "qemu", sizeof("qemu")); info.partition_number = cpu_to_be32(0); info.mad_version = cpu_to_be32(1); info.os_type = cpu_to_be32(2); diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index 99e52cc6b7..ec81a7e6e8 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -1,5 +1,5 @@ #include "qdev.h" -#include "qemu-char.h" +#include "char/char.h" #include "hw/spapr.h" #include "hw/spapr_vio.h" @@ -26,7 +26,7 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size) if ((dev->in == dev->out) && size) { /* toggle line to simulate edge interrupt */ - qemu_irq_pulse(dev->sdev.qirq); + qemu_irq_pulse(spapr_vio_qirq(&dev->sdev)); } for (i = 0; i < size; i++) { assert((dev->in - dev->out) < VTERM_BUFSIZE); @@ -70,7 +70,7 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev) } /* Forward declaration */ -static target_ulong h_put_term_char(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong reg = args[0]; @@ -97,7 +97,7 @@ static target_ulong h_put_term_char(CPUPPCState *env, sPAPREnvironment *spapr, return H_SUCCESS; } -static target_ulong h_get_term_char(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_get_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong reg = args[0]; diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index 1dbf69e808..d11a302f20 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -78,7 +78,7 @@ enum { }; /* Note: on sparc, the lance 16 bit bus is swapped */ -void ledma_memory_read(void *opaque, target_phys_addr_t addr, +void ledma_memory_read(void *opaque, hwaddr addr, uint8_t *buf, int len, int do_bswap) { DMAState *s = opaque; @@ -98,7 +98,7 @@ void ledma_memory_read(void *opaque, target_phys_addr_t addr, } } -void ledma_memory_write(void *opaque, target_phys_addr_t addr, +void ledma_memory_write(void *opaque, hwaddr addr, uint8_t *buf, int len, int do_bswap) { DMAState *s = opaque; @@ -165,7 +165,7 @@ void espdma_memory_write(void *opaque, uint8_t *buf, int len) s->dmaregs[1] += len; } -static uint64_t dma_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t dma_mem_read(void *opaque, hwaddr addr, unsigned size) { DMAState *s = opaque; @@ -182,7 +182,7 @@ static uint64_t dma_mem_read(void *opaque, target_phys_addr_t addr, return s->dmaregs[saddr]; } -static void dma_mem_write(void *opaque, target_phys_addr_t addr, +static void dma_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { DMAState *s = opaque; diff --git a/hw/sparc32_dma.h b/hw/sparc32_dma.h index 8b72c37a98..9497b13d34 100644 --- a/hw/sparc32_dma.h +++ b/hw/sparc32_dma.h @@ -2,9 +2,9 @@ #define SPARC32_DMA_H /* sparc32_dma.c */ -void ledma_memory_read(void *opaque, target_phys_addr_t addr, +void ledma_memory_read(void *opaque, hwaddr addr, uint8_t *buf, int len, int do_bswap); -void ledma_memory_write(void *opaque, target_phys_addr_t addr, +void ledma_memory_write(void *opaque, hwaddr addr, uint8_t *buf, int len, int do_bswap); void espdma_memory_read(void *opaque, uint8_t *buf, int len); void espdma_memory_write(void *opaque, uint8_t *buf, int len); diff --git a/hw/spitz.c b/hw/spitz.c index 20e7835191..8e1be7fb21 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -13,21 +13,21 @@ #include "hw.h" #include "pxa.h" #include "arm-misc.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "pcmcia.h" #include "i2c.h" #include "ssi.h" #include "flash.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "devices.h" #include "sharpsl.h" -#include "console.h" -#include "block.h" +#include "ui/console.h" +#include "block/block.h" #include "audio/audio.h" #include "boards.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "sysbus.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #undef REG_FMT #define REG_FMT "0x%02lx" @@ -60,7 +60,7 @@ typedef struct { ECCState ecc; } SLNANDState; -static uint64_t sl_read(void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t sl_read(void *opaque, hwaddr addr, unsigned size) { SLNANDState *s = (SLNANDState *) opaque; int ryby; @@ -102,7 +102,7 @@ static uint64_t sl_read(void *opaque, target_phys_addr_t addr, unsigned size) return 0; } -static void sl_write(void *opaque, target_phys_addr_t addr, +static void sl_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { SLNANDState *s = (SLNANDState *) opaque; @@ -879,15 +879,14 @@ static struct arm_boot_info spitz_binfo = { .ram_size = 0x04000000, }; -static void spitz_common_init(ram_addr_t ram_size, - const char *kernel_filename, - const char *kernel_cmdline, const char *initrd_filename, - const char *cpu_model, enum spitz_model_e model, int arm_id) +static void spitz_common_init(QEMUMachineInitArgs *args, + enum spitz_model_e model, int arm_id) { PXA2xxState *mpu; DeviceState *scp0, *scp1 = NULL; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *rom = g_new(MemoryRegion, 1); + const char *cpu_model = args->cpu_model; if (!cpu_model) cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0"; @@ -928,48 +927,32 @@ static void spitz_common_init(ram_addr_t ram_size, /* A 4.0 GB microdrive is permanently sitting in CF slot 0. */ spitz_microdrive_attach(mpu, 0); - spitz_binfo.kernel_filename = kernel_filename; - spitz_binfo.kernel_cmdline = kernel_cmdline; - spitz_binfo.initrd_filename = initrd_filename; + spitz_binfo.kernel_filename = args->kernel_filename; + spitz_binfo.kernel_cmdline = args->kernel_cmdline; + spitz_binfo.initrd_filename = args->initrd_filename; spitz_binfo.board_id = arm_id; arm_load_kernel(mpu->cpu, &spitz_binfo); sl_bootparam_write(SL_PXA_PARAM_BASE); } -static void spitz_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void spitz_init(QEMUMachineInitArgs *args) { - spitz_common_init(ram_size, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, spitz, 0x2c9); + spitz_common_init(args, spitz, 0x2c9); } -static void borzoi_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void borzoi_init(QEMUMachineInitArgs *args) { - spitz_common_init(ram_size, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, borzoi, 0x33f); + spitz_common_init(args, borzoi, 0x33f); } -static void akita_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void akita_init(QEMUMachineInitArgs *args) { - spitz_common_init(ram_size, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, akita, 0x2e8); + spitz_common_init(args, akita, 0x2e8); } -static void terrier_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void terrier_init(QEMUMachineInitArgs *args) { - spitz_common_init(ram_size, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model, terrier, 0x33f); + spitz_common_init(args, terrier, 0x33f); } static QEMUMachine akitapda_machine = { @@ -1083,10 +1066,11 @@ static TypeInfo spitz_keyboard_info = { static const VMStateDescription vmstate_corgi_ssp_regs = { .name = "corgi-ssp", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, .fields = (VMStateField []) { + VMSTATE_SSI_SLAVE(ssidev, CorgiSSPState), VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3), VMSTATE_END_OF_LIST(), } @@ -1115,6 +1099,7 @@ static const VMStateDescription vmstate_spitz_lcdtg_regs = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { + VMSTATE_SSI_SLAVE(ssidev, SpitzLCDTG), VMSTATE_UINT32(bl_intensity, SpitzLCDTG), VMSTATE_UINT32(bl_power, SpitzLCDTG), VMSTATE_END_OF_LIST(), @@ -177,13 +177,13 @@ struct srp_tsk_mgmt { uint8_t reserved1[6]; uint64_t tag; uint8_t reserved2[4]; - uint64_t lun QEMU_PACKED; + uint64_t lun; uint8_t reserved3[2]; uint8_t tsk_mgmt_func; uint8_t reserved4; uint64_t task_tag; uint8_t reserved5[8]; -}; +} QEMU_PACKED; /* * We need the packed attribute because the SRP spec only aligns the @@ -198,14 +198,14 @@ struct srp_cmd { uint8_t data_in_desc_cnt; uint64_t tag; uint8_t reserved2[4]; - uint64_t lun QEMU_PACKED; + uint64_t lun; uint8_t reserved3; uint8_t task_attr; uint8_t reserved4; uint8_t add_cdb_len; uint8_t cdb[16]; uint8_t add_data[0]; -}; +} QEMU_PACKED; enum { SRP_RSP_FLAG_RSPVALID = 1 << 0, diff --git a/hw/ssd0303.c b/hw/ssd0303.c index 4e1ee6e12b..cbdf49af57 100644 --- a/hw/ssd0303.c +++ b/hw/ssd0303.c @@ -11,7 +11,7 @@ implement one. Most of the commends relating to brightness and geometry setup are ignored. */ #include "i2c.h" -#include "console.h" +#include "ui/console.h" //#define DEBUG_SSD0303 1 @@ -252,7 +252,7 @@ static void ssd0303_update_display(void *opaque) } } s->redraw = 0; - dpy_update(s->ds, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY); + dpy_gfx_update(s->ds, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY); } static void ssd0303_invalidate_display(void * opaque) diff --git a/hw/ssd0323.c b/hw/ssd0323.c index b101c5112c..fe6f801ae7 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -11,7 +11,7 @@ implement one. Most of the commends relating to brightness and geometry setup are ignored. */ #include "ssi.h" -#include "console.h" +#include "ui/console.h" //#define DEBUG_SSD0323 1 @@ -260,7 +260,7 @@ static void ssd0323_update_display(void *opaque) } } s->redraw = 0; - dpy_update(s->ds, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY); + dpy_gfx_update(s->ds, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY); } static void ssd0323_invalidate_display(void * opaque) @@ -279,6 +279,7 @@ static void ssd0323_cd(void *opaque, int n, int level) static void ssd0323_save(QEMUFile *f, void *opaque) { + SSISlave *ss = SSI_SLAVE(opaque); ssd0323_state *s = (ssd0323_state *)opaque; int i; @@ -296,10 +297,13 @@ static void ssd0323_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->remap); qemu_put_be32(f, s->mode); qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer)); + + qemu_put_be32(f, ss->cs); } static int ssd0323_load(QEMUFile *f, void *opaque, int version_id) { + SSISlave *ss = SSI_SLAVE(opaque); ssd0323_state *s = (ssd0323_state *)opaque; int i; @@ -321,6 +325,8 @@ static int ssd0323_load(QEMUFile *f, void *opaque, int version_id) s->mode = qemu_get_be32(f); qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer)); + ss->cs = qemu_get_be32(f); + return 0; } @@ -348,6 +354,7 @@ static void ssd0323_class_init(ObjectClass *klass, void *data) k->init = ssd0323_init; k->transfer = ssd0323_transfer; + k->cs_polarity = SSI_CS_HIGH; } static TypeInfo ssd0323_info = { diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c index b519bdb29a..d61c3328d9 100644 --- a/hw/ssi-sd.c +++ b/hw/ssi-sd.c @@ -10,7 +10,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "ssi.h" #include "sd.h" @@ -197,6 +197,7 @@ static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val) static void ssi_sd_save(QEMUFile *f, void *opaque) { + SSISlave *ss = SSI_SLAVE(opaque); ssi_sd_state *s = (ssi_sd_state *)opaque; int i; @@ -209,10 +210,13 @@ static void ssi_sd_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->arglen); qemu_put_be32(f, s->response_pos); qemu_put_be32(f, s->stopping); + + qemu_put_be32(f, ss->cs); } static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) { + SSISlave *ss = SSI_SLAVE(opaque); ssi_sd_state *s = (ssi_sd_state *)opaque; int i; @@ -229,6 +233,8 @@ static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) s->response_pos = qemu_get_be32(f); s->stopping = qemu_get_be32(f); + ss->cs = qemu_get_be32(f); + return 0; } @@ -250,6 +256,7 @@ static void ssi_sd_class_init(ObjectClass *klass, void *data) k->init = ssi_sd_init; k->transfer = ssi_sd_transfer; + k->cs_polarity = SSI_CS_LOW; } static TypeInfo ssi_sd_info = { @@ -2,6 +2,8 @@ * QEMU Synchronous Serial Interface support * * Copyright (c) 2009 CodeSourcery. + * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com) + * Copyright (c) 2012 PetaLogix Pty Ltd. * Written by Paul Brook * * This code is licensed under the GNU GPL v2. @@ -25,17 +27,40 @@ static const TypeInfo ssi_bus_info = { .instance_size = sizeof(SSIBus), }; +static void ssi_cs_default(void *opaque, int n, int level) +{ + SSISlave *s = SSI_SLAVE(opaque); + bool cs = !!level; + assert(n == 0); + if (s->cs != cs) { + SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s); + if (ssc->set_cs) { + ssc->set_cs(s, cs); + } + } + s->cs = cs; +} + +static uint32_t ssi_transfer_raw_default(SSISlave *dev, uint32_t val) +{ + SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(dev); + + if ((dev->cs && ssc->cs_polarity == SSI_CS_HIGH) || + (!dev->cs && ssc->cs_polarity == SSI_CS_LOW) || + ssc->cs_polarity == SSI_CS_NONE) { + return ssc->transfer(dev, val); + } + return 0; +} + static int ssi_slave_init(DeviceState *dev) { SSISlave *s = SSI_SLAVE(dev); SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s); - SSIBus *bus; - BusChild *kid; - bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev)); - kid = QTAILQ_FIRST(&bus->qbus.children); - if (kid->child != dev || QTAILQ_NEXT(kid, sibling) != NULL) { - hw_error("Too many devices on SSI bus"); + if (ssc->transfer_raw == ssi_transfer_raw_default && + ssc->cs_polarity != SSI_CS_NONE) { + qdev_init_gpio_in(&s->qdev, ssi_cs_default, 1); } return ssc->init(s); @@ -43,9 +68,14 @@ static int ssi_slave_init(DeviceState *dev) static void ssi_slave_class_init(ObjectClass *klass, void *data) { + SSISlaveClass *ssc = SSI_SLAVE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); + dc->init = ssi_slave_init; dc->bus_type = TYPE_SSI_BUS; + if (!ssc->transfer_raw) { + ssc->transfer_raw = ssi_transfer_raw_default; + } } static TypeInfo ssi_slave_info = { @@ -56,10 +86,15 @@ static TypeInfo ssi_slave_info = { .abstract = true, }; +DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name) +{ + return qdev_create(&bus->qbus, name); +} + DeviceState *ssi_create_slave(SSIBus *bus, const char *name) { - DeviceState *dev; - dev = qdev_create(&bus->qbus, name); + DeviceState *dev = ssi_create_slave_no_init(bus, name); + qdev_init_nofail(dev); return dev; } @@ -74,18 +109,29 @@ SSIBus *ssi_create_bus(DeviceState *parent, const char *name) uint32_t ssi_transfer(SSIBus *bus, uint32_t val) { BusChild *kid; - SSISlave *slave; SSISlaveClass *ssc; + uint32_t r = 0; - kid = QTAILQ_FIRST(&bus->qbus.children); - if (!kid) { - return 0; + QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { + SSISlave *slave = SSI_SLAVE(kid->child); + ssc = SSI_SLAVE_GET_CLASS(slave); + r |= ssc->transfer_raw(slave, val); } - slave = SSI_SLAVE(kid->child); - ssc = SSI_SLAVE_GET_CLASS(slave); - return ssc->transfer(slave, val); + + return r; } +const VMStateDescription vmstate_ssi_slave = { + .name = "SSISlave", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_BOOL(cs, SSISlave), + VMSTATE_END_OF_LIST() + } +}; + static void ssi_slave_register_types(void) { type_register_static(&ssi_bus_info); @@ -93,3 +139,36 @@ static void ssi_slave_register_types(void) } type_init(ssi_slave_register_types) + +typedef struct SSIAutoConnectArg { + qemu_irq **cs_linep; + SSIBus *bus; +} SSIAutoConnectArg; + +static int ssi_auto_connect_slave(Object *child, void *opaque) +{ + SSIAutoConnectArg *arg = opaque; + SSISlave *dev = (SSISlave *)object_dynamic_cast(child, TYPE_SSI_SLAVE); + qemu_irq cs_line; + + if (!dev) { + return 0; + } + + cs_line = qdev_get_gpio_in(DEVICE(dev), 0); + qdev_set_parent_bus(DEVICE(dev), &arg->bus->qbus); + **arg->cs_linep = cs_line; + (*arg->cs_linep)++; + return 0; +} + +void ssi_auto_connect_slaves(DeviceState *parent, qemu_irq *cs_line, + SSIBus *bus) +{ + SSIAutoConnectArg arg = { + .cs_linep = &cs_line, + .bus = bus + }; + + object_child_foreach(OBJECT(parent), ssi_auto_connect_slave, &arg); +} @@ -23,28 +23,70 @@ typedef struct SSISlave SSISlave; #define SSI_SLAVE_GET_CLASS(obj) \ OBJECT_GET_CLASS(SSISlaveClass, (obj), TYPE_SSI_SLAVE) +typedef enum { + SSI_CS_NONE = 0, + SSI_CS_LOW, + SSI_CS_HIGH, +} SSICSMode; + /* Slave devices. */ typedef struct SSISlaveClass { DeviceClass parent_class; int (*init)(SSISlave *dev); + + /* if you have standard or no CS behaviour, just override transfer. + * This is called when the device cs is active (true by default). + */ uint32_t (*transfer)(SSISlave *dev, uint32_t val); + /* called when the CS line changes. Optional, devices only need to implement + * this if they have side effects associated with the cs line (beyond + * tristating the txrx lines). + */ + int (*set_cs)(SSISlave *dev, bool select); + /* define whether or not CS exists and is active low/high */ + SSICSMode cs_polarity; + + /* if you have non-standard CS behaviour override this to take control + * of the CS behaviour at the device level. transfer, set_cs, and + * cs_polarity are unused if this is overwritten. Transfer_raw will + * always be called for the device for every txrx access to the parent bus + */ + uint32_t (*transfer_raw)(SSISlave *dev, uint32_t val); } SSISlaveClass; struct SSISlave { DeviceState qdev; + + /* Chip select state */ + bool cs; }; #define SSI_SLAVE_FROM_QDEV(dev) DO_UPCAST(SSISlave, qdev, dev) #define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev) +extern const VMStateDescription vmstate_ssi_slave; + +#define VMSTATE_SSI_SLAVE(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(SSISlave), \ + .vmsd = &vmstate_ssi_slave, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, SSISlave), \ +} + DeviceState *ssi_create_slave(SSIBus *bus, const char *name); +DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name); /* Master interface. */ SSIBus *ssi_create_bus(DeviceState *parent, const char *name); uint32_t ssi_transfer(SSIBus *bus, uint32_t val); +/* Automatically connect all children nodes a spi controller as slaves */ +void ssi_auto_connect_slaves(DeviceState *parent, qemu_irq *cs_lines, + SSIBus *bus); + /* max111x.c */ void max111x_set_input(DeviceState *dev, int line, uint8_t value); diff --git a/hw/stellaris.c b/hw/stellaris.c index 562fbbf494..26da3c7f60 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -11,11 +11,11 @@ #include "ssi.h" #include "arm-misc.h" #include "devices.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "i2c.h" -#include "net.h" +#include "net/net.h" #include "boards.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #define GPIO_A 0 #define GPIO_B 1 @@ -141,7 +141,7 @@ static void gptm_tick(void *opaque) gptm_update_irq(s); } -static uint64_t gptm_read(void *opaque, target_phys_addr_t offset, +static uint64_t gptm_read(void *opaque, hwaddr offset, unsigned size) { gptm_state *s = (gptm_state *)opaque; @@ -190,7 +190,7 @@ static uint64_t gptm_read(void *opaque, target_phys_addr_t offset, } } -static void gptm_write(void *opaque, target_phys_addr_t offset, +static void gptm_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { gptm_state *s = (gptm_state *)opaque; @@ -410,7 +410,7 @@ static int ssys_board_class(const ssys_state *s) } } -static uint64_t ssys_read(void *opaque, target_phys_addr_t offset, +static uint64_t ssys_read(void *opaque, hwaddr offset, unsigned size) { ssys_state *s = (ssys_state *)opaque; @@ -515,7 +515,7 @@ static void ssys_calculate_system_clock(ssys_state *s) } } -static void ssys_write(void *opaque, target_phys_addr_t offset, +static void ssys_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { ssys_state *s = (ssys_state *)opaque; @@ -701,7 +701,7 @@ typedef struct { #define STELLARIS_I2C_MCS_IDLE 0x20 #define STELLARIS_I2C_MCS_BUSBSY 0x40 -static uint64_t stellaris_i2c_read(void *opaque, target_phys_addr_t offset, +static uint64_t stellaris_i2c_read(void *opaque, hwaddr offset, unsigned size) { stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; @@ -738,7 +738,7 @@ static void stellaris_i2c_update(stellaris_i2c_state *s) qemu_set_irq(s->irq, level); } -static void stellaris_i2c_write(void *opaque, target_phys_addr_t offset, +static void stellaris_i2c_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; @@ -989,7 +989,7 @@ static void stellaris_adc_reset(stellaris_adc_state *s) } } -static uint64_t stellaris_adc_read(void *opaque, target_phys_addr_t offset, +static uint64_t stellaris_adc_read(void *opaque, hwaddr offset, unsigned size) { stellaris_adc_state *s = (stellaris_adc_state *)opaque; @@ -1037,7 +1037,7 @@ static uint64_t stellaris_adc_read(void *opaque, target_phys_addr_t offset, } } -static void stellaris_adc_write(void *opaque, target_phys_addr_t offset, +static void stellaris_adc_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { stellaris_adc_state *s = (stellaris_adc_state *)opaque; @@ -1154,57 +1154,6 @@ static int stellaris_adc_init(SysBusDevice *dev) return 0; } -/* Some boards have both an OLED controller and SD card connected to - the same SSI port, with the SD card chip select connected to a - GPIO pin. Technically the OLED chip select is connected to the SSI - Fss pin. We do not bother emulating that as both devices should - never be selected simultaneously, and our OLED controller ignores stray - 0xff commands that occur when deselecting the SD card. */ - -typedef struct { - SSISlave ssidev; - qemu_irq irq; - int current_dev; - SSIBus *bus[2]; -} stellaris_ssi_bus_state; - -static void stellaris_ssi_bus_select(void *opaque, int irq, int level) -{ - stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; - - s->current_dev = level; -} - -static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val) -{ - stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev); - - return ssi_transfer(s->bus[s->current_dev], val); -} - -static const VMStateDescription vmstate_stellaris_ssi_bus = { - .name = "stellaris_ssi_bus", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(current_dev, stellaris_ssi_bus_state), - VMSTATE_END_OF_LIST() - } -}; - -static int stellaris_ssi_bus_init(SSISlave *dev) -{ - stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev); - - s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0"); - s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1"); - qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1); - - vmstate_register(&dev->qdev, -1, &vmstate_stellaris_ssi_bus, s); - return 0; -} - /* Board init. */ static stellaris_board_info stellaris_boards[] = { { "LM3S811EVB", @@ -1305,19 +1254,25 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, if (board->dc2 & (1 << 4)) { dev = sysbus_create_simple("pl022", 0x40008000, pic[7]); if (board->peripherals & BP_OLED_SSI) { - DeviceState *mux; void *bus; - + DeviceState *sddev; + DeviceState *ssddev; + + /* Some boards have both an OLED controller and SD card connected to + * the same SSI port, with the SD card chip select connected to a + * GPIO pin. Technically the OLED chip select is connected to the + * SSI Fss pin. We do not bother emulating that as both devices + * should never be selected simultaneously, and our OLED controller + * ignores stray 0xff commands that occur when deselecting the SD + * card. + */ bus = qdev_get_child_bus(dev, "ssi"); - mux = ssi_create_slave(bus, "evb6965-ssi"); - gpio_out[GPIO_D][0] = qdev_get_gpio_in(mux, 0); - - bus = qdev_get_child_bus(mux, "ssi0"); - ssi_create_slave(bus, "ssi-sd"); - bus = qdev_get_child_bus(mux, "ssi1"); - dev = ssi_create_slave(bus, "ssd0323"); - gpio_out[GPIO_C][7] = qdev_get_gpio_in(dev, 0); + sddev = ssi_create_slave(bus, "ssi-sd"); + ssddev = ssi_create_slave(bus, "ssd0323"); + gpio_out[GPIO_D][0] = qemu_irq_split(qdev_get_gpio_in(sddev, 0), + qdev_get_gpio_in(ssddev, 0)); + gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 1); /* Make sure the select pin is high. */ qemu_irq_raise(gpio_out[GPIO_D][0]); @@ -1358,19 +1313,17 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, } /* FIXME: Figure out how to generate these from stellaris_boards. */ -static void lm3s811evb_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void lm3s811evb_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]); } -static void lm3s6965evb_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void lm3s6965evb_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]); } @@ -1394,21 +1347,6 @@ static void stellaris_machine_init(void) machine_init(stellaris_machine_init); -static void stellaris_ssi_bus_class_init(ObjectClass *klass, void *data) -{ - SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - - k->init = stellaris_ssi_bus_init; - k->transfer = stellaris_ssi_bus_transfer; -} - -static TypeInfo stellaris_ssi_bus_info = { - .name = "evb6965-ssi", - .parent = TYPE_SSI_SLAVE, - .instance_size = sizeof(stellaris_ssi_bus_state), - .class_init = stellaris_ssi_bus_class_init, -}; - static void stellaris_i2c_class_init(ObjectClass *klass, void *data) { SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); @@ -1456,7 +1394,6 @@ static void stellaris_register_types(void) type_register_static(&stellaris_i2c_info); type_register_static(&stellaris_gptm_info); type_register_static(&stellaris_adc_info); - type_register_static(&stellaris_ssi_bus_info); } type_init(stellaris_register_types) diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index bc97280cca..d7e1e21ff9 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -7,7 +7,7 @@ * This code is licensed under the GPL. */ #include "sysbus.h" -#include "net.h" +#include "net/net.h" #include <zlib.h> //#define DEBUG_STELLARIS_ENET 1 @@ -130,7 +130,7 @@ static int stellaris_enet_can_receive(NetClientState *nc) return (s->np < 31); } -static uint64_t stellaris_enet_read(void *opaque, target_phys_addr_t offset, +static uint64_t stellaris_enet_read(void *opaque, hwaddr offset, unsigned size) { stellaris_enet_state *s = (stellaris_enet_state *)opaque; @@ -198,7 +198,7 @@ static uint64_t stellaris_enet_read(void *opaque, target_phys_addr_t offset, } } -static void stellaris_enet_write(void *opaque, target_phys_addr_t offset, +static void stellaris_enet_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { stellaris_enet_state *s = (stellaris_enet_state *)opaque; diff --git a/hw/stellaris_input.c b/hw/stellaris_input.c index 68c600c04c..7a95c3fc88 100644 --- a/hw/stellaris_input.c +++ b/hw/stellaris_input.c @@ -8,7 +8,7 @@ */ #include "hw.h" #include "devices.h" -#include "console.h" +#include "ui/console.h" typedef struct { qemu_irq irq; diff --git a/hw/stream.h b/hw/stream.h index 21123a9089..f6137d6e25 100644 --- a/hw/stream.h +++ b/hw/stream.h @@ -2,7 +2,7 @@ #define STREAM_H 1 #include "qemu-common.h" -#include "qemu/object.h" +#include "qom/object.h" /* stream slave. Used until qdev provides a generic way. */ #define TYPE_STREAM_SLAVE "stream-slave" diff --git a/hw/strongarm.c b/hw/strongarm.c index 7150eeb2db..804c1a37a6 100644 --- a/hw/strongarm.c +++ b/hw/strongarm.c @@ -28,9 +28,10 @@ */ #include "sysbus.h" #include "strongarm.h" -#include "qemu-error.h" +#include "qemu/error-report.h" #include "arm-misc.h" -#include "sysemu.h" +#include "char/char.h" +#include "sysemu/sysemu.h" #include "ssi.h" //#define DEBUG @@ -59,7 +60,7 @@ #endif static struct { - target_phys_addr_t io_base; + hwaddr io_base; int irq; } sa_serial[] = { { 0x80010000, SA_PIC_UART1 }, @@ -113,7 +114,7 @@ static void strongarm_pic_set_irq(void *opaque, int irq, int level) strongarm_pic_update(s); } -static uint64_t strongarm_pic_mem_read(void *opaque, target_phys_addr_t offset, +static uint64_t strongarm_pic_mem_read(void *opaque, hwaddr offset, unsigned size) { StrongARMPICState *s = opaque; @@ -138,7 +139,7 @@ static uint64_t strongarm_pic_mem_read(void *opaque, target_phys_addr_t offset, } } -static void strongarm_pic_mem_write(void *opaque, target_phys_addr_t offset, +static void strongarm_pic_mem_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { StrongARMPICState *s = opaque; @@ -294,7 +295,7 @@ static inline void strongarm_rtc_hz_tick(void *opaque) strongarm_rtc_int_update(s); } -static uint64_t strongarm_rtc_read(void *opaque, target_phys_addr_t addr, +static uint64_t strongarm_rtc_read(void *opaque, hwaddr addr, unsigned size) { StrongARMRTCState *s = opaque; @@ -316,7 +317,7 @@ static uint64_t strongarm_rtc_read(void *opaque, target_phys_addr_t addr, } } -static void strongarm_rtc_write(void *opaque, target_phys_addr_t addr, +static void strongarm_rtc_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { StrongARMRTCState *s = opaque; @@ -517,7 +518,7 @@ static void strongarm_gpio_handler_update(StrongARMGPIOInfo *s) s->prev_level = level; } -static uint64_t strongarm_gpio_read(void *opaque, target_phys_addr_t offset, +static uint64_t strongarm_gpio_read(void *opaque, hwaddr offset, unsigned size) { StrongARMGPIOInfo *s = opaque; @@ -559,7 +560,7 @@ static uint64_t strongarm_gpio_read(void *opaque, target_phys_addr_t offset, return 0; } -static void strongarm_gpio_write(void *opaque, target_phys_addr_t offset, +static void strongarm_gpio_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { StrongARMGPIOInfo *s = opaque; @@ -609,7 +610,7 @@ static const MemoryRegionOps strongarm_gpio_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static DeviceState *strongarm_gpio_init(target_phys_addr_t base, +static DeviceState *strongarm_gpio_init(hwaddr base, DeviceState *pic) { DeviceState *dev; @@ -729,7 +730,7 @@ static void strongarm_ppc_handler_update(StrongARMPPCInfo *s) s->prev_level = level; } -static uint64_t strongarm_ppc_read(void *opaque, target_phys_addr_t offset, +static uint64_t strongarm_ppc_read(void *opaque, hwaddr offset, unsigned size) { StrongARMPPCInfo *s = opaque; @@ -759,7 +760,7 @@ static uint64_t strongarm_ppc_read(void *opaque, target_phys_addr_t offset, return 0; } -static void strongarm_ppc_write(void *opaque, target_phys_addr_t offset, +static void strongarm_ppc_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { StrongARMPPCInfo *s = opaque; @@ -1095,7 +1096,7 @@ static void strongarm_uart_tx(void *opaque) strongarm_uart_update_int_status(s); } -static uint64_t strongarm_uart_read(void *opaque, target_phys_addr_t addr, +static uint64_t strongarm_uart_read(void *opaque, hwaddr addr, unsigned size) { StrongARMUARTState *s = opaque; @@ -1137,7 +1138,7 @@ static uint64_t strongarm_uart_read(void *opaque, target_phys_addr_t addr, } } -static void strongarm_uart_write(void *opaque, target_phys_addr_t addr, +static void strongarm_uart_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { StrongARMUARTState *s = opaque; @@ -1376,7 +1377,7 @@ static void strongarm_ssp_fifo_update(StrongARMSSPState *s) strongarm_ssp_int_update(s); } -static uint64_t strongarm_ssp_read(void *opaque, target_phys_addr_t addr, +static uint64_t strongarm_ssp_read(void *opaque, hwaddr addr, unsigned size) { StrongARMSSPState *s = opaque; @@ -1409,7 +1410,7 @@ static uint64_t strongarm_ssp_read(void *opaque, target_phys_addr_t addr, return 0; } -static void strongarm_ssp_write(void *opaque, target_phys_addr_t addr, +static void strongarm_ssp_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { StrongARMSSPState *s = opaque; diff --git a/hw/strongarm.h b/hw/strongarm.h index d30dd6ac5e..2893f94445 100644 --- a/hw/strongarm.h +++ b/hw/strongarm.h @@ -1,7 +1,7 @@ #ifndef _STRONGARM_H #define _STRONGARM_H -#include "memory.h" +#include "exec/memory.h" #define SA_CS0 0x00000000 #define SA_CS1 0x08000000 diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c index 8dfa5ecab6..b78d54f232 100644 --- a/hw/sun4c_intctl.c +++ b/hw/sun4c_intctl.c @@ -24,7 +24,7 @@ #include "hw.h" #include "sun4m.h" -#include "monitor.h" +#include "monitor/monitor.h" #include "sysbus.h" //#define DEBUG_IRQ_COUNT @@ -61,7 +61,7 @@ typedef struct Sun4c_INTCTLState { static void sun4c_check_interrupts(void *opaque); -static uint64_t sun4c_intctl_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t sun4c_intctl_mem_read(void *opaque, hwaddr addr, unsigned size) { Sun4c_INTCTLState *s = opaque; @@ -73,7 +73,7 @@ static uint64_t sun4c_intctl_mem_read(void *opaque, target_phys_addr_t addr, return ret; } -static void sun4c_intctl_mem_write(void *opaque, target_phys_addr_t addr, +static void sun4c_intctl_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { Sun4c_INTCTLState *s = opaque; @@ -94,29 +94,6 @@ static const MemoryRegionOps sun4c_intctl_mem_ops = { }, }; -void sun4c_pic_info(Monitor *mon, void *opaque) -{ - Sun4c_INTCTLState *s = opaque; - - monitor_printf(mon, "master: pending 0x%2.2x, enabled 0x%2.2x\n", - s->pending, s->reg); -} - -void sun4c_irq_info(Monitor *mon, void *opaque) -{ -#ifndef DEBUG_IRQ_COUNT - monitor_printf(mon, "irq statistic code not compiled.\n"); -#else - Sun4c_INTCTLState *s = opaque; - int64_t count; - - monitor_printf(mon, "IRQ statistics:\n"); - count = s->irq_count; - if (count > 0) - monitor_printf(mon, " %" PRId64 "\n", count); -#endif -} - static const uint32_t intbit_to_level[] = { 0, 1, 4, 6, 8, 10, 0, 14, }; static void sun4c_check_interrupts(void *opaque) diff --git a/hw/sun4m.c b/hw/sun4m.c index 0f909b5f86..0d84b373b1 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -22,13 +22,13 @@ * THE SOFTWARE. */ #include "sysbus.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "sun4m.h" #include "nvram.h" #include "sparc32_dma.h" #include "fdc.h" -#include "sysemu.h" -#include "net.h" +#include "sysemu/sysemu.h" +#include "net/net.h" #include "boards.h" #include "firmware_abi.h" #include "esp.h" @@ -40,7 +40,7 @@ #include "qdev-addr.h" #include "loader.h" #include "elf.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "trace.h" /* @@ -87,16 +87,16 @@ #define ESCC_CLOCK 4915200 struct sun4m_hwdef { - target_phys_addr_t iommu_base, iommu_pad_base, iommu_pad_len, slavio_base; - target_phys_addr_t intctl_base, counter_base, nvram_base, ms_kb_base; - target_phys_addr_t serial_base, fd_base; - target_phys_addr_t afx_base, idreg_base, dma_base, esp_base, le_base; - target_phys_addr_t tcx_base, cs_base, apc_base, aux1_base, aux2_base; - target_phys_addr_t bpp_base, dbri_base, sx_base; + hwaddr iommu_base, iommu_pad_base, iommu_pad_len, slavio_base; + hwaddr intctl_base, counter_base, nvram_base, ms_kb_base; + hwaddr serial_base, fd_base; + hwaddr afx_base, idreg_base, dma_base, esp_base, le_base; + hwaddr tcx_base, cs_base, apc_base, aux1_base, aux2_base; + hwaddr bpp_base, dbri_base, sx_base; struct { - target_phys_addr_t reg_base, vram_base; + hwaddr reg_base, vram_base; } vsimm[MAX_VSIMMS]; - target_phys_addr_t ecc_base; + hwaddr ecc_base; uint64_t max_mem; const char * const default_cpu_model; uint32_t ecc_version; @@ -108,13 +108,13 @@ struct sun4m_hwdef { #define MAX_IOUNITS 5 struct sun4d_hwdef { - target_phys_addr_t iounit_bases[MAX_IOUNITS], slavio_base; - target_phys_addr_t counter_base, nvram_base, ms_kb_base; - target_phys_addr_t serial_base; - target_phys_addr_t espdma_base, esp_base; - target_phys_addr_t ledma_base, le_base; - target_phys_addr_t tcx_base; - target_phys_addr_t sbi_base; + hwaddr iounit_bases[MAX_IOUNITS], slavio_base; + hwaddr counter_base, nvram_base, ms_kb_base; + hwaddr serial_base; + hwaddr espdma_base, esp_base; + hwaddr ledma_base, le_base; + hwaddr tcx_base; + hwaddr sbi_base; uint64_t max_mem; const char * const default_cpu_model; uint32_t iounit_version; @@ -123,11 +123,11 @@ struct sun4d_hwdef { }; struct sun4c_hwdef { - target_phys_addr_t iommu_base, slavio_base; - target_phys_addr_t intctl_base, counter_base, nvram_base, ms_kb_base; - target_phys_addr_t serial_base, fd_base; - target_phys_addr_t idreg_base, dma_base, esp_base, le_base; - target_phys_addr_t tcx_base, aux1_base; + hwaddr iommu_base, slavio_base; + hwaddr intctl_base, counter_base, nvram_base, ms_kb_base; + hwaddr serial_base, fd_base; + hwaddr idreg_base, dma_base, esp_base, le_base; + hwaddr tcx_base, aux1_base; uint64_t max_mem; const char * const default_cpu_model; uint32_t iommu_version; @@ -253,21 +253,24 @@ void cpu_check_irqs(CPUSPARCState *env) } } -static void cpu_kick_irq(CPUSPARCState *env) +static void cpu_kick_irq(SPARCCPU *cpu) { + CPUSPARCState *env = &cpu->env; + env->halted = 0; cpu_check_irqs(env); - qemu_cpu_kick(env); + qemu_cpu_kick(CPU(cpu)); } static void cpu_set_irq(void *opaque, int irq, int level) { - CPUSPARCState *env = opaque; + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; if (level) { trace_sun4m_cpu_set_irq_raise(irq); env->pil_in |= 1 << irq; - cpu_kick_irq(env); + cpu_kick_irq(cpu); } else { trace_sun4m_cpu_set_irq_lower(irq); env->pil_in &= ~(1 << irq); @@ -370,7 +373,7 @@ static unsigned long sun4m_load_kernel(const char *kernel_filename, return kernel_size; } -static void *iommu_init(target_phys_addr_t addr, uint32_t version, qemu_irq irq) +static void *iommu_init(hwaddr addr, uint32_t version, qemu_irq irq) { DeviceState *dev; SysBusDevice *s; @@ -385,7 +388,7 @@ static void *iommu_init(target_phys_addr_t addr, uint32_t version, qemu_irq irq) return s; } -static void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq, +static void *sparc32_dma_init(hwaddr daddr, qemu_irq parent_irq, void *iommu, qemu_irq *dev_irq, int is_ledma) { DeviceState *dev; @@ -403,7 +406,7 @@ static void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq, return s; } -static void lance_init(NICInfo *nd, target_phys_addr_t leaddr, +static void lance_init(NICInfo *nd, hwaddr leaddr, void *dma_opaque, qemu_irq irq) { DeviceState *dev; @@ -423,8 +426,8 @@ static void lance_init(NICInfo *nd, target_phys_addr_t leaddr, qdev_connect_gpio_out(dma_opaque, 0, reset); } -static DeviceState *slavio_intctl_init(target_phys_addr_t addr, - target_phys_addr_t addrg, +static DeviceState *slavio_intctl_init(hwaddr addr, + hwaddr addrg, qemu_irq **parent_irq) { DeviceState *dev; @@ -452,7 +455,7 @@ static DeviceState *slavio_intctl_init(target_phys_addr_t addr, #define SYS_TIMER_OFFSET 0x10000ULL #define CPU_TIMER_OFFSET(cpu) (0x1000ULL * cpu) -static void slavio_timer_init_all(target_phys_addr_t addr, qemu_irq master_irq, +static void slavio_timer_init_all(hwaddr addr, qemu_irq master_irq, qemu_irq *cpu_irqs, unsigned int num_cpus) { DeviceState *dev; @@ -467,20 +470,31 @@ static void slavio_timer_init_all(target_phys_addr_t addr, qemu_irq master_irq, sysbus_mmio_map(s, 0, addr + SYS_TIMER_OFFSET); for (i = 0; i < MAX_CPUS; i++) { - sysbus_mmio_map(s, i + 1, addr + (target_phys_addr_t)CPU_TIMER_OFFSET(i)); + sysbus_mmio_map(s, i + 1, addr + (hwaddr)CPU_TIMER_OFFSET(i)); sysbus_connect_irq(s, i + 1, cpu_irqs[i]); } } +static qemu_irq slavio_system_powerdown; + +static void slavio_powerdown_req(Notifier *n, void *opaque) +{ + qemu_irq_raise(slavio_system_powerdown); +} + +static Notifier slavio_system_powerdown_notifier = { + .notify = slavio_powerdown_req +}; + #define MISC_LEDS 0x01600000 #define MISC_CFG 0x01800000 #define MISC_DIAG 0x01a00000 #define MISC_MDM 0x01b00000 #define MISC_SYS 0x01f00000 -static void slavio_misc_init(target_phys_addr_t base, - target_phys_addr_t aux1_base, - target_phys_addr_t aux2_base, qemu_irq irq, +static void slavio_misc_init(hwaddr base, + hwaddr aux1_base, + hwaddr aux2_base, qemu_irq irq, qemu_irq fdc_tc) { DeviceState *dev; @@ -514,10 +528,11 @@ static void slavio_misc_init(target_phys_addr_t base, } sysbus_connect_irq(s, 0, irq); sysbus_connect_irq(s, 1, fdc_tc); - qemu_system_powerdown = qdev_get_gpio_in(dev, 0); + slavio_system_powerdown = qdev_get_gpio_in(dev, 0); + qemu_register_powerdown_notifier(&slavio_system_powerdown_notifier); } -static void ecc_init(target_phys_addr_t base, qemu_irq irq, uint32_t version) +static void ecc_init(hwaddr base, qemu_irq irq, uint32_t version) { DeviceState *dev; SysBusDevice *s; @@ -533,7 +548,7 @@ static void ecc_init(target_phys_addr_t base, qemu_irq irq, uint32_t version) } } -static void apc_init(target_phys_addr_t power_base, qemu_irq cpu_halt) +static void apc_init(hwaddr power_base, qemu_irq cpu_halt) { DeviceState *dev; SysBusDevice *s; @@ -546,7 +561,7 @@ static void apc_init(target_phys_addr_t power_base, qemu_irq cpu_halt) sysbus_connect_irq(s, 0, cpu_halt); } -static void tcx_init(target_phys_addr_t addr, int vram_size, int width, +static void tcx_init(hwaddr addr, int vram_size, int width, int height, int depth) { DeviceState *dev; @@ -582,7 +597,7 @@ static void tcx_init(target_phys_addr_t addr, int vram_size, int width, /* NCR89C100/MACIO Internal ID register */ static const uint8_t idreg_data[] = { 0xfe, 0x81, 0x01, 0x03 }; -static void idreg_init(target_phys_addr_t addr) +static void idreg_init(hwaddr addr) { DeviceState *dev; SysBusDevice *s; @@ -631,7 +646,7 @@ typedef struct AFXState { } AFXState; /* SS-5 TCX AFX register */ -static void afx_init(target_phys_addr_t addr) +static void afx_init(hwaddr addr) { DeviceState *dev; SysBusDevice *s; @@ -675,11 +690,11 @@ typedef struct PROMState { /* Boot PROM (OpenBIOS) */ static uint64_t translate_prom_address(void *opaque, uint64_t addr) { - target_phys_addr_t *base_addr = (target_phys_addr_t *)opaque; + hwaddr *base_addr = (hwaddr *)opaque; return addr + *base_addr - PROM_VADDR; } -static void prom_init(target_phys_addr_t addr, const char *bios_name) +static void prom_init(hwaddr addr, const char *bios_name) { DeviceState *dev; SysBusDevice *s; @@ -762,7 +777,7 @@ static int ram_init1(SysBusDevice *dev) return 0; } -static void ram_init(target_phys_addr_t addr, ram_addr_t RAM_size, +static void ram_init(hwaddr addr, ram_addr_t RAM_size, uint64_t max_mem) { DeviceState *dev; @@ -828,7 +843,7 @@ static void cpu_devinit(const char *cpu_model, unsigned int id, qemu_register_reset(secondary_cpu_reset, cpu); env->halted = 1; } - *cpu_irqs = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS); + *cpu_irqs = qemu_allocate_irqs(cpu_set_irq, cpu, MAX_PILS); env->prom_addr = prom_addr; } @@ -1291,92 +1306,118 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { }; /* SPARCstation 5 hardware initialisation */ -static void ss5_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss5_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[0], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCstation 10 hardware initialisation */ -static void ss10_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss10_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[1], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCserver 600MP hardware initialisation */ -static void ss600mp_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss600mp_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[2], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCstation 20 hardware initialisation */ -static void ss20_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss20_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[3], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCstation Voyager hardware initialisation */ -static void vger_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void vger_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[4], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCstation LX hardware initialisation */ -static void ss_lx_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss_lx_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[5], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCstation 4 hardware initialisation */ -static void ss4_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss4_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[6], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCClassic hardware initialisation */ -static void scls_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void scls_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[7], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCbook hardware initialisation */ -static void sbook_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void sbook_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[8], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } @@ -1385,7 +1426,7 @@ static QEMUMachine ss5_machine = { .name = "SS-5", .desc = "Sun4m platform, SPARCstation 5", .init = ss5_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, .is_default = 1, }; @@ -1393,7 +1434,7 @@ static QEMUMachine ss10_machine = { .name = "SS-10", .desc = "Sun4m platform, SPARCstation 10", .init = ss10_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, .max_cpus = 4, }; @@ -1401,7 +1442,7 @@ static QEMUMachine ss600mp_machine = { .name = "SS-600MP", .desc = "Sun4m platform, SPARCserver 600MP", .init = ss600mp_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, .max_cpus = 4, }; @@ -1409,7 +1450,7 @@ static QEMUMachine ss20_machine = { .name = "SS-20", .desc = "Sun4m platform, SPARCstation 20", .init = ss20_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, .max_cpus = 4, }; @@ -1417,35 +1458,35 @@ static QEMUMachine voyager_machine = { .name = "Voyager", .desc = "Sun4m platform, SPARCstation Voyager", .init = vger_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, }; static QEMUMachine ss_lx_machine = { .name = "LX", .desc = "Sun4m platform, SPARCstation LX", .init = ss_lx_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, }; static QEMUMachine ss4_machine = { .name = "SS-4", .desc = "Sun4m platform, SPARCstation 4", .init = ss4_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, }; static QEMUMachine scls_machine = { .name = "SPARCClassic", .desc = "Sun4m platform, SPARCClassic", .init = scls_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, }; static QEMUMachine sbook_machine = { .name = "SPARCbook", .desc = "Sun4m platform, SPARCbook", .init = sbook_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, }; static const struct sun4d_hwdef sun4d_hwdefs[] = { @@ -1503,7 +1544,7 @@ static const struct sun4d_hwdef sun4d_hwdefs[] = { }, }; -static DeviceState *sbi_init(target_phys_addr_t addr, qemu_irq **parent_irq) +static DeviceState *sbi_init(hwaddr addr, qemu_irq **parent_irq) { DeviceState *dev; SysBusDevice *s; @@ -1564,7 +1605,7 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, } for (i = 0; i < MAX_IOUNITS; i++) - if (hwdef->iounit_bases[i] != (target_phys_addr_t)-1) + if (hwdef->iounit_bases[i] != (hwaddr)-1) iounits[i] = iommu_init(hwdef->iounit_bases[i], hwdef->iounit_version, sbi_irq[0]); @@ -1639,21 +1680,27 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, } /* SPARCserver 1000 hardware initialisation */ -static void ss1000_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss1000_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4d_hw_init(&sun4d_hwdefs[0], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCcenter 2000 hardware initialisation */ -static void ss2000_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss2000_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4d_hw_init(&sun4d_hwdefs[1], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } @@ -1662,7 +1709,7 @@ static QEMUMachine ss1000_machine = { .name = "SS-1000", .desc = "Sun4d platform, SPARCserver 1000", .init = ss1000_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, .max_cpus = 8, }; @@ -1670,7 +1717,7 @@ static QEMUMachine ss2000_machine = { .name = "SS-2000", .desc = "Sun4d platform, SPARCcenter 2000", .init = ss2000_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, .max_cpus = 20, }; @@ -1697,7 +1744,7 @@ static const struct sun4c_hwdef sun4c_hwdefs[] = { }, }; -static DeviceState *sun4c_intctl_init(target_phys_addr_t addr, +static DeviceState *sun4c_intctl_init(hwaddr addr, qemu_irq *parent_irq) { DeviceState *dev; @@ -1778,7 +1825,7 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size, slavio_irq[1], serial_hds[0], serial_hds[1], ESCC_CLOCK, 1); - if (hwdef->fd_base != (target_phys_addr_t)-1) { + if (hwdef->fd_base != (hwaddr)-1) { /* there is zero or one floppy drive */ memset(fd, 0, sizeof(fd)); fd[0] = drive_get(IF_FLOPPY, 0, 0); @@ -1833,11 +1880,14 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size, } /* SPARCstation 2 hardware initialisation */ -static void ss2_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss2_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4c_hw_init(&sun4c_hwdefs[0], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } @@ -1846,7 +1896,7 @@ static QEMUMachine ss2_machine = { .name = "SS-2", .desc = "Sun4c platform, SPARCstation 2", .init = ss2_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, }; static void sun4m_register_types(void) diff --git a/hw/sun4m.h b/hw/sun4m.h index 504c3af413..47eb945f07 100644 --- a/hw/sun4m.h +++ b/hw/sun4m.h @@ -6,17 +6,17 @@ /* Devices used by sparc32 system. */ /* iommu.c */ -void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, +void sparc_iommu_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write); static inline void sparc_iommu_memory_read(void *opaque, - target_phys_addr_t addr, + hwaddr addr, uint8_t *buf, int len) { sparc_iommu_memory_rw(opaque, addr, buf, len, 0); } static inline void sparc_iommu_memory_write(void *opaque, - target_phys_addr_t addr, + hwaddr addr, uint8_t *buf, int len) { sparc_iommu_memory_rw(opaque, addr, buf, len, 1); @@ -26,10 +26,6 @@ static inline void sparc_iommu_memory_write(void *opaque, void slavio_pic_info(Monitor *mon, DeviceState *dev); void slavio_irq_info(Monitor *mon, DeviceState *dev); -/* sun4c_intctl.c */ -void sun4c_pic_info(Monitor *mon, void *opaque); -void sun4c_irq_info(Monitor *mon, void *opaque); - /* sun4m.c */ void sun4m_pic_info(Monitor *mon); void sun4m_irq_info(Monitor *mon); diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c index ebefa91b7a..ce6819e10b 100644 --- a/hw/sun4m_iommu.c +++ b/hw/sun4m_iommu.c @@ -130,16 +130,16 @@ typedef struct IOMMUState { SysBusDevice busdev; MemoryRegion iomem; uint32_t regs[IOMMU_NREGS]; - target_phys_addr_t iostart; + hwaddr iostart; qemu_irq irq; uint32_t version; } IOMMUState; -static uint64_t iommu_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t iommu_mem_read(void *opaque, hwaddr addr, unsigned size) { IOMMUState *s = opaque; - target_phys_addr_t saddr; + hwaddr saddr; uint32_t ret; saddr = addr >> 2; @@ -157,11 +157,11 @@ static uint64_t iommu_mem_read(void *opaque, target_phys_addr_t addr, return ret; } -static void iommu_mem_write(void *opaque, target_phys_addr_t addr, +static void iommu_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { IOMMUState *s = opaque; - target_phys_addr_t saddr; + hwaddr saddr; saddr = addr >> 2; trace_sun4m_iommu_mem_writel(saddr, val); @@ -249,11 +249,11 @@ static const MemoryRegionOps iommu_mem_ops = { }, }; -static uint32_t iommu_page_get_flags(IOMMUState *s, target_phys_addr_t addr) +static uint32_t iommu_page_get_flags(IOMMUState *s, hwaddr addr) { uint32_t ret; - target_phys_addr_t iopte; - target_phys_addr_t pa = addr; + hwaddr iopte; + hwaddr pa = addr; iopte = s->regs[IOMMU_BASE] << 4; addr &= ~s->iostart; @@ -264,17 +264,17 @@ static uint32_t iommu_page_get_flags(IOMMUState *s, target_phys_addr_t addr) return ret; } -static target_phys_addr_t iommu_translate_pa(target_phys_addr_t addr, +static hwaddr iommu_translate_pa(hwaddr addr, uint32_t pte) { - target_phys_addr_t pa; + hwaddr pa; pa = ((pte & IOPTE_PAGE) << 4) + (addr & ~IOMMU_PAGE_MASK); trace_sun4m_iommu_translate_pa(addr, pa, pte); return pa; } -static void iommu_bad_addr(IOMMUState *s, target_phys_addr_t addr, +static void iommu_bad_addr(IOMMUState *s, hwaddr addr, int is_write) { trace_sun4m_iommu_bad_addr(addr); @@ -286,12 +286,12 @@ static void iommu_bad_addr(IOMMUState *s, target_phys_addr_t addr, qemu_irq_raise(s->irq); } -void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, +void sparc_iommu_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write) { int l; uint32_t flags; - target_phys_addr_t page, phys_addr; + hwaddr page, phys_addr; while (len > 0) { page = addr & IOMMU_PAGE_MASK; diff --git a/hw/sun4u.c b/hw/sun4u.c index 137a7c6666..cbfd217587 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -22,14 +22,15 @@ * THE SOFTWARE. */ #include "hw.h" -#include "pci.h" +#include "pci/pci.h" #include "apb_pci.h" #include "pc.h" +#include "serial.h" #include "nvram.h" #include "fdc.h" -#include "net.h" -#include "qemu-timer.h" -#include "sysemu.h" +#include "net/net.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" #include "boards.h" #include "firmware_abi.h" #include "fw_cfg.h" @@ -37,8 +38,8 @@ #include "ide.h" #include "loader.h" #include "elf.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" //#define DEBUG_IRQ //#define DEBUG_EBUS @@ -310,16 +311,19 @@ void cpu_check_irqs(CPUSPARCState *env) } } -static void cpu_kick_irq(CPUSPARCState *env) +static void cpu_kick_irq(SPARCCPU *cpu) { + CPUSPARCState *env = &cpu->env; + env->halted = 0; cpu_check_irqs(env); - qemu_cpu_kick(env); + qemu_cpu_kick(CPU(cpu)); } static void cpu_set_ivec_irq(void *opaque, int irq, int level) { - CPUSPARCState *env = opaque; + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; if (level) { if (!(env->ivec_status & 0x20)) { @@ -366,7 +370,7 @@ void cpu_get_timer(QEMUFile *f, CPUTimer *s) qemu_get_timer(f, s->qtimer); } -static CPUTimer* cpu_timer_create(const char* name, CPUSPARCState *env, +static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu, QEMUBHFunc *cb, uint32_t frequency, uint64_t disabled_mask) { @@ -379,7 +383,7 @@ static CPUTimer* cpu_timer_create(const char* name, CPUSPARCState *env, timer->disabled = 1; timer->clock_offset = qemu_get_clock_ns(vm_clock); - timer->qtimer = qemu_new_timer_ns(vm_clock, cb, env); + timer->qtimer = qemu_new_timer_ns(vm_clock, cb, cpu); return timer; } @@ -418,7 +422,8 @@ static void main_cpu_reset(void *opaque) static void tick_irq(void *opaque) { - CPUSPARCState *env = opaque; + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; CPUTimer* timer = env->tick; @@ -430,12 +435,13 @@ static void tick_irq(void *opaque) } env->softint |= SOFTINT_TIMER; - cpu_kick_irq(env); + cpu_kick_irq(cpu); } static void stick_irq(void *opaque) { - CPUSPARCState *env = opaque; + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; CPUTimer* timer = env->stick; @@ -447,12 +453,13 @@ static void stick_irq(void *opaque) } env->softint |= SOFTINT_STIMER; - cpu_kick_irq(env); + cpu_kick_irq(cpu); } static void hstick_irq(void *opaque) { - CPUSPARCState *env = opaque; + SPARCCPU *cpu = opaque; + CPUSPARCState *env = &cpu->env; CPUTimer* timer = env->hstick; @@ -464,7 +471,7 @@ static void hstick_irq(void *opaque) } env->softint |= SOFTINT_STIMER; - cpu_kick_irq(env); + cpu_kick_irq(cpu); } static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency) @@ -625,12 +632,12 @@ typedef struct PROMState { static uint64_t translate_prom_address(void *opaque, uint64_t addr) { - target_phys_addr_t *base_addr = (target_phys_addr_t *)opaque; + hwaddr *base_addr = (hwaddr *)opaque; return addr + *base_addr - PROM_VADDR; } /* Boot PROM (OpenBIOS) */ -static void prom_init(target_phys_addr_t addr, const char *bios_name) +static void prom_init(hwaddr addr, const char *bios_name) { DeviceState *dev; SysBusDevice *s; @@ -714,7 +721,7 @@ static int ram_init1(SysBusDevice *dev) return 0; } -static void ram_init(target_phys_addr_t addr, ram_addr_t RAM_size) +static void ram_init(hwaddr addr, ram_addr_t RAM_size) { DeviceState *dev; SysBusDevice *s; @@ -772,13 +779,13 @@ static SPARCCPU *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef) } env = &cpu->env; - env->tick = cpu_timer_create("tick", env, tick_irq, + env->tick = cpu_timer_create("tick", cpu, tick_irq, tick_frequency, TICK_NPT_MASK); - env->stick = cpu_timer_create("stick", env, stick_irq, + env->stick = cpu_timer_create("stick", cpu, stick_irq, stick_frequency, TICK_INT_DIS); - env->hstick = cpu_timer_create("hstick", env, hstick_irq, + env->hstick = cpu_timer_create("hstick", cpu, hstick_irq, hstick_frequency, TICK_INT_DIS); reset_info = g_malloc0(sizeof(ResetData)); @@ -797,7 +804,6 @@ static void sun4uv_init(MemoryRegion *address_space_mem, const struct hwdef *hwdef) { SPARCCPU *cpu; - CPUSPARCState *env; M48t59State *nvram; unsigned int i; uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry; @@ -810,14 +816,13 @@ static void sun4uv_init(MemoryRegion *address_space_mem, /* init CPUs */ cpu = cpu_devinit(cpu_model, hwdef); - env = &cpu->env; /* set up devices */ ram_init(0, RAM_size); prom_init(hwdef->prom_addr, bios_name); - ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, env, IVEC_MAX); + ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, cpu, IVEC_MAX); pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2, &pci_bus3, &pbm_irqs); pci_vga_init(pci_bus); @@ -929,31 +934,40 @@ static const struct hwdef hwdefs[] = { }; /* Sun4u hardware initialisation */ -static void sun4u_init(ram_addr_t RAM_size, - const char *boot_devices, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ +static void sun4u_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_devices = args->boot_device; sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, &hwdefs[0]); } /* Sun4v hardware initialisation */ -static void sun4v_init(ram_addr_t RAM_size, - const char *boot_devices, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ +static void sun4v_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_devices = args->boot_device; sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, &hwdefs[1]); } /* Niagara hardware initialisation */ -static void niagara_init(ram_addr_t RAM_size, - const char *boot_devices, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ +static void niagara_init(QEMUMachineInitArgs *args) +{ + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_devices = args->boot_device; sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, &hwdefs[2]); } diff --git a/hw/sysbus.c b/hw/sysbus.c index 9d8b1eaf7d..49a41775f8 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -18,8 +18,8 @@ */ #include "sysbus.h" -#include "monitor.h" -#include "exec-memory.h" +#include "monitor/monitor.h" +#include "exec/address-spaces.h" static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent); static char *sysbus_get_fw_dev_path(DeviceState *dev); @@ -48,7 +48,7 @@ void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq) } } -void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr) +void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr) { assert(n >= 0 && n < dev->num_mmio); @@ -56,7 +56,7 @@ void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr) /* ??? region already mapped here. */ return; } - if (dev->mmio[n].addr != (target_phys_addr_t)-1) { + if (dev->mmio[n].addr != (hwaddr)-1) { /* Unregister previous mapping. */ memory_region_del_subregion(get_system_memory(), dev->mmio[n].memory); } @@ -122,7 +122,7 @@ static int sysbus_device_init(DeviceState *dev) } DeviceState *sysbus_create_varargs(const char *name, - target_phys_addr_t addr, ...) + hwaddr addr, ...) { DeviceState *dev; SysBusDevice *s; @@ -133,7 +133,7 @@ DeviceState *sysbus_create_varargs(const char *name, dev = qdev_create(NULL, name); s = sysbus_from_qdev(dev); qdev_init_nofail(dev); - if (addr != (target_phys_addr_t)-1) { + if (addr != (hwaddr)-1) { sysbus_mmio_map(s, 0, addr); } va_start(va, addr); @@ -151,7 +151,7 @@ DeviceState *sysbus_create_varargs(const char *name, } DeviceState *sysbus_try_create_varargs(const char *name, - target_phys_addr_t addr, ...) + hwaddr addr, ...) { DeviceState *dev; SysBusDevice *s; @@ -165,7 +165,7 @@ DeviceState *sysbus_try_create_varargs(const char *name, } s = sysbus_from_qdev(dev); qdev_init_nofail(dev); - if (addr != (target_phys_addr_t)-1) { + if (addr != (hwaddr)-1) { sysbus_mmio_map(s, 0, addr); } va_start(va, addr); @@ -185,7 +185,7 @@ DeviceState *sysbus_try_create_varargs(const char *name, static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) { SysBusDevice *s = sysbus_from_qdev(dev); - target_phys_addr_t size; + hwaddr size; int i; monitor_printf(mon, "%*sirq %d\n", indent, "", s->num_irq); @@ -211,16 +211,16 @@ static char *sysbus_get_fw_dev_path(DeviceState *dev) snprintf(path + off, sizeof(path) - off, "@i%04x", s->pio[0]); } - return strdup(path); + return g_strdup(path); } -void sysbus_add_memory(SysBusDevice *dev, target_phys_addr_t addr, +void sysbus_add_memory(SysBusDevice *dev, hwaddr addr, MemoryRegion *mem) { memory_region_add_subregion(get_system_memory(), addr, mem); } -void sysbus_add_memory_overlap(SysBusDevice *dev, target_phys_addr_t addr, +void sysbus_add_memory_overlap(SysBusDevice *dev, hwaddr addr, MemoryRegion *mem, unsigned priority) { memory_region_add_subregion_overlap(get_system_memory(), addr, mem, @@ -232,7 +232,7 @@ void sysbus_del_memory(SysBusDevice *dev, MemoryRegion *mem) memory_region_del_subregion(get_system_memory(), mem); } -void sysbus_add_io(SysBusDevice *dev, target_phys_addr_t addr, +void sysbus_add_io(SysBusDevice *dev, hwaddr addr, MemoryRegion *mem) { memory_region_add_subregion(get_system_io(), addr, mem); @@ -274,7 +274,7 @@ static void main_system_bus_create(void) main_system_bus = g_malloc0(system_bus_info.instance_size); qbus_create_inplace(main_system_bus, TYPE_SYSTEM_BUS, NULL, "main-system-bus"); - main_system_bus->glib_allocated = true; + OBJECT(main_system_bus)->free = g_free; object_property_add_child(container_get(qdev_get_machine(), "/unattached"), "sysbus", OBJECT(main_system_bus), NULL); diff --git a/hw/sysbus.h b/hw/sysbus.h index acfbcfba52..669cf87ae9 100644 --- a/hw/sysbus.h +++ b/hw/sysbus.h @@ -4,7 +4,7 @@ /* Devices attached directly to the main system bus. */ #include "qdev.h" -#include "memory.h" +#include "exec/memory.h" #define QDEV_MAX_MMIO 32 #define QDEV_MAX_PIO 32 @@ -36,7 +36,7 @@ struct SysBusDevice { qemu_irq *irqp[QDEV_MAX_IRQ]; int num_mmio; struct { - target_phys_addr_t addr; + hwaddr addr; MemoryRegion *memory; } mmio[QDEV_MAX_MMIO]; int num_pio; @@ -56,31 +56,31 @@ void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size); void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq); -void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr); -void sysbus_add_memory(SysBusDevice *dev, target_phys_addr_t addr, +void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr); +void sysbus_add_memory(SysBusDevice *dev, hwaddr addr, MemoryRegion *mem); -void sysbus_add_memory_overlap(SysBusDevice *dev, target_phys_addr_t addr, +void sysbus_add_memory_overlap(SysBusDevice *dev, hwaddr addr, MemoryRegion *mem, unsigned priority); void sysbus_del_memory(SysBusDevice *dev, MemoryRegion *mem); -void sysbus_add_io(SysBusDevice *dev, target_phys_addr_t addr, +void sysbus_add_io(SysBusDevice *dev, hwaddr addr, MemoryRegion *mem); void sysbus_del_io(SysBusDevice *dev, MemoryRegion *mem); MemoryRegion *sysbus_address_space(SysBusDevice *dev); /* Legacy helper function for creating devices. */ DeviceState *sysbus_create_varargs(const char *name, - target_phys_addr_t addr, ...); + hwaddr addr, ...); DeviceState *sysbus_try_create_varargs(const char *name, - target_phys_addr_t addr, ...); + hwaddr addr, ...); static inline DeviceState *sysbus_create_simple(const char *name, - target_phys_addr_t addr, + hwaddr addr, qemu_irq irq) { return sysbus_create_varargs(name, addr, irq, NULL); } static inline DeviceState *sysbus_try_create_simple(const char *name, - target_phys_addr_t addr, + hwaddr addr, qemu_irq irq) { return sysbus_try_create_varargs(name, addr, irq, NULL); diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c index 420925ccb3..e815f83198 100644 --- a/hw/tc6393xb.c +++ b/hw/tc6393xb.c @@ -13,9 +13,9 @@ #include "hw.h" #include "devices.h" #include "flash.h" -#include "console.h" -#include "pixel_ops.h" -#include "blockdev.h" +#include "ui/console.h" +#include "ui/pixel_ops.h" +#include "sysemu/blockdev.h" #define IRQ_TC6393_NAND 0 #define IRQ_TC6393_MMC 1 @@ -215,7 +215,7 @@ static void tc6393xb_sub_irq(void *opaque, int line, int level) { case SCR_ ##N(1): return s->scr.N[1]; \ case SCR_ ##N(2): return s->scr.N[2] -static uint32_t tc6393xb_scr_readb(TC6393xbState *s, target_phys_addr_t addr) +static uint32_t tc6393xb_scr_readb(TC6393xbState *s, hwaddr addr) { switch (addr) { case SCR_REVID: @@ -276,7 +276,7 @@ static uint32_t tc6393xb_scr_readb(TC6393xbState *s, target_phys_addr_t addr) case SCR_ ##N(1): s->scr.N[1] = value; return; \ case SCR_ ##N(2): s->scr.N[2] = value; return -static void tc6393xb_scr_writeb(TC6393xbState *s, target_phys_addr_t addr, uint32_t value) +static void tc6393xb_scr_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) { switch (addr) { SCR_REG_B(ISR); @@ -327,7 +327,7 @@ static void tc6393xb_nand_irq(TC6393xbState *s) { (s->nand.imr & 0x80) && (s->nand.imr & s->nand.isr)); } -static uint32_t tc6393xb_nand_cfg_readb(TC6393xbState *s, target_phys_addr_t addr) { +static uint32_t tc6393xb_nand_cfg_readb(TC6393xbState *s, hwaddr addr) { switch (addr) { case NAND_CFG_COMMAND: return s->nand_enable ? 2 : 0; @@ -340,7 +340,7 @@ static uint32_t tc6393xb_nand_cfg_readb(TC6393xbState *s, target_phys_addr_t add fprintf(stderr, "tc6393xb_nand_cfg: unhandled read at %08x\n", (uint32_t) addr); return 0; } -static void tc6393xb_nand_cfg_writeb(TC6393xbState *s, target_phys_addr_t addr, uint32_t value) { +static void tc6393xb_nand_cfg_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) { switch (addr) { case NAND_CFG_COMMAND: s->nand_enable = (value & 0x2); @@ -357,7 +357,7 @@ static void tc6393xb_nand_cfg_writeb(TC6393xbState *s, target_phys_addr_t addr, (uint32_t) addr, value & 0xff); } -static uint32_t tc6393xb_nand_readb(TC6393xbState *s, target_phys_addr_t addr) { +static uint32_t tc6393xb_nand_readb(TC6393xbState *s, hwaddr addr) { switch (addr) { case NAND_DATA + 0: case NAND_DATA + 1: @@ -376,7 +376,7 @@ static uint32_t tc6393xb_nand_readb(TC6393xbState *s, target_phys_addr_t addr) { fprintf(stderr, "tc6393xb_nand: unhandled read at %08x\n", (uint32_t) addr); return 0; } -static void tc6393xb_nand_writeb(TC6393xbState *s, target_phys_addr_t addr, uint32_t value) { +static void tc6393xb_nand_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) { // fprintf(stderr, "tc6393xb_nand: write at %08x: %02x\n", // (uint32_t) addr, value & 0xff); switch (addr) { @@ -454,7 +454,7 @@ static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update) return; } - dpy_update(s->ds, 0, 0, s->scr_width, s->scr_height); + dpy_gfx_update(s->ds, 0, 0, s->scr_width, s->scr_height); } static void tc6393xb_draw_blank(TC6393xbState *s, int full_update) @@ -472,7 +472,7 @@ static void tc6393xb_draw_blank(TC6393xbState *s, int full_update) d += ds_get_linesize(s->ds); } - dpy_update(s->ds, 0, 0, s->scr_width, s->scr_height); + dpy_gfx_update(s->ds, 0, 0, s->scr_width, s->scr_height); } static void tc6393xb_update_display(void *opaque) @@ -499,7 +499,7 @@ static void tc6393xb_update_display(void *opaque) } -static uint64_t tc6393xb_readb(void *opaque, target_phys_addr_t addr, +static uint64_t tc6393xb_readb(void *opaque, hwaddr addr, unsigned size) { TC6393xbState *s = opaque; @@ -522,7 +522,7 @@ static uint64_t tc6393xb_readb(void *opaque, target_phys_addr_t addr, return 0; } -static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr, +static void tc6393xb_writeb(void *opaque, hwaddr addr, uint64_t value, unsigned size) { TC6393xbState *s = opaque; @@ -22,8 +22,9 @@ * THE SOFTWARE. */ -#include "console.h" -#include "pixel_ops.h" +#include "qemu-common.h" +#include "ui/console.h" +#include "ui/pixel_ops.h" #include "sysbus.h" #include "qdev-addr.h" @@ -36,7 +37,7 @@ typedef struct TCXState { SysBusDevice busdev; - target_phys_addr_t addr; + hwaddr addr; DisplayState *ds; uint8_t *vram; uint32_t *vram24, *cplane; @@ -56,8 +57,10 @@ typedef struct TCXState { uint8_t dac_index, dac_state; } TCXState; -static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch); -static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch); +static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp); +static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp); static void tcx_set_dirty(TCXState *s) { @@ -266,8 +269,8 @@ static void tcx_update_display(void *opaque) } else { if (y_start >= 0) { /* flush to display */ - dpy_update(ts->ds, 0, y_start, - ts->width, y - y_start); + dpy_gfx_update(ts->ds, 0, y_start, + ts->width, y - y_start); y_start = -1; } d += dd * 4; @@ -276,8 +279,8 @@ static void tcx_update_display(void *opaque) } if (y_start >= 0) { /* flush to display */ - dpy_update(ts->ds, 0, y_start, - ts->width, y - y_start); + dpy_gfx_update(ts->ds, 0, y_start, + ts->width, y - y_start); } /* reset modified pages */ if (page_max >= page_min) { @@ -342,8 +345,8 @@ static void tcx24_update_display(void *opaque) } else { if (y_start >= 0) { /* flush to display */ - dpy_update(ts->ds, 0, y_start, - ts->width, y - y_start); + dpy_gfx_update(ts->ds, 0, y_start, + ts->width, y - y_start); y_start = -1; } d += dd * 4; @@ -354,8 +357,8 @@ static void tcx24_update_display(void *opaque) } if (y_start >= 0) { /* flush to display */ - dpy_update(ts->ds, 0, y_start, - ts->width, y - y_start); + dpy_gfx_update(ts->ds, 0, y_start, + ts->width, y - y_start); } /* reset modified pages */ if (page_max >= page_min) { @@ -430,13 +433,13 @@ static void tcx_reset(DeviceState *d) s->dac_state = 0; } -static uint64_t tcx_dac_readl(void *opaque, target_phys_addr_t addr, +static uint64_t tcx_dac_readl(void *opaque, hwaddr addr, unsigned size) { return 0; } -static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint64_t val, +static void tcx_dac_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { TCXState *s = opaque; @@ -470,7 +473,6 @@ static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint64_t val, default: break; } - return; } static const MemoryRegionOps tcx_dac_ops = { @@ -483,13 +485,13 @@ static const MemoryRegionOps tcx_dac_ops = { }, }; -static uint64_t dummy_readl(void *opaque, target_phys_addr_t addr, +static uint64_t dummy_readl(void *opaque, hwaddr addr, unsigned size) { return 0; } -static void dummy_writel(void *opaque, target_phys_addr_t addr, +static void dummy_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { } @@ -574,45 +576,76 @@ static int tcx_init1(SysBusDevice *dev) return 0; } -static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch) +static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp) { TCXState *s = opaque; FILE *f; uint8_t *d, *d1, v; - int y, x; + int ret, y, x; f = fopen(filename, "wb"); - if (!f) + if (!f) { + error_setg(errp, "failed to open file '%s': %s", filename, + strerror(errno)); return; - fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); + } + ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); + if (ret < 0) { + goto write_err; + } d1 = s->vram; for(y = 0; y < s->height; y++) { d = d1; for(x = 0; x < s->width; x++) { v = *d; - fputc(s->r[v], f); - fputc(s->g[v], f); - fputc(s->b[v], f); + ret = fputc(s->r[v], f); + if (ret == EOF) { + goto write_err; + } + ret = fputc(s->g[v], f); + if (ret == EOF) { + goto write_err; + } + ret = fputc(s->b[v], f); + if (ret == EOF) { + goto write_err; + } d++; } d1 += MAXX; } + +out: fclose(f); return; + +write_err: + error_setg(errp, "failed to write to file '%s': %s", filename, + strerror(errno)); + unlink(filename); + goto out; } -static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch) +static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp) { TCXState *s = opaque; FILE *f; uint8_t *d, *d1, v; uint32_t *s24, *cptr, dval; - int y, x; + int ret, y, x; f = fopen(filename, "wb"); - if (!f) + if (!f) { + error_setg(errp, "failed to open file '%s': %s", filename, + strerror(errno)); return; - fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); + } + ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); + if (ret < 0) { + goto write_err; + } d1 = s->vram; s24 = s->vram24; cptr = s->cplane; @@ -621,20 +654,46 @@ static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch) for(x = 0; x < s->width; x++, d++, s24++) { if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct dval = *s24 & 0x00ffffff; - fputc((dval >> 16) & 0xff, f); - fputc((dval >> 8) & 0xff, f); - fputc(dval & 0xff, f); + ret = fputc((dval >> 16) & 0xff, f); + if (ret == EOF) { + goto write_err; + } + ret = fputc((dval >> 8) & 0xff, f); + if (ret == EOF) { + goto write_err; + } + ret = fputc(dval & 0xff, f); + if (ret == EOF) { + goto write_err; + } } else { v = *d; - fputc(s->r[v], f); - fputc(s->g[v], f); - fputc(s->b[v], f); + ret = fputc(s->r[v], f); + if (ret == EOF) { + goto write_err; + } + ret = fputc(s->g[v], f); + if (ret == EOF) { + goto write_err; + } + ret = fputc(s->b[v], f); + if (ret == EOF) { + goto write_err; + } } } d1 += MAXX; } + +out: fclose(f); return; + +write_err: + error_setg(errp, "failed to write to file '%s': %s", filename, + strerror(errno)); + unlink(filename); + goto out; } static Property tcx_properties[] = { diff --git a/hw/tmp105.c b/hw/tmp105.c index 8e8dbd94eb..9c67e644dd 100644 --- a/hw/tmp105.c +++ b/hw/tmp105.c @@ -20,6 +20,7 @@ #include "hw.h" #include "i2c.h" +#include "tmp105.h" typedef struct { I2CSlave i2c; @@ -92,22 +93,22 @@ static void tmp105_read(TMP105State *s) } switch (s->pointer & 3) { - case 0: /* Temperature */ + case TMP105_REG_TEMPERATURE: s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8); s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) & (0xf0 << ((~s->config >> 5) & 3)); /* R */ break; - case 1: /* Configuration */ + case TMP105_REG_CONFIG: s->buf[s->len ++] = s->config; break; - case 2: /* T_LOW */ + case TMP105_REG_T_LOW: s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8; s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0; break; - case 3: /* T_HIGH */ + case TMP105_REG_T_HIGH: s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8; s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0; break; @@ -117,10 +118,10 @@ static void tmp105_read(TMP105State *s) static void tmp105_write(TMP105State *s) { switch (s->pointer & 3) { - case 0: /* Temperature */ + case TMP105_REG_TEMPERATURE: break; - case 1: /* Configuration */ + case TMP105_REG_CONFIG: if (s->buf[0] & ~s->config & (1 << 0)) /* SD */ printf("%s: TMP105 shutdown\n", __FUNCTION__); s->config = s->buf[0]; @@ -128,8 +129,8 @@ static void tmp105_write(TMP105State *s) tmp105_alarm_update(s); break; - case 2: /* T_LOW */ - case 3: /* T_HIGH */ + case TMP105_REG_T_LOW: + case TMP105_REG_T_HIGH: if (s->len >= 3) s->limit[s->pointer & 1] = (int16_t) ((((uint16_t) s->buf[0]) << 8) | s->buf[1]); diff --git a/hw/tmp105.h b/hw/tmp105.h new file mode 100644 index 0000000000..51eff4be1c --- /dev/null +++ b/hw/tmp105.h @@ -0,0 +1,67 @@ +/* + * Texas Instruments TMP105 Temperature Sensor + * + * Browse the data sheet: + * + * http://www.ti.com/lit/gpn/tmp105 + * + * Copyright (C) 2012 Alex Horn <alex.horn@cs.ox.ac.uk> + * Copyright (C) 2008-2012 Andrzej Zaborowski <balrogg@gmail.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ +#ifndef QEMU_TMP105_H +#define QEMU_TMP105_H + +#include "i2c.h" + +/** + * TMP105Reg: + * @TMP105_REG_TEMPERATURE: Temperature register + * @TMP105_REG_CONFIG: Configuration register + * @TMP105_REG_T_LOW: Low temperature register (also known as T_hyst) + * @TMP105_REG_T_HIGH: High temperature register (also known as T_OS) + * + * The following temperature sensors are + * compatible with the TMP105 registers: + * - adt75 + * - ds1775 + * - ds75 + * - lm75 + * - lm75a + * - max6625 + * - max6626 + * - mcp980x + * - stds75 + * - tcn75 + * - tmp100 + * - tmp101 + * - tmp105 + * - tmp175 + * - tmp275 + * - tmp75 + **/ +typedef enum TMP105Reg { + TMP105_REG_TEMPERATURE = 0, + TMP105_REG_CONFIG, + TMP105_REG_T_LOW, + TMP105_REG_T_HIGH, +} TMP105Reg; + +/** + * tmp105_set: + * @i2c: dispatcher to TMP105 hardware model + * @temp: temperature with 0.001 centigrades units in the range -40 C to +125 C + * + * Sets the temperature of the TMP105 hardware model. + * + * Bits 5 and 6 (value 32 and 64) in the register indexed by TMP105_REG_CONFIG + * determine the precision of the temperature. See Table 8 in the data sheet. + * + * @see_also: I2C_SLAVE macro + * @see_also: http://www.ti.com/lit/gpn/tmp105 + */ +void tmp105_set(I2CSlave *i2c, int temp); + +#endif @@ -17,13 +17,13 @@ #include "devices.h" #include "sharpsl.h" #include "pcmcia.h" -#include "block.h" +#include "block/block.h" #include "boards.h" #include "i2c.h" #include "ssi.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "sysbus.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #define TOSA_RAM 0x04000000 #define TOSA_ROM 0x00800000 @@ -205,11 +205,12 @@ static struct arm_boot_info tosa_binfo = { .ram_size = 0x04000000, }; -static void tosa_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void tosa_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *rom = g_new(MemoryRegion, 1); PXA2xxState *mpu; diff --git a/hw/tsc2005.c b/hw/tsc2005.c index 9a500ebb3d..740ff86aa8 100644 --- a/hw/tsc2005.c +++ b/hw/tsc2005.c @@ -19,8 +19,8 @@ */ #include "hw.h" -#include "qemu-timer.h" -#include "console.h" +#include "qemu/timer.h" +#include "ui/console.h" #include "devices.h" #define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - (p ? 12 : 10))) diff --git a/hw/tsc210x.c b/hw/tsc210x.c index 3c448a6f0f..2076c355d2 100644 --- a/hw/tsc210x.c +++ b/hw/tsc210x.c @@ -21,8 +21,8 @@ #include "hw.h" #include "audio/audio.h" -#include "qemu-timer.h" -#include "console.h" +#include "qemu/timer.h" +#include "ui/console.h" #include "omap.h" /* For I2SCodec and uWireSlave */ #include "devices.h" diff --git a/hw/tusb6010.c b/hw/tusb6010.c index 5ba8da6d6a..990d50619d 100644 --- a/hw/tusb6010.c +++ b/hw/tusb6010.c @@ -19,7 +19,7 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "qemu-common.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "usb.h" #include "omap.h" #include "irq.h" @@ -281,7 +281,7 @@ static void tusb_gpio_intr_update(TUSBState *s) extern CPUReadMemoryFunc * const musb_read[]; extern CPUWriteMemoryFunc * const musb_write[]; -static uint32_t tusb_async_readb(void *opaque, target_phys_addr_t addr) +static uint32_t tusb_async_readb(void *opaque, hwaddr addr) { TUSBState *s = (TUSBState *) opaque; @@ -298,7 +298,7 @@ static uint32_t tusb_async_readb(void *opaque, target_phys_addr_t addr) return 0; } -static uint32_t tusb_async_readh(void *opaque, target_phys_addr_t addr) +static uint32_t tusb_async_readh(void *opaque, hwaddr addr) { TUSBState *s = (TUSBState *) opaque; @@ -315,7 +315,7 @@ static uint32_t tusb_async_readh(void *opaque, target_phys_addr_t addr) return 0; } -static uint32_t tusb_async_readw(void *opaque, target_phys_addr_t addr) +static uint32_t tusb_async_readw(void *opaque, hwaddr addr) { TUSBState *s = (TUSBState *) opaque; int offset = addr & 0xfff; @@ -438,7 +438,7 @@ static uint32_t tusb_async_readw(void *opaque, target_phys_addr_t addr) return 0; } -static void tusb_async_writeb(void *opaque, target_phys_addr_t addr, +static void tusb_async_writeb(void *opaque, hwaddr addr, uint32_t value) { TUSBState *s = (TUSBState *) opaque; @@ -459,7 +459,7 @@ static void tusb_async_writeb(void *opaque, target_phys_addr_t addr, } } -static void tusb_async_writeh(void *opaque, target_phys_addr_t addr, +static void tusb_async_writeh(void *opaque, hwaddr addr, uint32_t value) { TUSBState *s = (TUSBState *) opaque; @@ -480,7 +480,7 @@ static void tusb_async_writeh(void *opaque, target_phys_addr_t addr, } } -static void tusb_async_writew(void *opaque, target_phys_addr_t addr, +static void tusb_async_writew(void *opaque, hwaddr addr, uint32_t value) { TUSBState *s = (TUSBState *) opaque; diff --git a/hw/twl92230.c b/hw/twl92230.c index 0d70d8498d..c71e4a2af0 100644 --- a/hw/twl92230.c +++ b/hw/twl92230.c @@ -20,10 +20,10 @@ */ #include "hw.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "i2c.h" -#include "sysemu.h" -#include "console.h" +#include "sysemu/sysemu.h" +#include "ui/console.h" #define VERBOSE 1 diff --git a/hw/uboot_image.h b/hw/uboot_image.h new file mode 100644 index 0000000000..9fc2760b53 --- /dev/null +++ b/hw/uboot_image.h @@ -0,0 +1,158 @@ +/* + * (C) Copyright 2000-2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************** + * NOTE: This header file defines an interface to U-Boot. Including + * this (unmodified) header file in another file is considered normal + * use of U-Boot, and does *not* fall under the heading of "derived + * work". + ******************************************************************** + */ + +#ifndef __UBOOT_IMAGE_H__ +#define __UBOOT_IMAGE_H__ + +/* + * Operating System Codes + */ +#define IH_OS_INVALID 0 /* Invalid OS */ +#define IH_OS_OPENBSD 1 /* OpenBSD */ +#define IH_OS_NETBSD 2 /* NetBSD */ +#define IH_OS_FREEBSD 3 /* FreeBSD */ +#define IH_OS_4_4BSD 4 /* 4.4BSD */ +#define IH_OS_LINUX 5 /* Linux */ +#define IH_OS_SVR4 6 /* SVR4 */ +#define IH_OS_ESIX 7 /* Esix */ +#define IH_OS_SOLARIS 8 /* Solaris */ +#define IH_OS_IRIX 9 /* Irix */ +#define IH_OS_SCO 10 /* SCO */ +#define IH_OS_DELL 11 /* Dell */ +#define IH_OS_NCR 12 /* NCR */ +#define IH_OS_LYNXOS 13 /* LynxOS */ +#define IH_OS_VXWORKS 14 /* VxWorks */ +#define IH_OS_PSOS 15 /* pSOS */ +#define IH_OS_QNX 16 /* QNX */ +#define IH_OS_U_BOOT 17 /* Firmware */ +#define IH_OS_RTEMS 18 /* RTEMS */ +#define IH_OS_ARTOS 19 /* ARTOS */ +#define IH_OS_UNITY 20 /* Unity OS */ + +/* + * CPU Architecture Codes (supported by Linux) + */ +#define IH_CPU_INVALID 0 /* Invalid CPU */ +#define IH_CPU_ALPHA 1 /* Alpha */ +#define IH_CPU_ARM 2 /* ARM */ +#define IH_CPU_I386 3 /* Intel x86 */ +#define IH_CPU_IA64 4 /* IA64 */ +#define IH_CPU_MIPS 5 /* MIPS */ +#define IH_CPU_MIPS64 6 /* MIPS 64 Bit */ +#define IH_CPU_PPC 7 /* PowerPC */ +#define IH_CPU_S390 8 /* IBM S390 */ +#define IH_CPU_SH 9 /* SuperH */ +#define IH_CPU_SPARC 10 /* Sparc */ +#define IH_CPU_SPARC64 11 /* Sparc 64 Bit */ +#define IH_CPU_M68K 12 /* M68K */ +#define IH_CPU_NIOS 13 /* Nios-32 */ +#define IH_CPU_MICROBLAZE 14 /* MicroBlaze */ +#define IH_CPU_NIOS2 15 /* Nios-II */ +#define IH_CPU_BLACKFIN 16 /* Blackfin */ +#define IH_CPU_AVR32 17 /* AVR32 */ + +/* + * Image Types + * + * "Standalone Programs" are directly runnable in the environment + * provided by U-Boot; it is expected that (if they behave + * well) you can continue to work in U-Boot after return from + * the Standalone Program. + * "OS Kernel Images" are usually images of some Embedded OS which + * will take over control completely. Usually these programs + * will install their own set of exception handlers, device + * drivers, set up the MMU, etc. - this means, that you cannot + * expect to re-enter U-Boot except by resetting the CPU. + * "RAMDisk Images" are more or less just data blocks, and their + * parameters (address, size) are passed to an OS kernel that is + * being started. + * "Multi-File Images" contain several images, typically an OS + * (Linux) kernel image and one or more data images like + * RAMDisks. This construct is useful for instance when you want + * to boot over the network using BOOTP etc., where the boot + * server provides just a single image file, but you want to get + * for instance an OS kernel and a RAMDisk image. + * + * "Multi-File Images" start with a list of image sizes, each + * image size (in bytes) specified by an "uint32_t" in network + * byte order. This list is terminated by an "(uint32_t)0". + * Immediately after the terminating 0 follow the images, one by + * one, all aligned on "uint32_t" boundaries (size rounded up to + * a multiple of 4 bytes - except for the last file). + * + * "Firmware Images" are binary images containing firmware (like + * U-Boot or FPGA images) which usually will be programmed to + * flash memory. + * + * "Script files" are command sequences that will be executed by + * U-Boot's command interpreter; this feature is especially + * useful when you configure U-Boot to use a real shell (hush) + * as command interpreter (=> Shell Scripts). + */ + +#define IH_TYPE_INVALID 0 /* Invalid Image */ +#define IH_TYPE_STANDALONE 1 /* Standalone Program */ +#define IH_TYPE_KERNEL 2 /* OS Kernel Image */ +#define IH_TYPE_RAMDISK 3 /* RAMDisk Image */ +#define IH_TYPE_MULTI 4 /* Multi-File Image */ +#define IH_TYPE_FIRMWARE 5 /* Firmware Image */ +#define IH_TYPE_SCRIPT 6 /* Script file */ +#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */ +#define IH_TYPE_FLATDT 8 /* Binary Flat Device Tree Blob */ + +/* + * Compression Types + */ +#define IH_COMP_NONE 0 /* No Compression Used */ +#define IH_COMP_GZIP 1 /* gzip Compression Used */ +#define IH_COMP_BZIP2 2 /* bzip2 Compression Used */ + +#define IH_MAGIC 0x27051956 /* Image Magic Number */ +#define IH_NMLEN 32 /* Image Name Length */ + +/* + * all data in network byte order (aka natural aka bigendian) + */ + +typedef struct uboot_image_header { + uint32_t ih_magic; /* Image Header Magic Number */ + uint32_t ih_hcrc; /* Image Header CRC Checksum */ + uint32_t ih_time; /* Image Creation Timestamp */ + uint32_t ih_size; /* Image Data Size */ + uint32_t ih_load; /* Data Load Address */ + uint32_t ih_ep; /* Entry Point Address */ + uint32_t ih_dcrc; /* Image Data CRC Checksum */ + uint8_t ih_os; /* Operating System */ + uint8_t ih_arch; /* CPU architecture */ + uint8_t ih_type; /* Image Type */ + uint8_t ih_comp; /* Compression Type */ + uint8_t ih_name[IH_NMLEN]; /* Image Name */ +} uboot_image_header_t; + + +#endif /* __IMAGE_H__ */ diff --git a/hw/unin_pci.c b/hw/unin_pci.c index 409bcd4cc6..46757924b6 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -23,8 +23,8 @@ */ #include "hw.h" #include "ppc_mac.h" -#include "pci.h" -#include "pci_host.h" +#include "pci/pci.h" +#include "pci/pci_host.h" /* debug UniNorth */ //#define DEBUG_UNIN @@ -38,8 +38,23 @@ static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e }; +#define TYPE_UNI_NORTH_PCI_HOST_BRIDGE "uni-north-pci-pcihost" +#define TYPE_UNI_NORTH_AGP_HOST_BRIDGE "uni-north-agp-pcihost" +#define TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE "uni-north-internal-pci-pcihost" +#define TYPE_U3_AGP_HOST_BRIDGE "u3-agp-pcihost" + +#define UNI_NORTH_PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_PCI_HOST_BRIDGE) +#define UNI_NORTH_AGP_HOST_BRIDGE(obj) \ + OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_AGP_HOST_BRIDGE) +#define UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE(obj) \ + OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE) +#define U3_AGP_HOST_BRIDGE(obj) \ + OBJECT_CHECK(UNINState, (obj), TYPE_U3_AGP_HOST_BRIDGE) + typedef struct UNINState { - PCIHostState host_state; + PCIHostState parent_obj; + MemoryRegion pci_mmio; MemoryRegion pci_hole; } UNINState; @@ -96,25 +111,27 @@ static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr) return retval; } -static void unin_data_write(void *opaque, target_phys_addr_t addr, +static void unin_data_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) { UNINState *s = opaque; + PCIHostState *phb = PCI_HOST_BRIDGE(s); UNIN_DPRINTF("write addr %" TARGET_FMT_plx " len %d val %"PRIx64"\n", addr, len, val); - pci_data_write(s->host_state.bus, - unin_get_config_reg(s->host_state.config_reg, addr), + pci_data_write(phb->bus, + unin_get_config_reg(phb->config_reg, addr), val, len); } -static uint64_t unin_data_read(void *opaque, target_phys_addr_t addr, +static uint64_t unin_data_read(void *opaque, hwaddr addr, unsigned len) { UNINState *s = opaque; + PCIHostState *phb = PCI_HOST_BRIDGE(s); uint32_t val; - val = pci_data_read(s->host_state.bus, - unin_get_config_reg(s->host_state.config_reg, addr), + val = pci_data_read(phb->bus, + unin_get_config_reg(phb->config_reg, addr), len); UNIN_DPRINTF("read addr %" TARGET_FMT_plx " len %d val %x\n", addr, len, val); @@ -130,19 +147,17 @@ static const MemoryRegionOps unin_data_ops = { static int pci_unin_main_init_device(SysBusDevice *dev) { PCIHostState *h; - UNINState *s; /* Use values found on a real PowerMac */ /* Uninorth main bus */ - h = FROM_SYSBUS(PCIHostState, dev); - s = DO_UPCAST(UNINState, host_state, h); + h = PCI_HOST_BRIDGE(dev); - memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops, - &s->host_state, "pci-conf-idx", 0x1000); - memory_region_init_io(&s->host_state.data_mem, &unin_data_ops, s, + memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops, + dev, "pci-conf-idx", 0x1000); + memory_region_init_io(&h->data_mem, &unin_data_ops, dev, "pci-conf-data", 0x1000); - sysbus_init_mmio(dev, &s->host_state.conf_mem); - sysbus_init_mmio(dev, &s->host_state.data_mem); + sysbus_init_mmio(dev, &h->conf_mem); + sysbus_init_mmio(dev, &h->data_mem); return 0; } @@ -151,18 +166,16 @@ static int pci_unin_main_init_device(SysBusDevice *dev) static int pci_u3_agp_init_device(SysBusDevice *dev) { PCIHostState *h; - UNINState *s; /* Uninorth U3 AGP bus */ - h = FROM_SYSBUS(PCIHostState, dev); - s = DO_UPCAST(UNINState, host_state, h); + h = PCI_HOST_BRIDGE(dev); - memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops, - &s->host_state, "pci-conf-idx", 0x1000); - memory_region_init_io(&s->host_state.data_mem, &unin_data_ops, s, + memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops, + dev, "pci-conf-idx", 0x1000); + memory_region_init_io(&h->data_mem, &unin_data_ops, dev, "pci-conf-data", 0x1000); - sysbus_init_mmio(dev, &s->host_state.conf_mem); - sysbus_init_mmio(dev, &s->host_state.data_mem); + sysbus_init_mmio(dev, &h->conf_mem); + sysbus_init_mmio(dev, &h->data_mem); return 0; } @@ -170,36 +183,32 @@ static int pci_u3_agp_init_device(SysBusDevice *dev) static int pci_unin_agp_init_device(SysBusDevice *dev) { PCIHostState *h; - UNINState *s; /* Uninorth AGP bus */ - h = FROM_SYSBUS(PCIHostState, dev); - s = DO_UPCAST(UNINState, host_state, h); - - memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops, - &s->host_state, "pci-conf-idx", 0x1000); - memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops, - &s->host_state, "pci-conf-data", 0x1000); - sysbus_init_mmio(dev, &s->host_state.conf_mem); - sysbus_init_mmio(dev, &s->host_state.data_mem); + h = PCI_HOST_BRIDGE(dev); + + memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops, + dev, "pci-conf-idx", 0x1000); + memory_region_init_io(&h->data_mem, &pci_host_data_le_ops, + dev, "pci-conf-data", 0x1000); + sysbus_init_mmio(dev, &h->conf_mem); + sysbus_init_mmio(dev, &h->data_mem); return 0; } static int pci_unin_internal_init_device(SysBusDevice *dev) { PCIHostState *h; - UNINState *s; /* Uninorth internal bus */ - h = FROM_SYSBUS(PCIHostState, dev); - s = DO_UPCAST(UNINState, host_state, h); - - memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops, - &s->host_state, "pci-conf-idx", 0x1000); - memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops, - &s->host_state, "pci-conf-data", 0x1000); - sysbus_init_mmio(dev, &s->host_state.conf_mem); - sysbus_init_mmio(dev, &s->host_state.data_mem); + h = PCI_HOST_BRIDGE(dev); + + memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops, + dev, "pci-conf-idx", 0x1000); + memory_region_init_io(&h->data_mem, &pci_host_data_le_ops, + dev, "pci-conf-data", 0x1000); + sysbus_init_mmio(dev, &h->conf_mem); + sysbus_init_mmio(dev, &h->data_mem); return 0; } @@ -214,26 +223,26 @@ PCIBus *pci_pmac_init(qemu_irq *pic, /* Use values found on a real PowerMac */ /* Uninorth main bus */ - dev = qdev_create(NULL, "uni-north-pci-pcihost"); + dev = qdev_create(NULL, TYPE_UNI_NORTH_PCI_HOST_BRIDGE); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); - h = FROM_SYSBUS(PCIHostState, s); - d = DO_UPCAST(UNINState, host_state, h); + s = SYS_BUS_DEVICE(dev); + h = PCI_HOST_BRIDGE(s); + d = UNI_NORTH_PCI_HOST_BRIDGE(dev); memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL); memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio, 0x80000000ULL, 0x70000000ULL); memory_region_add_subregion(address_space_mem, 0x80000000ULL, &d->pci_hole); - d->host_state.bus = pci_register_bus(dev, "pci", - pci_unin_set_irq, pci_unin_map_irq, - pic, - &d->pci_mmio, - address_space_io, - PCI_DEVFN(11, 0), 4); + h->bus = pci_register_bus(dev, "pci", + pci_unin_set_irq, pci_unin_map_irq, + pic, + &d->pci_mmio, + address_space_io, + PCI_DEVFN(11, 0), 4); #if 0 - pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north"); + pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north"); #endif sysbus_mmio_map(s, 0, 0xf2800000); @@ -242,30 +251,30 @@ PCIBus *pci_pmac_init(qemu_irq *pic, /* DEC 21154 bridge */ #if 0 /* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */ - pci_create_simple(d->host_state.bus, PCI_DEVFN(12, 0), "dec-21154"); + pci_create_simple(h->bus, PCI_DEVFN(12, 0), "dec-21154"); #endif /* Uninorth AGP bus */ - pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north-agp"); - dev = qdev_create(NULL, "uni-north-agp-pcihost"); + pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north-agp"); + dev = qdev_create(NULL, TYPE_UNI_NORTH_AGP_HOST_BRIDGE); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, 0xf0800000); sysbus_mmio_map(s, 1, 0xf0c00000); /* Uninorth internal bus */ #if 0 /* XXX: not needed for now */ - pci_create_simple(d->host_state.bus, PCI_DEVFN(14, 0), + pci_create_simple(h->bus, PCI_DEVFN(14, 0), "uni-north-internal-pci"); - dev = qdev_create(NULL, "uni-north-internal-pci-pcihost"); + dev = qdev_create(NULL, TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, 0xf4800000); sysbus_mmio_map(s, 1, 0xf4c00000); #endif - return d->host_state.bus; + return h->bus; } PCIBus *pci_pmac_u3_init(qemu_irq *pic, @@ -279,11 +288,11 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic, /* Uninorth AGP bus */ - dev = qdev_create(NULL, "u3-agp-pcihost"); + dev = qdev_create(NULL, TYPE_U3_AGP_HOST_BRIDGE); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); - h = FROM_SYSBUS(PCIHostState, s); - d = DO_UPCAST(UNINState, host_state, h); + s = SYS_BUS_DEVICE(dev); + h = PCI_HOST_BRIDGE(dev); + d = U3_AGP_HOST_BRIDGE(dev); memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL); memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio, @@ -291,19 +300,19 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic, memory_region_add_subregion(address_space_mem, 0x80000000ULL, &d->pci_hole); - d->host_state.bus = pci_register_bus(dev, "pci", - pci_unin_set_irq, pci_unin_map_irq, - pic, - &d->pci_mmio, - address_space_io, - PCI_DEVFN(11, 0), 4); + h->bus = pci_register_bus(dev, "pci", + pci_unin_set_irq, pci_unin_map_irq, + pic, + &d->pci_mmio, + address_space_io, + PCI_DEVFN(11, 0), 4); sysbus_mmio_map(s, 0, 0xf0800000); sysbus_mmio_map(s, 1, 0xf0c00000); - pci_create_simple(d->host_state.bus, 11 << 3, "u3-agp"); + pci_create_simple(h->bus, 11 << 3, "u3-agp"); - return d->host_state.bus; + return h->bus; } static int unin_main_pci_host_init(PCIDevice *d) @@ -350,7 +359,7 @@ static void unin_main_pci_host_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_HOST; } -static TypeInfo unin_main_pci_host_info = { +static const TypeInfo unin_main_pci_host_info = { .name = "uni-north-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), @@ -368,7 +377,7 @@ static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_HOST; } -static TypeInfo u3_agp_pci_host_info = { +static const TypeInfo u3_agp_pci_host_info = { .name = "u3-agp", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), @@ -386,7 +395,7 @@ static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_HOST; } -static TypeInfo unin_agp_pci_host_info = { +static const TypeInfo unin_agp_pci_host_info = { .name = "uni-north-agp", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), @@ -404,7 +413,7 @@ static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_HOST; } -static TypeInfo unin_internal_pci_host_info = { +static const TypeInfo unin_internal_pci_host_info = { .name = "uni-north-internal-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), @@ -418,9 +427,9 @@ static void pci_unin_main_class_init(ObjectClass *klass, void *data) sbc->init = pci_unin_main_init_device; } -static TypeInfo pci_unin_main_info = { - .name = "uni-north-pci-pcihost", - .parent = TYPE_SYS_BUS_DEVICE, +static const TypeInfo pci_unin_main_info = { + .name = TYPE_UNI_NORTH_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(UNINState), .class_init = pci_unin_main_class_init, }; @@ -432,9 +441,9 @@ static void pci_u3_agp_class_init(ObjectClass *klass, void *data) sbc->init = pci_u3_agp_init_device; } -static TypeInfo pci_u3_agp_info = { - .name = "u3-agp-pcihost", - .parent = TYPE_SYS_BUS_DEVICE, +static const TypeInfo pci_u3_agp_info = { + .name = TYPE_U3_AGP_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(UNINState), .class_init = pci_u3_agp_class_init, }; @@ -446,9 +455,9 @@ static void pci_unin_agp_class_init(ObjectClass *klass, void *data) sbc->init = pci_unin_agp_init_device; } -static TypeInfo pci_unin_agp_info = { - .name = "uni-north-agp-pcihost", - .parent = TYPE_SYS_BUS_DEVICE, +static const TypeInfo pci_unin_agp_info = { + .name = TYPE_UNI_NORTH_AGP_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(UNINState), .class_init = pci_unin_agp_class_init, }; @@ -460,9 +469,9 @@ static void pci_unin_internal_class_init(ObjectClass *klass, void *data) sbc->init = pci_unin_internal_init_device; } -static TypeInfo pci_unin_internal_info = { - .name = "uni-north-internal-pci-pcihost", - .parent = TYPE_SYS_BUS_DEVICE, +static const TypeInfo pci_unin_internal_info = { + .name = TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(UNINState), .class_init = pci_unin_internal_class_init, }; @@ -26,7 +26,7 @@ */ #include "qdev.h" -#include "qemu-queue.h" +#include "qemu/queue.h" /* Constants related to the USB / PCI interaction */ #define USB_SBRN 0x60 /* Serial Bus Release Number Register */ @@ -38,12 +38,15 @@ #define USB_TOKEN_IN 0x69 /* device -> host */ #define USB_TOKEN_OUT 0xe1 /* host -> device */ -#define USB_RET_NODEV (-1) -#define USB_RET_NAK (-2) -#define USB_RET_STALL (-3) -#define USB_RET_BABBLE (-4) -#define USB_RET_IOERROR (-5) -#define USB_RET_ASYNC (-6) +#define USB_RET_SUCCESS (0) +#define USB_RET_NODEV (-1) +#define USB_RET_NAK (-2) +#define USB_RET_STALL (-3) +#define USB_RET_BABBLE (-4) +#define USB_RET_IOERROR (-5) +#define USB_RET_ASYNC (-6) +#define USB_RET_ADD_TO_QUEUE (-7) +#define USB_RET_REMOVE_FROM_QUEUE (-8) #define USB_SPEED_LOW 0 #define USB_SPEED_FULL 1 @@ -135,8 +138,15 @@ #define USB_DT_OTHER_SPEED_CONFIG 0x07 #define USB_DT_DEBUG 0x0A #define USB_DT_INTERFACE_ASSOC 0x0B +#define USB_DT_BOS 0x0F +#define USB_DT_DEVICE_CAPABILITY 0x10 #define USB_DT_CS_INTERFACE 0x24 #define USB_DT_CS_ENDPOINT 0x25 +#define USB_DT_ENDPOINT_COMPANION 0x30 + +#define USB_DEV_CAP_WIRELESS 0x01 +#define USB_DEV_CAP_USB2_EXT 0x02 +#define USB_DEV_CAP_SUPERSPEED 0x03 #define USB_ENDPOINT_XFER_CONTROL 0 #define USB_ENDPOINT_XFER_ISOC 1 @@ -151,6 +161,7 @@ typedef struct USBBusOps USBBusOps; typedef struct USBPort USBPort; typedef struct USBDevice USBDevice; typedef struct USBPacket USBPacket; +typedef struct USBCombinedPacket USBCombinedPacket; typedef struct USBEndpoint USBEndpoint; typedef struct USBDesc USBDesc; @@ -179,12 +190,14 @@ struct USBEndpoint { uint8_t ifnum; int max_packet_size; bool pipeline; + bool halted; USBDevice *dev; QTAILQ_HEAD(, USBPacket) queue; }; enum USBDeviceFlags { USB_DEV_FLAG_FULL_PATH, + USB_DEV_FLAG_IS_HOST, }; /* definition of a USB device */ @@ -217,6 +230,7 @@ struct USBDevice { USBEndpoint ep_out[USB_MAX_ENDPOINTS]; QLIST_HEAD(, USBDescString) strings; + const USBDesc *usb_desc; /* Overrides class usb_desc if not NULL */ const USBDescDevice *device; int configuration; @@ -269,22 +283,36 @@ typedef struct USBDeviceClass { * Process control request. * Called from handle_packet(). * - * Returns length or one of the USB_RET_ codes. + * Status gets stored in p->status, and if p->status == USB_RET_SUCCESS + * then the number of bytes transferred is stored in p->actual_length */ - int (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value, - int index, int length, uint8_t *data); + void (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value, + int index, int length, uint8_t *data); /* * Process data transfers (both BULK and ISOC). * Called from handle_packet(). * - * Returns length or one of the USB_RET_ codes. + * Status gets stored in p->status, and if p->status == USB_RET_SUCCESS + * then the number of bytes transferred is stored in p->actual_length */ - int (*handle_data)(USBDevice *dev, USBPacket *p); + void (*handle_data)(USBDevice *dev, USBPacket *p); void (*set_interface)(USBDevice *dev, int interface, int alt_old, int alt_new); + /* + * Called when the hcd is done queuing packets for an endpoint, only + * necessary for devices which can return USB_RET_ADD_TO_QUEUE. + */ + void (*flush_ep_queue)(USBDevice *dev, USBEndpoint *ep); + + /* + * Called by the hcd to let the device know the queue for an endpoint + * has been unlinked / stopped. Optional may be NULL. + */ + void (*ep_stopped)(USBDevice *dev, USBEndpoint *ep); + const char *product_desc; const USBDesc *usb_desc; } USBDeviceClass; @@ -331,19 +359,32 @@ typedef enum USBPacketState { struct USBPacket { /* Data fields for use by the driver. */ int pid; + uint64_t id; USBEndpoint *ep; QEMUIOVector iov; uint64_t parameter; /* control transfers */ - int result; /* transfer length or USB_RET_* status code */ + bool short_not_ok; + bool int_req; + int status; /* USB_RET_* status code */ + int actual_length; /* Number of bytes actually transferred */ /* Internal use by the USB layer. */ USBPacketState state; + USBCombinedPacket *combined; QTAILQ_ENTRY(USBPacket) queue; + QTAILQ_ENTRY(USBPacket) combined_entry; +}; + +struct USBCombinedPacket { + USBPacket *first; + QTAILQ_HEAD(packets_head, USBPacket) packets; + QEMUIOVector iov; }; void usb_packet_init(USBPacket *p); void usb_packet_set_state(USBPacket *p, USBPacketState state); void usb_packet_check_state(USBPacket *p, USBPacketState expected); -void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep); +void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id, + bool short_not_ok, bool int_req); void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len); int usb_packet_map(USBPacket *p, QEMUSGList *sgl); void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl); @@ -359,8 +400,9 @@ static inline bool usb_packet_is_inflight(USBPacket *p) USBDevice *usb_find_device(USBPort *port, uint8_t addr); -int usb_handle_packet(USBDevice *dev, USBPacket *p); +void usb_handle_packet(USBDevice *dev, USBPacket *p); void usb_packet_complete(USBDevice *dev, USBPacket *p); +void usb_packet_complete_one(USBDevice *dev, USBPacket *p); void usb_cancel_packet(USBPacket * p); void usb_ep_init(USBDevice *dev); @@ -375,6 +417,12 @@ void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep, uint16_t raw); int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep); void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled); +USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep, + uint64_t id); + +void usb_ep_combine_input_packets(USBEndpoint *ep); +void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p); +void usb_combined_packet_cancel(USBDevice *dev, USBPacket *p); void usb_attach(USBPort *port); void usb_detach(USBPort *port); @@ -487,17 +535,33 @@ void usb_device_handle_attach(USBDevice *dev); void usb_device_handle_reset(USBDevice *dev); -int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, int value, - int index, int length, uint8_t *data); +void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, + int val, int index, int length, uint8_t *data); -int usb_device_handle_data(USBDevice *dev, USBPacket *p); +void usb_device_handle_data(USBDevice *dev, USBPacket *p); void usb_device_set_interface(USBDevice *dev, int interface, int alt_old, int alt_new); +void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep); + +void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep); + const char *usb_device_get_product_desc(USBDevice *dev); const USBDesc *usb_device_get_usb_desc(USBDevice *dev); -#endif +int ehci_create_ich9_with_companions(PCIBus *bus, int slot); +/* quirks.c */ + +/* In bulk endpoints are streaming data sources (iow behave like isoc eps) */ +#define USB_QUIRK_BUFFER_BULK_IN 0x01 +/* Bulk pkts in FTDI format, need special handling when combining packets */ +#define USB_QUIRK_IS_FTDI 0x02 + +int usb_get_quirks(uint16_t vendor_id, uint16_t product_id, + uint8_t interface_class, uint8_t interface_subclass, + uint8_t interface_protocol); + +#endif diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index 4225136d0f..dad4cb9f3c 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -1,13 +1,13 @@ -hw-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o -hw-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o -hw-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o -hw-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o -hw-obj-y += libhw.o +common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o +common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o +common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o hcd-ehci-sysbus.o +common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o +common-obj-y += libhw.o -hw-obj-$(CONFIG_SMARTCARD) += dev-smartcard-reader.o -hw-obj-$(CONFIG_USB_REDIR) += redirect.o +common-obj-$(CONFIG_SMARTCARD) += dev-smartcard-reader.o +common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o -common-obj-y += core.o bus.o desc.o dev-hub.o +common-obj-y += core.o combined-packet.o bus.o desc.o dev-hub.o common-obj-y += host-$(HOST_USB).o dev-bluetooth.o common-obj-y += dev-hid.o dev-storage.o dev-wacom.o common-obj-y += dev-serial.o dev-network.o dev-audio.o diff --git a/hw/usb/bus.c b/hw/usb/bus.c index b649360dd3..180d1d739b 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -1,8 +1,8 @@ #include "hw/hw.h" #include "hw/usb.h" #include "hw/qdev.h" -#include "sysemu.h" -#include "monitor.h" +#include "sysemu/sysemu.h" +#include "monitor/monitor.h" #include "trace.h" static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent); @@ -140,24 +140,21 @@ void usb_device_handle_reset(USBDevice *dev) } } -int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, - int value, int index, int length, uint8_t *data) +void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, + int value, int index, int length, uint8_t *data) { USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); if (klass->handle_control) { - return klass->handle_control(dev, p, request, value, index, length, - data); + klass->handle_control(dev, p, request, value, index, length, data); } - return -ENOSYS; } -int usb_device_handle_data(USBDevice *dev, USBPacket *p) +void usb_device_handle_data(USBDevice *dev, USBPacket *p) { USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); if (klass->handle_data) { - return klass->handle_data(dev, p); + klass->handle_data(dev, p); } - return -ENOSYS; } const char *usb_device_get_product_desc(USBDevice *dev) @@ -169,6 +166,9 @@ const char *usb_device_get_product_desc(USBDevice *dev) const USBDesc *usb_device_get_usb_desc(USBDevice *dev) { USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (dev->usb_desc) { + return dev->usb_desc; + } return klass->usb_desc; } @@ -181,6 +181,22 @@ void usb_device_set_interface(USBDevice *dev, int interface, } } +void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (klass->flush_ep_queue) { + klass->flush_ep_queue(dev, ep); + } +} + +void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (klass->ep_stopped) { + klass->ep_stopped(dev, ep); + } +} + static int usb_qdev_init(DeviceState *qdev) { USBDevice *dev = USB_DEVICE(qdev); @@ -585,6 +601,13 @@ USBDevice *usbdevice_create(const char *cmdline) return NULL; } + if (!bus) { + error_report("Error: no usb bus to attach usbdevice %s, " + "please try -machine usb=on and check that " + "the machine model supports USB", driver); + return NULL; + } + if (!f->usbdevice_init) { if (*params) { error_report("usbdevice %s accepts no params", driver); diff --git a/hw/usb/combined-packet.c b/hw/usb/combined-packet.c new file mode 100644 index 0000000000..13f6602ad2 --- /dev/null +++ b/hw/usb/combined-packet.c @@ -0,0 +1,186 @@ +/* + * QEMU USB packet combining code (for input pipelining) + * + * Copyright(c) 2012 Red Hat, Inc. + * + * Red Hat Authors: + * Hans de Goede <hdegoede@redhat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or(at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ +#include "qemu-common.h" +#include "hw/usb.h" +#include "qemu/iov.h" +#include "trace.h" + +static void usb_combined_packet_add(USBCombinedPacket *combined, USBPacket *p) +{ + qemu_iovec_concat(&combined->iov, &p->iov, 0, p->iov.size); + QTAILQ_INSERT_TAIL(&combined->packets, p, combined_entry); + p->combined = combined; +} + +/* Note will free combined when the last packet gets removed */ +static void usb_combined_packet_remove(USBCombinedPacket *combined, + USBPacket *p) +{ + assert(p->combined == combined); + p->combined = NULL; + QTAILQ_REMOVE(&combined->packets, p, combined_entry); + if (QTAILQ_EMPTY(&combined->packets)) { + g_free(combined); + } +} + +/* Also handles completion of non combined packets for pipelined input eps */ +void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p) +{ + USBCombinedPacket *combined = p->combined; + USBEndpoint *ep = p->ep; + USBPacket *next; + int status, actual_length; + bool short_not_ok, done = false; + + if (combined == NULL) { + usb_packet_complete_one(dev, p); + goto leave; + } + + assert(combined->first == p && p == QTAILQ_FIRST(&combined->packets)); + + status = combined->first->status; + actual_length = combined->first->actual_length; + short_not_ok = QTAILQ_LAST(&combined->packets, packets_head)->short_not_ok; + + QTAILQ_FOREACH_SAFE(p, &combined->packets, combined_entry, next) { + if (!done) { + /* Distribute data over uncombined packets */ + if (actual_length >= p->iov.size) { + p->actual_length = p->iov.size; + } else { + /* Send short or error packet to complete the transfer */ + p->actual_length = actual_length; + done = true; + } + /* Report status on the last packet */ + if (done || next == NULL) { + p->status = status; + } else { + p->status = USB_RET_SUCCESS; + } + p->short_not_ok = short_not_ok; + /* Note will free combined when the last packet gets removed! */ + usb_combined_packet_remove(combined, p); + usb_packet_complete_one(dev, p); + actual_length -= p->actual_length; + } else { + /* Remove any leftover packets from the queue */ + p->status = USB_RET_REMOVE_FROM_QUEUE; + /* Note will free combined on the last packet! */ + dev->port->ops->complete(dev->port, p); + } + } + /* Do not use combined here, it has been freed! */ +leave: + /* Check if there are packets in the queue waiting for our completion */ + usb_ep_combine_input_packets(ep); +} + +/* May only be called for combined packets! */ +void usb_combined_packet_cancel(USBDevice *dev, USBPacket *p) +{ + USBCombinedPacket *combined = p->combined; + assert(combined != NULL); + USBPacket *first = p->combined->first; + + /* Note will free combined on the last packet! */ + usb_combined_packet_remove(combined, p); + if (p == first) { + usb_device_cancel_packet(dev, p); + } +} + +/* + * Large input transfers can get split into multiple input packets, this + * function recombines them, removing the short_not_ok checks which all but + * the last packet of such splits transfers have, thereby allowing input + * transfer pipelining (which we cannot do on short_not_ok transfers) + */ +void usb_ep_combine_input_packets(USBEndpoint *ep) +{ + USBPacket *p, *u, *next, *prev = NULL, *first = NULL; + USBPort *port = ep->dev->port; + int totalsize; + + assert(ep->pipeline); + assert(ep->pid == USB_TOKEN_IN); + + QTAILQ_FOREACH_SAFE(p, &ep->queue, queue, next) { + /* Empty the queue on a halt */ + if (ep->halted) { + p->status = USB_RET_REMOVE_FROM_QUEUE; + port->ops->complete(port, p); + continue; + } + + /* Skip packets already submitted to the device */ + if (p->state == USB_PACKET_ASYNC) { + prev = p; + continue; + } + usb_packet_check_state(p, USB_PACKET_QUEUED); + + /* + * If the previous (combined) packet has the short_not_ok flag set + * stop, as we must not submit packets to the device after a transfer + * ending with short_not_ok packet. + */ + if (prev && prev->short_not_ok) { + break; + } + + if (first) { + if (first->combined == NULL) { + USBCombinedPacket *combined = g_new0(USBCombinedPacket, 1); + + combined->first = first; + QTAILQ_INIT(&combined->packets); + qemu_iovec_init(&combined->iov, 2); + usb_combined_packet_add(combined, first); + } + usb_combined_packet_add(first->combined, p); + } else { + first = p; + } + + /* Is this packet the last one of a (combined) transfer? */ + totalsize = (p->combined) ? p->combined->iov.size : p->iov.size; + if ((p->iov.size % ep->max_packet_size) != 0 || !p->short_not_ok || + next == NULL || + /* Work around for Linux usbfs bulk splitting + migration */ + (totalsize == 16348 && p->int_req)) { + usb_device_handle_data(ep->dev, first); + assert(first->status == USB_RET_ASYNC); + if (first->combined) { + QTAILQ_FOREACH(u, &first->combined->packets, combined_entry) { + usb_packet_set_state(u, USB_PACKET_ASYNC); + } + } else { + usb_packet_set_state(first, USB_PACKET_ASYNC); + } + first = NULL; + prev = p; + } + } +} diff --git a/hw/usb/core.c b/hw/usb/core.c index 01a7622837..d057aab900 100644 --- a/hw/usb/core.c +++ b/hw/usb/core.c @@ -25,7 +25,7 @@ */ #include "qemu-common.h" #include "hw/usb.h" -#include "iov.h" +#include "qemu/iov.h" #include "trace.h" void usb_attach(USBPort *port) @@ -97,16 +97,17 @@ void usb_wakeup(USBEndpoint *ep) #define SETUP_STATE_ACK 3 #define SETUP_STATE_PARAM 4 -static int do_token_setup(USBDevice *s, USBPacket *p) +static void do_token_setup(USBDevice *s, USBPacket *p) { int request, value, index; - int ret = 0; if (p->iov.size != 8) { - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } usb_packet_copy(p, s->setup_buf, p->iov.size); + p->actual_length = 0; s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6]; s->setup_index = 0; @@ -115,24 +116,26 @@ static int do_token_setup(USBDevice *s, USBPacket *p) index = (s->setup_buf[5] << 8) | s->setup_buf[4]; if (s->setup_buf[0] & USB_DIR_IN) { - ret = usb_device_handle_control(s, p, request, value, index, - s->setup_len, s->data_buf); - if (ret == USB_RET_ASYNC) { - s->setup_state = SETUP_STATE_SETUP; - return USB_RET_ASYNC; + usb_device_handle_control(s, p, request, value, index, + s->setup_len, s->data_buf); + if (p->status == USB_RET_ASYNC) { + s->setup_state = SETUP_STATE_SETUP; + } + if (p->status != USB_RET_SUCCESS) { + return; } - if (ret < 0) - return ret; - if (ret < s->setup_len) - s->setup_len = ret; + if (p->actual_length < s->setup_len) { + s->setup_len = p->actual_length; + } s->setup_state = SETUP_STATE_DATA; } else { if (s->setup_len > sizeof(s->data_buf)) { fprintf(stderr, "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", s->setup_len, sizeof(s->data_buf)); - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } if (s->setup_len == 0) s->setup_state = SETUP_STATE_ACK; @@ -140,13 +143,12 @@ static int do_token_setup(USBDevice *s, USBPacket *p) s->setup_state = SETUP_STATE_DATA; } - return ret; + p->actual_length = 8; } -static int do_token_in(USBDevice *s, USBPacket *p) +static void do_token_in(USBDevice *s, USBPacket *p) { int request, value, index; - int ret = 0; assert(p->ep->nr == 0); @@ -157,19 +159,15 @@ static int do_token_in(USBDevice *s, USBPacket *p) switch(s->setup_state) { case SETUP_STATE_ACK: if (!(s->setup_buf[0] & USB_DIR_IN)) { - ret = usb_device_handle_control(s, p, request, value, index, - s->setup_len, s->data_buf); - if (ret == USB_RET_ASYNC) { - return USB_RET_ASYNC; + usb_device_handle_control(s, p, request, value, index, + s->setup_len, s->data_buf); + if (p->status == USB_RET_ASYNC) { + return; } s->setup_state = SETUP_STATE_IDLE; - if (ret > 0) - return 0; - return ret; + p->actual_length = 0; } - - /* return 0 byte */ - return 0; + break; case SETUP_STATE_DATA: if (s->setup_buf[0] & USB_DIR_IN) { @@ -179,20 +177,21 @@ static int do_token_in(USBDevice *s, USBPacket *p) } usb_packet_copy(p, s->data_buf + s->setup_index, len); s->setup_index += len; - if (s->setup_index >= s->setup_len) + if (s->setup_index >= s->setup_len) { s->setup_state = SETUP_STATE_ACK; - return len; + } + return; } - s->setup_state = SETUP_STATE_IDLE; - return USB_RET_STALL; + p->status = USB_RET_STALL; + break; default: - return USB_RET_STALL; + p->status = USB_RET_STALL; } } -static int do_token_out(USBDevice *s, USBPacket *p) +static void do_token_out(USBDevice *s, USBPacket *p) { assert(p->ep->nr == 0); @@ -204,7 +203,7 @@ static int do_token_out(USBDevice *s, USBPacket *p) } else { /* ignore additional output */ } - return 0; + break; case SETUP_STATE_DATA: if (!(s->setup_buf[0] & USB_DIR_IN)) { @@ -214,23 +213,23 @@ static int do_token_out(USBDevice *s, USBPacket *p) } usb_packet_copy(p, s->data_buf + s->setup_index, len); s->setup_index += len; - if (s->setup_index >= s->setup_len) + if (s->setup_index >= s->setup_len) { s->setup_state = SETUP_STATE_ACK; - return len; + } + return; } - s->setup_state = SETUP_STATE_IDLE; - return USB_RET_STALL; + p->status = USB_RET_STALL; + break; default: - return USB_RET_STALL; + p->status = USB_RET_STALL; } } -static int do_parameter(USBDevice *s, USBPacket *p) +static void do_parameter(USBDevice *s, USBPacket *p) { - int request, value, index; - int i, ret = 0; + int i, request, value, index; for (i = 0; i < 8; i++) { s->setup_buf[i] = p->parameter >> (i*8); @@ -248,27 +247,27 @@ static int do_parameter(USBDevice *s, USBPacket *p) fprintf(stderr, "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", s->setup_len, sizeof(s->data_buf)); - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } if (p->pid == USB_TOKEN_OUT) { usb_packet_copy(p, s->data_buf, s->setup_len); } - ret = usb_device_handle_control(s, p, request, value, index, - s->setup_len, s->data_buf); - if (ret < 0) { - return ret; + usb_device_handle_control(s, p, request, value, index, + s->setup_len, s->data_buf); + if (p->status == USB_RET_ASYNC) { + return; } - if (ret < s->setup_len) { - s->setup_len = ret; + if (p->actual_length < s->setup_len) { + s->setup_len = p->actual_length; } if (p->pid == USB_TOKEN_IN) { + p->actual_length = 0; usb_packet_copy(p, s->data_buf, s->setup_len); } - - return ret; } /* ctrl complete function for devices which use usb_generic_handle_packet and @@ -277,30 +276,30 @@ static int do_parameter(USBDevice *s, USBPacket *p) usb_packet_complete to complete their async control packets. */ void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p) { - if (p->result < 0) { + if (p->status < 0) { s->setup_state = SETUP_STATE_IDLE; } switch (s->setup_state) { case SETUP_STATE_SETUP: - if (p->result < s->setup_len) { - s->setup_len = p->result; + if (p->actual_length < s->setup_len) { + s->setup_len = p->actual_length; } s->setup_state = SETUP_STATE_DATA; - p->result = 8; + p->actual_length = 8; break; case SETUP_STATE_ACK: s->setup_state = SETUP_STATE_IDLE; - p->result = 0; + p->actual_length = 0; break; case SETUP_STATE_PARAM: - if (p->result < s->setup_len) { - s->setup_len = p->result; + if (p->actual_length < s->setup_len) { + s->setup_len = p->actual_length; } if (p->pid == USB_TOKEN_IN) { - p->result = 0; + p->actual_length = 0; usb_packet_copy(p, s->data_buf, s->setup_len); } break; @@ -341,61 +340,110 @@ USBDevice *usb_find_device(USBPort *port, uint8_t addr) return usb_device_find_device(dev, addr); } -static int usb_process_one(USBPacket *p) +static void usb_process_one(USBPacket *p) { USBDevice *dev = p->ep->dev; + /* + * Handlers expect status to be initialized to USB_RET_SUCCESS, but it + * can be USB_RET_NAK here from a previous usb_process_one() call, + * or USB_RET_ASYNC from going through usb_queue_one(). + */ + p->status = USB_RET_SUCCESS; + if (p->ep->nr == 0) { /* control pipe */ if (p->parameter) { - return do_parameter(dev, p); + do_parameter(dev, p); + return; } switch (p->pid) { case USB_TOKEN_SETUP: - return do_token_setup(dev, p); + do_token_setup(dev, p); + break; case USB_TOKEN_IN: - return do_token_in(dev, p); + do_token_in(dev, p); + break; case USB_TOKEN_OUT: - return do_token_out(dev, p); + do_token_out(dev, p); + break; default: - return USB_RET_STALL; + p->status = USB_RET_STALL; } } else { /* data pipe */ - return usb_device_handle_data(dev, p); + usb_device_handle_data(dev, p); } } -/* Hand over a packet to a device for processing. Return value +static void usb_queue_one(USBPacket *p) +{ + usb_packet_set_state(p, USB_PACKET_QUEUED); + QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue); + p->status = USB_RET_ASYNC; +} + +/* Hand over a packet to a device for processing. p->status == USB_RET_ASYNC indicates the processing isn't finished yet, the driver will call usb_packet_complete() when done processing it. */ -int usb_handle_packet(USBDevice *dev, USBPacket *p) +void usb_handle_packet(USBDevice *dev, USBPacket *p) { - int ret; - if (dev == NULL) { - return USB_RET_NODEV; + p->status = USB_RET_NODEV; + return; } assert(dev == p->ep->dev); assert(dev->state == USB_STATE_DEFAULT); usb_packet_check_state(p, USB_PACKET_SETUP); assert(p->ep != NULL); + /* Submitting a new packet clears halt */ + if (p->ep->halted) { + assert(QTAILQ_EMPTY(&p->ep->queue)); + p->ep->halted = false; + } + if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) { - ret = usb_process_one(p); - if (ret == USB_RET_ASYNC) { + usb_process_one(p); + if (p->status == USB_RET_ASYNC) { + /* hcd drivers cannot handle async for isoc */ + assert(p->ep->type != USB_ENDPOINT_XFER_ISOC); + /* using async for interrupt packets breaks migration */ + assert(p->ep->type != USB_ENDPOINT_XFER_INT || + (dev->flags & USB_DEV_FLAG_IS_HOST)); usb_packet_set_state(p, USB_PACKET_ASYNC); QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue); + } else if (p->status == USB_RET_ADD_TO_QUEUE) { + usb_queue_one(p); } else { - p->result = ret; - usb_packet_set_state(p, USB_PACKET_COMPLETE); + /* + * When pipelining is enabled usb-devices must always return async, + * otherwise packets can complete out of order! + */ + assert(!p->ep->pipeline || QTAILQ_EMPTY(&p->ep->queue)); + if (p->status != USB_RET_NAK) { + usb_packet_set_state(p, USB_PACKET_COMPLETE); + } } } else { - ret = USB_RET_ASYNC; - usb_packet_set_state(p, USB_PACKET_QUEUED); - QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue); + usb_queue_one(p); } - return ret; +} + +void usb_packet_complete_one(USBDevice *dev, USBPacket *p) +{ + USBEndpoint *ep = p->ep; + + assert(QTAILQ_FIRST(&ep->queue) == p); + assert(p->status != USB_RET_ASYNC && p->status != USB_RET_NAK); + + if (p->status != USB_RET_SUCCESS || + (p->short_not_ok && (p->actual_length < p->iov.size))) { + ep->halted = true; + } + usb_packet_set_state(p, USB_PACKET_COMPLETE); + QTAILQ_REMOVE(&ep->queue, p, queue); + dev->port->ops->complete(dev->port, p); } /* Notify the controller that an async packet is complete. This should only @@ -404,29 +452,28 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p) void usb_packet_complete(USBDevice *dev, USBPacket *p) { USBEndpoint *ep = p->ep; - int ret; usb_packet_check_state(p, USB_PACKET_ASYNC); - assert(QTAILQ_FIRST(&ep->queue) == p); - usb_packet_set_state(p, USB_PACKET_COMPLETE); - QTAILQ_REMOVE(&ep->queue, p, queue); - dev->port->ops->complete(dev->port, p); + usb_packet_complete_one(dev, p); while (!QTAILQ_EMPTY(&ep->queue)) { p = QTAILQ_FIRST(&ep->queue); + if (ep->halted) { + /* Empty the queue on a halt */ + p->status = USB_RET_REMOVE_FROM_QUEUE; + dev->port->ops->complete(dev->port, p); + continue; + } if (p->state == USB_PACKET_ASYNC) { break; } usb_packet_check_state(p, USB_PACKET_QUEUED); - ret = usb_process_one(p); - if (ret == USB_RET_ASYNC) { + usb_process_one(p); + if (p->status == USB_RET_ASYNC) { usb_packet_set_state(p, USB_PACKET_ASYNC); break; } - p->result = ret; - usb_packet_set_state(p, USB_PACKET_COMPLETE); - QTAILQ_REMOVE(&ep->queue, p, queue); - dev->port->ops->complete(dev->port, p); + usb_packet_complete_one(ep->dev, p); } } @@ -498,14 +545,20 @@ void usb_packet_set_state(USBPacket *p, USBPacketState state) p->state = state; } -void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep) +void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id, + bool short_not_ok, bool int_req) { assert(!usb_packet_is_inflight(p)); assert(p->iov.iov != NULL); + p->id = id; p->pid = pid; p->ep = ep; - p->result = 0; + p->status = USB_RET_SUCCESS; + p->actual_length = 0; p->parameter = 0; + p->short_not_ok = short_not_ok; + p->int_req = int_req; + p->combined = NULL; qemu_iovec_reset(&p->iov); usb_packet_set_state(p, USB_PACKET_SETUP); } @@ -517,31 +570,31 @@ void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len) void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes) { - assert(p->result >= 0); - assert(p->result + bytes <= p->iov.size); + assert(p->actual_length >= 0); + assert(p->actual_length + bytes <= p->iov.size); switch (p->pid) { case USB_TOKEN_SETUP: case USB_TOKEN_OUT: - iov_to_buf(p->iov.iov, p->iov.niov, p->result, ptr, bytes); + iov_to_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes); break; case USB_TOKEN_IN: - iov_from_buf(p->iov.iov, p->iov.niov, p->result, ptr, bytes); + iov_from_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes); break; default: fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid); abort(); } - p->result += bytes; + p->actual_length += bytes; } void usb_packet_skip(USBPacket *p, size_t bytes) { - assert(p->result >= 0); - assert(p->result + bytes <= p->iov.size); + assert(p->actual_length >= 0); + assert(p->actual_length + bytes <= p->iov.size); if (p->pid == USB_TOKEN_IN) { - iov_memset(p->iov.iov, p->iov.niov, p->result, 0, bytes); + iov_memset(p->iov.iov, p->iov.niov, p->actual_length, 0, bytes); } - p->result += bytes; + p->actual_length += bytes; } void usb_packet_cleanup(USBPacket *p) @@ -701,3 +754,18 @@ void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled) struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); uep->pipeline = enabled; } + +USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep, + uint64_t id) +{ + struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); + USBPacket *p; + + QTAILQ_FOREACH(p, &uep->queue, queue) { + if (p->id == id) { + return p; + } + } + + return NULL; +} diff --git a/hw/usb/desc.c b/hw/usb/desc.c index 0a9d3c9f60..b7c32333d7 100644 --- a/hw/usb/desc.c +++ b/hw/usb/desc.c @@ -76,7 +76,8 @@ int usb_desc_device_qualifier(const USBDescDevice *dev, return bLength; } -int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) +int usb_desc_config(const USBDescConfig *conf, int flags, + uint8_t *dest, size_t len) { uint8_t bLength = 0x09; uint16_t wTotalLength = 0; @@ -99,7 +100,7 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) /* handle grouped interfaces if any */ for (i = 0; i < conf->nif_groups; i++) { - rc = usb_desc_iface_group(&(conf->if_groups[i]), + rc = usb_desc_iface_group(&(conf->if_groups[i]), flags, dest + wTotalLength, len - wTotalLength); if (rc < 0) { @@ -110,7 +111,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) /* handle normal (ungrouped / no IAD) interfaces if any */ for (i = 0; i < conf->nif; i++) { - rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength); + rc = usb_desc_iface(conf->ifs + i, flags, + dest + wTotalLength, len - wTotalLength); if (rc < 0) { return rc; } @@ -122,8 +124,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) return wTotalLength; } -int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest, - size_t len) +int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags, + uint8_t *dest, size_t len) { int pos = 0; int i = 0; @@ -147,7 +149,7 @@ int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest, /* handle associated interfaces in this group */ for (i = 0; i < iad->nif; i++) { - int rc = usb_desc_iface(&(iad->ifs[i]), dest + pos, len - pos); + int rc = usb_desc_iface(&(iad->ifs[i]), flags, dest + pos, len - pos); if (rc < 0) { return rc; } @@ -157,7 +159,8 @@ int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest, return pos; } -int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len) +int usb_desc_iface(const USBDescIface *iface, int flags, + uint8_t *dest, size_t len) { uint8_t bLength = 0x09; int i, rc, pos = 0; @@ -188,7 +191,7 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len) } for (i = 0; i < iface->bNumEndpoints; i++) { - rc = usb_desc_endpoint(iface->eps + i, dest + pos, len - pos); + rc = usb_desc_endpoint(iface->eps + i, flags, dest + pos, len - pos); if (rc < 0) { return rc; } @@ -198,13 +201,15 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len) return pos; } -int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len) +int usb_desc_endpoint(const USBDescEndpoint *ep, int flags, + uint8_t *dest, size_t len) { uint8_t bLength = ep->is_audio ? 0x09 : 0x07; uint8_t extralen = ep->extra ? ep->extra[0] : 0; + uint8_t superlen = (flags & USB_DESC_FLAG_SUPER) ? 0x06 : 0; USBDescriptor *d = (void *)dest; - if (len < bLength + extralen) { + if (len < bLength + extralen + superlen) { return -1; } @@ -224,7 +229,21 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len) memcpy(dest + bLength, ep->extra, extralen); } - return bLength + extralen; + if (superlen) { + USBDescriptor *d = (void *)(dest + bLength + extralen); + + d->bLength = 0x06; + d->bDescriptorType = USB_DT_ENDPOINT_COMPANION; + + d->u.super_endpoint.bMaxBurst = ep->bMaxBurst; + d->u.super_endpoint.bmAttributes = ep->bmAttributes_super; + d->u.super_endpoint.wBytesPerInterval_lo = + usb_lo(ep->wBytesPerInterval); + d->u.super_endpoint.wBytesPerInterval_hi = + usb_hi(ep->wBytesPerInterval); + } + + return bLength + extralen + superlen; } int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) @@ -239,6 +258,111 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) return bLength; } +static int usb_desc_cap_usb2_ext(const USBDesc *desc, uint8_t *dest, size_t len) +{ + uint8_t bLength = 0x07; + USBDescriptor *d = (void *)dest; + + if (len < bLength) { + return -1; + } + + d->bLength = bLength; + d->bDescriptorType = USB_DT_DEVICE_CAPABILITY; + d->u.cap.bDevCapabilityType = USB_DEV_CAP_USB2_EXT; + + d->u.cap.u.usb2_ext.bmAttributes_1 = (1 << 1); /* LPM */ + d->u.cap.u.usb2_ext.bmAttributes_2 = 0; + d->u.cap.u.usb2_ext.bmAttributes_3 = 0; + d->u.cap.u.usb2_ext.bmAttributes_4 = 0; + + return bLength; +} + +static int usb_desc_cap_super(const USBDesc *desc, uint8_t *dest, size_t len) +{ + uint8_t bLength = 0x0a; + USBDescriptor *d = (void *)dest; + + if (len < bLength) { + return -1; + } + + d->bLength = bLength; + d->bDescriptorType = USB_DT_DEVICE_CAPABILITY; + d->u.cap.bDevCapabilityType = USB_DEV_CAP_SUPERSPEED; + + d->u.cap.u.super.bmAttributes = 0; + d->u.cap.u.super.wSpeedsSupported_lo = 0; + d->u.cap.u.super.wSpeedsSupported_hi = 0; + d->u.cap.u.super.bFunctionalitySupport = 0; + d->u.cap.u.super.bU1DevExitLat = 0x0a; + d->u.cap.u.super.wU2DevExitLat_lo = 0x20; + d->u.cap.u.super.wU2DevExitLat_hi = 0; + + if (desc->full) { + d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 1); + d->u.cap.u.super.bFunctionalitySupport = 1; + } + if (desc->high) { + d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 2); + if (!d->u.cap.u.super.bFunctionalitySupport) { + d->u.cap.u.super.bFunctionalitySupport = 2; + } + } + if (desc->super) { + d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 3); + if (!d->u.cap.u.super.bFunctionalitySupport) { + d->u.cap.u.super.bFunctionalitySupport = 3; + } + } + + return bLength; +} + +static int usb_desc_bos(const USBDesc *desc, uint8_t *dest, size_t len) +{ + uint8_t bLength = 0x05; + uint16_t wTotalLength = 0; + uint8_t bNumDeviceCaps = 0; + USBDescriptor *d = (void *)dest; + int rc; + + if (len < bLength) { + return -1; + } + + d->bLength = bLength; + d->bDescriptorType = USB_DT_BOS; + + wTotalLength += bLength; + + if (desc->high != NULL) { + rc = usb_desc_cap_usb2_ext(desc, dest + wTotalLength, + len - wTotalLength); + if (rc < 0) { + return rc; + } + wTotalLength += rc; + bNumDeviceCaps++; + } + + if (desc->super != NULL) { + rc = usb_desc_cap_super(desc, dest + wTotalLength, + len - wTotalLength); + if (rc < 0) { + return rc; + } + wTotalLength += rc; + bNumDeviceCaps++; + } + + d->u.bos.wTotalLength_lo = usb_lo(wTotalLength); + d->u.bos.wTotalLength_hi = usb_hi(wTotalLength); + d->u.bos.bNumDeviceCaps = bNumDeviceCaps; + return wTotalLength; +} + /* ------------------------------------------------------------------ */ static void usb_desc_ep_init(USBDevice *dev) @@ -359,6 +483,9 @@ static void usb_desc_setdefaults(USBDevice *dev) case USB_SPEED_HIGH: dev->device = desc->high; break; + case USB_SPEED_SUPER: + dev->device = desc->super; + break; } usb_desc_set_config(dev, 0); } @@ -376,6 +503,9 @@ void usb_desc_init(USBDevice *dev) if (desc->high) { dev->speedmask |= USB_SPEED_MASK_HIGH; } + if (desc->super) { + dev->speedmask |= USB_SPEED_MASK_SUPER; + } usb_desc_setdefaults(dev); } @@ -384,7 +514,9 @@ void usb_desc_attach(USBDevice *dev) const USBDesc *desc = usb_device_get_usb_desc(dev); assert(desc != NULL); - if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) { + if (desc->super && (dev->port->speedmask & USB_SPEED_MASK_SUPER)) { + dev->speed = USB_SPEED_SUPER; + } else if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) { dev->speed = USB_SPEED_HIGH; } else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) { dev->speed = USB_SPEED_FULL; @@ -494,14 +626,15 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len) return pos; } -int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len) +int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p, + int value, uint8_t *dest, size_t len) { const USBDesc *desc = usb_device_get_usb_desc(dev); const USBDescDevice *other_dev; uint8_t buf[256]; uint8_t type = value >> 8; uint8_t index = value & 0xff; - int ret = -1; + int flags, ret = -1; if (dev->speed == USB_SPEED_HIGH) { other_dev = usb_device_get_usb_desc(dev)->full; @@ -509,6 +642,11 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len other_dev = usb_device_get_usb_desc(dev)->high; } + flags = 0; + if (dev->device->bcdUSB >= 0x0300) { + flags |= USB_DESC_FLAG_SUPER; + } + switch(type) { case USB_DT_DEVICE: ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf)); @@ -516,7 +654,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len break; case USB_DT_CONFIG: if (index < dev->device->bNumConfigurations) { - ret = usb_desc_config(dev->device->confs + index, buf, sizeof(buf)); + ret = usb_desc_config(dev->device->confs + index, flags, + buf, sizeof(buf)); } trace_usb_desc_config(dev->addr, index, len, ret); break; @@ -524,7 +663,6 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len ret = usb_desc_string(dev, index, buf, sizeof(buf)); trace_usb_desc_string(dev->addr, index, len, ret); break; - case USB_DT_DEVICE_QUALIFIER: if (other_dev != NULL) { ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf)); @@ -533,11 +671,16 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len break; case USB_DT_OTHER_SPEED_CONFIG: if (other_dev != NULL && index < other_dev->bNumConfigurations) { - ret = usb_desc_config(other_dev->confs + index, buf, sizeof(buf)); + ret = usb_desc_config(other_dev->confs + index, flags, + buf, sizeof(buf)); buf[0x01] = USB_DT_OTHER_SPEED_CONFIG; } trace_usb_desc_other_speed_config(dev->addr, index, len, ret); break; + case USB_DT_BOS: + ret = usb_desc_bos(desc, buf, sizeof(buf)); + trace_usb_desc_bos(dev->addr, len, ret); + break; case USB_DT_DEBUG: /* ignore silently */ @@ -554,6 +697,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len ret = len; } memcpy(dest, buf, ret); + p->actual_length = ret; + ret = 0; } return ret; } @@ -573,7 +718,7 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, break; case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - ret = usb_desc_get_descriptor(dev, value, data, length); + ret = usb_desc_get_descriptor(dev, p, value, data, length); break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: @@ -582,7 +727,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, * the non zero value of bConfigurationValue. */ data[0] = dev->config ? dev->config->bConfigurationValue : 0; - ret = 1; + p->actual_length = 1; + ret = 0; break; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: ret = usb_desc_set_config(dev, value); @@ -607,7 +753,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP; } data[1] = 0x00; - ret = 2; + p->actual_length = 2; + ret = 0; break; } case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: @@ -630,7 +777,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, break; } data[0] = dev->altsetting[index]; - ret = 1; + p->actual_length = 1; + ret = 0; break; case InterfaceOutRequest | USB_REQ_SET_INTERFACE: ret = usb_desc_set_interface(dev, index, value); diff --git a/hw/usb/desc.h b/hw/usb/desc.h index 7cf5442945..ddd3e7485c 100644 --- a/hw/usb/desc.h +++ b/hw/usb/desc.h @@ -63,6 +63,37 @@ typedef struct USBDescriptor { uint8_t bRefresh; /* only audio ep */ uint8_t bSynchAddress; /* only audio ep */ } endpoint; + struct { + uint8_t bMaxBurst; + uint8_t bmAttributes; + uint8_t wBytesPerInterval_lo; + uint8_t wBytesPerInterval_hi; + } super_endpoint; + struct { + uint8_t wTotalLength_lo; + uint8_t wTotalLength_hi; + uint8_t bNumDeviceCaps; + } bos; + struct { + uint8_t bDevCapabilityType; + union { + struct { + uint8_t bmAttributes_1; + uint8_t bmAttributes_2; + uint8_t bmAttributes_3; + uint8_t bmAttributes_4; + } usb2_ext; + struct { + uint8_t bmAttributes; + uint8_t wSpeedsSupported_lo; + uint8_t wSpeedsSupported_hi; + uint8_t bFunctionalitySupport; + uint8_t bU1DevExitLat; + uint8_t wU2DevExitLat_lo; + uint8_t wU2DevExitLat_hi; + } super; + } u; + } cap; } u; } QEMU_PACKED USBDescriptor; @@ -139,6 +170,11 @@ struct USBDescEndpoint { uint8_t is_audio; /* has bRefresh + bSynchAddress */ uint8_t *extra; + + /* superspeed endpoint companion */ + uint8_t bMaxBurst; + uint8_t bmAttributes_super; + uint16_t wBytesPerInterval; }; struct USBDescOther { @@ -152,19 +188,25 @@ struct USBDesc { USBDescID id; const USBDescDevice *full; const USBDescDevice *high; + const USBDescDevice *super; const char* const *str; }; +#define USB_DESC_FLAG_SUPER (1 << 1) + /* generate usb packages from structs */ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, uint8_t *dest, size_t len); int usb_desc_device_qualifier(const USBDescDevice *dev, uint8_t *dest, size_t len); -int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len); -int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest, - size_t len); -int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len); -int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len); +int usb_desc_config(const USBDescConfig *conf, int flags, + uint8_t *dest, size_t len); +int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags, + uint8_t *dest, size_t len); +int usb_desc_iface(const USBDescIface *iface, int flags, + uint8_t *dest, size_t len); +int usb_desc_endpoint(const USBDescEndpoint *ep, int flags, + uint8_t *dest, size_t len); int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len); /* control message emulation helpers */ @@ -174,7 +216,8 @@ void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str); void usb_desc_create_serial(USBDevice *dev); const char *usb_desc_get_string(USBDevice *dev, uint8_t index); int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len); -int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len); +int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p, + int value, uint8_t *dest, size_t len); int usb_desc_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data); diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c index 79b75fb628..b669601c92 100644 --- a/hw/usb/dev-audio.c +++ b/hw/usb/dev-audio.c @@ -217,7 +217,7 @@ static const USBDescIface desc_iface[] = { }; static const USBDescDevice desc_device = { - .bcdUSB = 0x0200, + .bcdUSB = 0x0100, .bMaxPacketSize0 = 64, .bNumConfigurations = 1, .confs = (USBDescConfig[]) { @@ -503,7 +503,7 @@ static int usb_audio_set_control(USBAudioState *s, uint8_t attrib, return ret; } -static int usb_audio_handle_control(USBDevice *dev, USBPacket *p, +static void usb_audio_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { @@ -518,7 +518,7 @@ static int usb_audio_handle_control(USBDevice *dev, USBPacket *p, ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } switch (request) { @@ -534,6 +534,7 @@ static int usb_audio_handle_control(USBDevice *dev, USBPacket *p, } goto fail; } + p->actual_length = ret; break; case ClassInterfaceOutRequest | CR_SET_CUR: @@ -557,10 +558,9 @@ fail: "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n", request, value, index, length); } - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } static void usb_audio_set_interface(USBDevice *dev, int iface, @@ -583,50 +583,35 @@ static void usb_audio_handle_reset(USBDevice *dev) usb_audio_set_output_altset(s, ALTSET_OFF); } -static int usb_audio_handle_dataout(USBAudioState *s, USBPacket *p) +static void usb_audio_handle_dataout(USBAudioState *s, USBPacket *p) { - int rc; - if (s->out.altset == ALTSET_OFF) { - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } - rc = streambuf_put(&s->out.buf, p); - if (rc < p->iov.size && s->debug > 1) { + streambuf_put(&s->out.buf, p); + if (p->actual_length < p->iov.size && s->debug > 1) { fprintf(stderr, "usb-audio: output overrun (%zd bytes)\n", - p->iov.size - rc); + p->iov.size - p->actual_length); } - - return 0; } -static int usb_audio_handle_data(USBDevice *dev, USBPacket *p) +static void usb_audio_handle_data(USBDevice *dev, USBPacket *p) { USBAudioState *s = (USBAudioState *) dev; - int ret = 0; - switch (p->pid) { - case USB_TOKEN_OUT: - switch (p->ep->nr) { - case 1: - ret = usb_audio_handle_dataout(s, p); - break; - default: - goto fail; - } - break; - - default: -fail: - ret = USB_RET_STALL; - break; + if (p->pid == USB_TOKEN_OUT && p->ep->nr == 1) { + usb_audio_handle_dataout(s, p); + return; } - if (ret == USB_RET_STALL && s->debug) { + + p->status = USB_RET_STALL; + if (s->debug) { fprintf(stderr, "usb-audio: failed data transaction: " "pid 0x%x ep 0x%x len 0x%zx\n", p->pid, p->ep->nr, p->iov.size); } - return ret; } static void usb_audio_handle_destroy(USBDevice *dev) diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c index 55bc19184b..a0d7a88d91 100644 --- a/hw/usb/dev-bluetooth.c +++ b/hw/usb/dev-bluetooth.c @@ -21,12 +21,13 @@ #include "qemu-common.h" #include "hw/usb.h" #include "hw/usb/desc.h" -#include "net.h" +#include "bt/bt.h" #include "hw/bt.h" struct USBBtState { USBDevice dev; struct HCIInfo *hci; + USBEndpoint *intr; int config; @@ -285,13 +286,12 @@ static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo, fifo->fifo[off].len = len; } -static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo, +static inline void usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo, USBPacket *p) { int len; - if (likely(!fifo->len)) - return USB_RET_STALL; + assert(fifo->len != 0); len = MIN(p->iov.size, fifo->fifo[fifo->start].len); usb_packet_copy(p, fifo->fifo[fifo->start].data, len); @@ -310,8 +310,6 @@ static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo, fifo->dstart = 0; fifo->dsize = DFIFO_LEN_MASK + 1; } - - return len; } static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s, @@ -363,7 +361,7 @@ static void usb_bt_handle_reset(USBDevice *dev) s->outsco.len = 0; } -static int usb_bt_handle_control(USBDevice *dev, USBPacket *p, +static void usb_bt_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { struct USBBtState *s = (struct USBBtState *) dev->opaque; @@ -382,16 +380,15 @@ static int usb_bt_handle_control(USBDevice *dev, USBPacket *p, usb_bt_fifo_reset(&s->sco); break; } - return ret; + return; } - ret = 0; switch (request) { case InterfaceRequest | USB_REQ_GET_STATUS: case EndpointRequest | USB_REQ_GET_STATUS: data[0] = 0x00; data[1] = 0x00; - ret = 2; + p->actual_length = 2; break; case InterfaceOutRequest | USB_REQ_CLEAR_FEATURE: case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: @@ -407,16 +404,14 @@ static int usb_bt_handle_control(USBDevice *dev, USBPacket *p, break; default: fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } -static int usb_bt_handle_data(USBDevice *dev, USBPacket *p) +static void usb_bt_handle_data(USBDevice *dev, USBPacket *p) { struct USBBtState *s = (struct USBBtState *) dev->opaque; - int ret = 0; if (!s->config) goto fail; @@ -425,15 +420,27 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p) case USB_TOKEN_IN: switch (p->ep->nr) { case USB_EVT_EP: - ret = usb_bt_fifo_dequeue(&s->evt, p); + if (s->evt.len == 0) { + p->status = USB_RET_NAK; + break; + } + usb_bt_fifo_dequeue(&s->evt, p); break; case USB_ACL_EP: - ret = usb_bt_fifo_dequeue(&s->acl, p); + if (s->evt.len == 0) { + p->status = USB_RET_STALL; + break; + } + usb_bt_fifo_dequeue(&s->acl, p); break; case USB_SCO_EP: - ret = usb_bt_fifo_dequeue(&s->sco, p); + if (s->evt.len == 0) { + p->status = USB_RET_STALL; + break; + } + usb_bt_fifo_dequeue(&s->sco, p); break; default: @@ -460,11 +467,9 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p) default: fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - - return ret; } static void usb_bt_out_hci_packet_event(void *opaque, @@ -472,6 +477,9 @@ static void usb_bt_out_hci_packet_event(void *opaque, { struct USBBtState *s = (struct USBBtState *) opaque; + if (s->evt.len == 0) { + usb_wakeup(s->intr); + } usb_bt_fifo_enqueue(&s->evt, data, len); } @@ -494,8 +502,12 @@ static void usb_bt_handle_destroy(USBDevice *dev) static int usb_bt_initfn(USBDevice *dev) { + struct USBBtState *s = DO_UPCAST(struct USBBtState, dev, dev); + usb_desc_create_serial(dev); usb_desc_init(dev); + s->intr = usb_ep_get(dev, USB_TOKEN_IN, USB_EVT_EP); + return 0; } diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index b3dcd23109..b4ace04eef 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -23,10 +23,10 @@ * THE SOFTWARE. */ #include "hw/hw.h" -#include "console.h" +#include "ui/console.h" #include "hw/usb.h" #include "hw/usb/desc.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "hw/hid.h" /* HID interface requests */ @@ -46,6 +46,7 @@ typedef struct USBHIDState { USBDevice dev; USBEndpoint *intr; HIDState hid; + uint32_t usb_version; } USBHIDState; enum { @@ -131,6 +132,36 @@ static const USBDescIface desc_iface_tablet = { }, }; +static const USBDescIface desc_iface_tablet2 = { + .bInterfaceNumber = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceProtocol = 0x02, + .ndesc = 1, + .descs = (USBDescOther[]) { + { + /* HID descriptor */ + .data = (uint8_t[]) { + 0x09, /* u8 bLength */ + USB_DT_HID, /* u8 bDescriptorType */ + 0x01, 0x00, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + USB_DT_REPORT, /* u8 type: Report */ + 74, 0, /* u16 len */ + }, + }, + }, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x01, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 8, + .bInterval = 4, /* 2 ^ (4-1) * 125 usecs = 1 ms */ + }, + }, +}; + static const USBDescIface desc_iface_keyboard = { .bInterfaceNumber = 0, .bNumEndpoints = 1, @@ -196,6 +227,23 @@ static const USBDescDevice desc_device_tablet = { }, }; +static const USBDescDevice desc_device_tablet2 = { + .bcdUSB = 0x0200, + .bMaxPacketSize0 = 64, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = STR_CONFIG_TABLET, + .bmAttributes = 0xa0, + .bMaxPower = 50, + .nif = 1, + .ifs = &desc_iface_tablet2, + }, + }, +}; + static const USBDescDevice desc_device_keyboard = { .bcdUSB = 0x0100, .bMaxPacketSize0 = 8, @@ -239,6 +287,20 @@ static const USBDesc desc_tablet = { .str = desc_strings, }; +static const USBDesc desc_tablet2 = { + .id = { + .idVendor = 0x0627, + .idProduct = 0x0001, + .bcdDevice = 0, + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT_TABLET, + .iSerialNumber = STR_SERIALNUMBER, + }, + .full = &desc_device_tablet, + .high = &desc_device_tablet2, + .str = desc_strings, +}; + static const USBDesc desc_keyboard = { .id = { .idVendor = 0x0627, @@ -371,7 +433,7 @@ static void usb_hid_handle_reset(USBDevice *dev) hid_reset(&us->hid); } -static int usb_hid_handle_control(USBDevice *dev, USBPacket *p, +static void usb_hid_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); @@ -380,10 +442,9 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p, ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } - ret = 0; switch (request) { /* hid specific requests */ case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: @@ -392,15 +453,15 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p, if (hs->kind == HID_MOUSE) { memcpy(data, qemu_mouse_hid_report_descriptor, sizeof(qemu_mouse_hid_report_descriptor)); - ret = sizeof(qemu_mouse_hid_report_descriptor); + p->actual_length = sizeof(qemu_mouse_hid_report_descriptor); } else if (hs->kind == HID_TABLET) { memcpy(data, qemu_tablet_hid_report_descriptor, sizeof(qemu_tablet_hid_report_descriptor)); - ret = sizeof(qemu_tablet_hid_report_descriptor); + p->actual_length = sizeof(qemu_tablet_hid_report_descriptor); } else if (hs->kind == HID_KEYBOARD) { memcpy(data, qemu_keyboard_hid_report_descriptor, sizeof(qemu_keyboard_hid_report_descriptor)); - ret = sizeof(qemu_keyboard_hid_report_descriptor); + p->actual_length = sizeof(qemu_keyboard_hid_report_descriptor); } break; default: @@ -409,14 +470,14 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p, break; case GET_REPORT: if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { - ret = hid_pointer_poll(hs, data, length); + p->actual_length = hid_pointer_poll(hs, data, length); } else if (hs->kind == HID_KEYBOARD) { - ret = hid_keyboard_poll(hs, data, length); + p->actual_length = hid_keyboard_poll(hs, data, length); } break; case SET_REPORT: if (hs->kind == HID_KEYBOARD) { - ret = hid_keyboard_write(hs, data, length); + p->actual_length = hid_keyboard_write(hs, data, length); } else { goto fail; } @@ -425,61 +486,57 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p, if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) { goto fail; } - ret = 1; data[0] = hs->protocol; + p->actual_length = 1; break; case SET_PROTOCOL: if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) { goto fail; } - ret = 0; hs->protocol = value; break; case GET_IDLE: - ret = 1; data[0] = hs->idle; + p->actual_length = 1; break; case SET_IDLE: hs->idle = (uint8_t) (value >> 8); - hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock)); + hid_set_next_idle(hs); if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { hid_pointer_activate(hs); } - ret = 0; break; default: fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } -static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) +static void usb_hid_handle_data(USBDevice *dev, USBPacket *p) { USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); HIDState *hs = &us->hid; uint8_t buf[p->iov.size]; - int ret = 0; + int len = 0; switch (p->pid) { case USB_TOKEN_IN: if (p->ep->nr == 1) { - int64_t curtime = qemu_get_clock_ns(vm_clock); if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { hid_pointer_activate(hs); } - if (!hid_has_events(hs) && - (!hs->idle || hs->next_idle_clock - curtime > 0)) { - return USB_RET_NAK; + if (!hid_has_events(hs)) { + p->status = USB_RET_NAK; + return; } - hid_set_next_idle(hs, curtime); + hid_set_next_idle(hs); if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { - ret = hid_pointer_poll(hs, buf, p->iov.size); + len = hid_pointer_poll(hs, buf, p->iov.size); } else if (hs->kind == HID_KEYBOARD) { - ret = hid_keyboard_poll(hs, buf, p->iov.size); + len = hid_keyboard_poll(hs, buf, p->iov.size); } - usb_packet_copy(p, buf, ret); + usb_packet_copy(p, buf, len); } else { goto fail; } @@ -487,10 +544,9 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) case USB_TOKEN_OUT: default: fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } static void usb_hid_handle_destroy(USBDevice *dev) @@ -512,6 +568,21 @@ static int usb_hid_initfn(USBDevice *dev, int kind) static int usb_tablet_initfn(USBDevice *dev) { + USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); + + switch (us->usb_version) { + case 1: + dev->usb_desc = &desc_tablet; + break; + case 2: + dev->usb_desc = &desc_tablet2; + break; + default: + error_report("Invalid usb version %d for usb-tabler (must be 1 or 2)", + us->usb_version); + return -1; + } + return usb_hid_initfn(dev, HID_TABLET); } @@ -566,8 +637,14 @@ static void usb_hid_class_initfn(ObjectClass *klass, void *data) uc->handle_control = usb_hid_handle_control; uc->handle_data = usb_hid_handle_data; uc->handle_destroy = usb_hid_handle_destroy; + uc->handle_attach = usb_desc_attach; } +static Property usb_tablet_properties[] = { + DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2), + DEFINE_PROP_END_OF_LIST(), +}; + static void usb_tablet_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -576,8 +653,8 @@ static void usb_tablet_class_initfn(ObjectClass *klass, void *data) usb_hid_class_initfn(klass, data); uc->init = usb_tablet_initfn; uc->product_desc = "QEMU USB Tablet"; - uc->usb_desc = &desc_tablet; dc->vmsd = &vmstate_usb_ptr; + dc->props = usb_tablet_properties; } static TypeInfo usb_tablet_info = { diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index 8fd30df0e6..470fbbb86c 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -184,6 +184,7 @@ static void usb_hub_detach(USBPort *port1) port->wPortStatus &= ~PORT_STAT_ENABLE; port->wPortChange |= PORT_STAT_C_ENABLE; } + usb_wakeup(s->intr); } static void usb_hub_child_detach(USBPort *port1, USBDevice *child) @@ -288,7 +289,7 @@ static const char *feature_name(int feature) return name[feature] ?: "?"; } -static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, +static void usb_hub_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBHubState *s = (USBHubState *)dev; @@ -298,7 +299,7 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } switch(request) { @@ -306,7 +307,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, if (value == 0 && index != 0x81) { /* clear ep halt */ goto fail; } - ret = 0; break; /* usb specific requests */ case GetHubStatus: @@ -314,7 +314,7 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, data[1] = 0; data[2] = 0; data[3] = 0; - ret = 4; + p->actual_length = 4; break; case GetPortStatus: { @@ -331,16 +331,14 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, data[1] = port->wPortStatus >> 8; data[2] = port->wPortChange; data[3] = port->wPortChange >> 8; - ret = 4; + p->actual_length = 4; } break; case SetHubFeature: case ClearHubFeature: - if (value == 0 || value == 1) { - } else { + if (value != 0 && value != 1) { goto fail; } - ret = 0; break; case SetPortFeature: { @@ -366,6 +364,7 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, port->wPortChange |= PORT_STAT_C_RESET; /* set enable bit */ port->wPortStatus |= PORT_STAT_ENABLE; + usb_wakeup(s->intr); } break; case PORT_POWER: @@ -373,7 +372,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, default: goto fail; } - ret = 0; } break; case ClearPortFeature: @@ -413,7 +411,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, default: goto fail; } - ret = 0; } break; case GetHubDescriptor: @@ -437,22 +434,20 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, var_hub_size++; } - ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size; - data[0] = ret; + p->actual_length = sizeof(qemu_hub_hub_descriptor) + var_hub_size; + data[0] = p->actual_length; break; } default: fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } -static int usb_hub_handle_data(USBDevice *dev, USBPacket *p) +static void usb_hub_handle_data(USBDevice *dev, USBPacket *p) { USBHubState *s = (USBHubState *)dev; - int ret; switch(p->pid) { case USB_TOKEN_IN: @@ -465,7 +460,8 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p) if (p->iov.size == 1) { /* FreeBSD workaround */ n = 1; } else if (n > p->iov.size) { - return USB_RET_BABBLE; + p->status = USB_RET_BABBLE; + return; } status = 0; for(i = 0; i < NUM_PORTS; i++) { @@ -478,9 +474,8 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p) buf[i] = status >> (8 * i); } usb_packet_copy(p, buf, n); - ret = n; } else { - ret = USB_RET_NAK; /* usb11 11.13.1 */ + p->status = USB_RET_NAK; /* usb11 11.13.1 */ } } else { goto fail; @@ -489,10 +484,9 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p) case USB_TOKEN_OUT: default: fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } static void usb_hub_handle_destroy(USBDevice *dev) diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index c84892c98d..1c54863452 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -26,10 +26,11 @@ #include "qemu-common.h" #include "hw/usb.h" #include "hw/usb/desc.h" -#include "net.h" -#include "qemu-queue.h" -#include "sysemu.h" -#include "iov.h" +#include "net/net.h" +#include "qemu/queue.h" +#include "qemu/config-file.h" +#include "sysemu/sysemu.h" +#include "qemu/iov.h" /*#define TRAFFIC_DEBUG*/ /* Thanks to NetChip Technologies for donating this product ID. @@ -639,6 +640,8 @@ typedef struct USBNetState { unsigned int in_ptr, in_len; uint8_t in_buf[2048]; + USBEndpoint *intr; + char usbstring_mac[13]; NICState *nic; NICConf conf; @@ -851,6 +854,10 @@ static void *rndis_queue_response(USBNetState *s, unsigned int length) struct rndis_response *r = g_malloc0(sizeof(struct rndis_response) + length); + if (QTAILQ_EMPTY(&s->rndis_resp)) { + usb_wakeup(s->intr); + } + QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries); r->length = length; @@ -1001,6 +1008,13 @@ static int rndis_keepalive_response(USBNetState *s, return 0; } +/* Prepare to receive the next packet */ +static void usb_net_reset_in_buf(USBNetState *s) +{ + s->in_ptr = s->in_len = 0; + qemu_flush_queued_packets(&s->nic->nc); +} + static int rndis_parse(USBNetState *s, uint8_t *data, int length) { uint32_t msg_type; @@ -1025,7 +1039,8 @@ static int rndis_parse(USBNetState *s, uint8_t *data, int length) case RNDIS_RESET_MSG: rndis_clear_responsequeue(s); - s->out_ptr = s->in_ptr = s->in_len = 0; + s->out_ptr = 0; + usb_net_reset_in_buf(s); return rndis_reset_response(s, (rndis_reset_msg_type *) data); case RNDIS_KEEPALIVE_MSG: @@ -1040,7 +1055,7 @@ static void usb_net_handle_reset(USBDevice *dev) { } -static int usb_net_handle_control(USBDevice *dev, USBPacket *p, +static void usb_net_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBNetState *s = (USBNetState *) dev; @@ -1048,10 +1063,9 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p, ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } - ret = 0; switch(request) { case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND: if (!is_rndis(s) || value || index != 0) { @@ -1070,22 +1084,25 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p, } #endif ret = rndis_parse(s, data, length); + if (ret < 0) { + p->status = ret; + } break; case ClassInterfaceRequest | USB_CDC_GET_ENCAPSULATED_RESPONSE: if (!is_rndis(s) || value || index != 0) { goto fail; } - ret = rndis_get_response(s, data); - if (!ret) { + p->actual_length = rndis_get_response(s, data); + if (p->actual_length == 0) { data[0] = 0; - ret = 1; + p->actual_length = 1; } #ifdef TRAFFIC_DEBUG { unsigned int i; fprintf(stderr, "GET_ENCAPSULATED_RESPONSE:"); - for (i = 0; i < ret; i++) { + for (i = 0; i < p->actual_length; i++) { if (!(i & 15)) fprintf(stderr, "\n%04x:", i); fprintf(stderr, " %02x", data[i]); @@ -1100,72 +1117,67 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p, fprintf(stderr, "usbnet: failed control transaction: " "request 0x%x value 0x%x index 0x%x length 0x%x\n", request, value, index, length); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } -static int usb_net_handle_statusin(USBNetState *s, USBPacket *p) +static void usb_net_handle_statusin(USBNetState *s, USBPacket *p) { le32 buf[2]; - int ret = 8; if (p->iov.size < 8) { - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } buf[0] = cpu_to_le32(1); buf[1] = cpu_to_le32(0); usb_packet_copy(p, buf, 8); - if (!s->rndis_resp.tqh_first) - ret = USB_RET_NAK; + if (!s->rndis_resp.tqh_first) { + p->status = USB_RET_NAK; + } #ifdef TRAFFIC_DEBUG fprintf(stderr, "usbnet: interrupt poll len %zu return %d", - p->iov.size, ret); - iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret); + p->iov.size, p->status); + iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->status); #endif - - return ret; } -static int usb_net_handle_datain(USBNetState *s, USBPacket *p) +static void usb_net_handle_datain(USBNetState *s, USBPacket *p) { - int ret = USB_RET_NAK; + int len; if (s->in_ptr > s->in_len) { - s->in_ptr = s->in_len = 0; - ret = USB_RET_NAK; - return ret; + usb_net_reset_in_buf(s); + p->status = USB_RET_NAK; + return; } if (!s->in_len) { - ret = USB_RET_NAK; - return ret; + p->status = USB_RET_NAK; + return; } - ret = s->in_len - s->in_ptr; - if (ret > p->iov.size) { - ret = p->iov.size; + len = s->in_len - s->in_ptr; + if (len > p->iov.size) { + len = p->iov.size; } - usb_packet_copy(p, &s->in_buf[s->in_ptr], ret); - s->in_ptr += ret; + usb_packet_copy(p, &s->in_buf[s->in_ptr], len); + s->in_ptr += len; if (s->in_ptr >= s->in_len && - (is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) { + (is_rndis(s) || (s->in_len & (64 - 1)) || !len)) { /* no short packet necessary */ - s->in_ptr = s->in_len = 0; + usb_net_reset_in_buf(s); } #ifdef TRAFFIC_DEBUG - fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, ret); - iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret); + fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, len); + iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", len); #endif - - return ret; } -static int usb_net_handle_dataout(USBNetState *s, USBPacket *p) +static void usb_net_handle_dataout(USBNetState *s, USBPacket *p) { - int ret = p->iov.size; int sz = sizeof(s->out_buf) - s->out_ptr; struct rndis_packet_msg_type *msg = (struct rndis_packet_msg_type *) s->out_buf; @@ -1176,21 +1188,23 @@ static int usb_net_handle_dataout(USBNetState *s, USBPacket *p) iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->iov.size); #endif - if (sz > ret) - sz = ret; + if (sz > p->iov.size) { + sz = p->iov.size; + } usb_packet_copy(p, &s->out_buf[s->out_ptr], sz); s->out_ptr += sz; if (!is_rndis(s)) { - if (ret < 64) { + if (p->iov.size < 64) { qemu_send_packet(&s->nic->nc, s->out_buf, s->out_ptr); s->out_ptr = 0; } - return ret; + return; } len = le32_to_cpu(msg->MessageLength); - if (s->out_ptr < 8 || s->out_ptr < len) - return ret; + if (s->out_ptr < 8 || s->out_ptr < len) { + return; + } if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) { uint32_t offs = 8 + le32_to_cpu(msg->DataOffset); uint32_t size = le32_to_cpu(msg->DataLength); @@ -1199,24 +1213,21 @@ static int usb_net_handle_dataout(USBNetState *s, USBPacket *p) } s->out_ptr -= len; memmove(s->out_buf, &s->out_buf[len], s->out_ptr); - - return ret; } -static int usb_net_handle_data(USBDevice *dev, USBPacket *p) +static void usb_net_handle_data(USBDevice *dev, USBPacket *p) { USBNetState *s = (USBNetState *) dev; - int ret = 0; switch(p->pid) { case USB_TOKEN_IN: switch (p->ep->nr) { case 1: - ret = usb_net_handle_statusin(s, p); + usb_net_handle_statusin(s, p); break; case 2: - ret = usb_net_handle_datain(s, p); + usb_net_handle_datain(s, p); break; default: @@ -1227,7 +1238,7 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) case USB_TOKEN_OUT: switch (p->ep->nr) { case 2: - ret = usb_net_handle_dataout(s, p); + usb_net_handle_dataout(s, p); break; default: @@ -1237,33 +1248,46 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) default: fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - if (ret == USB_RET_STALL) + + if (p->status == USB_RET_STALL) { fprintf(stderr, "usbnet: failed data transaction: " "pid 0x%x ep 0x%x len 0x%zx\n", p->pid, p->ep->nr, p->iov.size); - return ret; + } } static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size) { USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; - struct rndis_packet_msg_type *msg; + uint8_t *in_buf = s->in_buf; + size_t total_size = size; if (is_rndis(s)) { - msg = (struct rndis_packet_msg_type *) s->in_buf; if (s->rndis_state != RNDIS_DATA_INITIALIZED) { return -1; } - if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf)) - return -1; + total_size += sizeof(struct rndis_packet_msg_type); + } + if (total_size > sizeof(s->in_buf)) { + return -1; + } + + /* Only accept packet if input buffer is empty */ + if (s->in_len > 0) { + return 0; + } + if (is_rndis(s)) { + struct rndis_packet_msg_type *msg; + + msg = (struct rndis_packet_msg_type *)in_buf; memset(msg, 0, sizeof(struct rndis_packet_msg_type)); msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG); - msg->MessageLength = cpu_to_le32(size + sizeof(struct rndis_packet_msg_type)); - msg->DataOffset = cpu_to_le32(sizeof(struct rndis_packet_msg_type) - 8); + msg->MessageLength = cpu_to_le32(size + sizeof(*msg)); + msg->DataOffset = cpu_to_le32(sizeof(*msg) - 8); msg->DataLength = cpu_to_le32(size); /* msg->OOBDataOffset; * msg->OOBDataLength; @@ -1273,14 +1297,11 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz * msg->VcHandle; * msg->Reserved; */ - memcpy(msg + 1, buf, size); - s->in_len = size + sizeof(struct rndis_packet_msg_type); - } else { - if (size > sizeof(s->in_buf)) - return -1; - memcpy(s->in_buf, buf, size); - s->in_len = size; + in_buf += sizeof(*msg); } + + memcpy(in_buf, buf, size); + s->in_len = total_size; s->in_ptr = 0; return size; } @@ -1335,6 +1356,7 @@ static int usb_net_initfn(USBDevice *dev) s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */; s->filter = 0; s->vendorid = 0x1234; + s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_usbnet_info, &s->conf, diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c index 8aa655286b..20cf5337b7 100644 --- a/hw/usb/dev-serial.c +++ b/hw/usb/dev-serial.c @@ -9,10 +9,10 @@ */ #include "qemu-common.h" -#include "qemu-error.h" +#include "qemu/error-report.h" #include "hw/usb.h" #include "hw/usb/desc.h" -#include "qemu-char.h" +#include "char/char.h" //#define DEBUG_Serial @@ -113,7 +113,7 @@ enum { static const USBDescStrings desc_strings = { [STR_MANUFACTURER] = "QEMU", [STR_PRODUCT_SERIAL] = "QEMU USB SERIAL", - [STR_PRODUCT_BRAILLE] = "QEMU USB BRAILLE", + [STR_PRODUCT_BRAILLE] = "QEMU USB BAUM BRAILLE", [STR_SERIALNUMBER] = "1", }; @@ -219,7 +219,7 @@ static uint8_t usb_get_modem_lines(USBSerialState *s) return ret; } -static int usb_serial_handle_control(USBDevice *dev, USBPacket *p, +static void usb_serial_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBSerialState *s = (USBSerialState *)dev; @@ -228,13 +228,11 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p, DPRINTF("got control %x, value %x\n",request, value); ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } - ret = 0; switch (request) { case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: - ret = 0; break; /* Class specific requests. */ @@ -323,7 +321,7 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p, case DeviceInVendor | FTDI_GET_MDM_ST: data[0] = usb_get_modem_lines(s) | 1; data[1] = 0; - ret = 2; + p->actual_length = 2; break; case DeviceOutVendor | FTDI_SET_EVENT_CHR: /* TODO: handle it */ @@ -338,25 +336,23 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p, break; case DeviceInVendor | FTDI_GET_LATENCY: data[0] = s->latency; - ret = 1; + p->actual_length = 1; break; default: fail: DPRINTF("got unsupported/bogus control %x, value %x\n", request, value); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } -static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) +static void usb_serial_handle_data(USBDevice *dev, USBPacket *p) { USBSerialState *s = (USBSerialState *)dev; - int i, ret = 0; uint8_t devep = p->ep->nr; struct iovec *iov; uint8_t header[2]; - int first_len, len; + int i, first_len, len; switch (p->pid) { case USB_TOKEN_OUT: @@ -366,6 +362,7 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) iov = p->iov.iov + i; qemu_chr_fe_write(s->cs, iov->iov_base, iov->iov_len); } + p->actual_length = p->iov.size; break; case USB_TOKEN_IN: @@ -374,7 +371,7 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) first_len = RECV_BUF - s->recv_ptr; len = p->iov.size; if (len <= 2) { - ret = USB_RET_NAK; + p->status = USB_RET_NAK; break; } header[0] = usb_get_modem_lines(s) | 1; @@ -384,7 +381,6 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) s->event_trigger &= ~FTDI_BI; header[1] = FTDI_BI; usb_packet_copy(p, header, 2); - ret = 2; break; } else { header[1] = 0; @@ -393,7 +389,7 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) if (len > s->recv_used) len = s->recv_used; if (!len) { - ret = USB_RET_NAK; + p->status = USB_RET_NAK; break; } if (first_len > len) @@ -404,29 +400,30 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) usb_packet_copy(p, s->recv_buf, len - first_len); s->recv_used -= len; s->recv_ptr = (s->recv_ptr + len) % RECV_BUF; - ret = len + 2; break; default: DPRINTF("Bad token\n"); fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - - return ret; } static void usb_serial_handle_destroy(USBDevice *dev) { USBSerialState *s = (USBSerialState *)dev; - qemu_chr_delete(s->cs); + qemu_chr_add_handlers(s->cs, NULL, NULL, NULL, NULL); } static int usb_serial_can_read(void *opaque) { USBSerialState *s = opaque; + + if (!s->dev.attached) { + return 0; + } return RECV_BUF - s->recv_used; } @@ -469,8 +466,14 @@ static void usb_serial_event(void *opaque, int event) case CHR_EVENT_FOCUS: break; case CHR_EVENT_OPENED: - usb_serial_reset(s); - /* TODO: Reset USB port */ + if (!s->dev.attached) { + usb_device_attach(&s->dev); + } + break; + case CHR_EVENT_CLOSED: + if (s->dev.attached) { + usb_device_detach(&s->dev); + } break; } } @@ -481,6 +484,7 @@ static int usb_serial_initfn(USBDevice *dev) usb_desc_create_serial(dev); usb_desc_init(dev); + dev->auto_attach = 0; if (!s->cs) { error_report("Property chardev is required"); @@ -490,6 +494,10 @@ static int usb_serial_initfn(USBDevice *dev) qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read, usb_serial_event, s); usb_serial_handle_reset(dev); + + if (s->cs->opened && !dev->attached) { + usb_device_attach(dev); + } return 0; } diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index 1ea079176a..f26bb341f7 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -35,10 +35,10 @@ */ #include "qemu-common.h" -#include "qemu-error.h" +#include "qemu/error-report.h" #include "hw/usb.h" #include "hw/usb/desc.h" -#include "monitor.h" +#include "monitor/monitor.h" #include "hw/ccid.h" @@ -635,39 +635,38 @@ static void ccid_handle_reset(USBDevice *dev) ccid_reset(s); } -static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request, +static void ccid_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); - int ret = 0; + int ret; DPRINTF(s, 1, "got control %x, value %x\n", request, value); ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } switch (request) { /* Class specific requests. */ case InterfaceOutClass | CCID_CONTROL_ABORT: DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n"); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; case InterfaceInClass | CCID_CONTROL_GET_CLOCK_FREQUENCIES: DPRINTF(s, 1, "ccid_control get clock frequencies UNIMPLEMENTED\n"); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; case InterfaceInClass | CCID_CONTROL_GET_DATA_RATES: DPRINTF(s, 1, "ccid_control get data rates UNIMPLEMENTED\n"); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; default: DPRINTF(s, 1, "got unsupported/bogus control %x, value %x\n", request, value); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } static bool ccid_card_inserted(USBCCIDState *s) @@ -870,18 +869,13 @@ static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv) } } -/* - * Handle a single USB_TOKEN_OUT, return value returned to guest. - * Return value: - * 0 - all ok - * USB_RET_STALL - failed to handle packet - */ -static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) +static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) { CCID_Header *ccid_header; if (p->iov.size + s->bulk_out_pos > BULK_OUT_DATA_SIZE) { - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } ccid_header = (CCID_Header *)s->bulk_out_data; usb_packet_copy(p, s->bulk_out_data + s->bulk_out_pos, p->iov.size); @@ -890,7 +884,7 @@ static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) DPRINTF(s, D_VERBOSE, "usb-ccid: bulk_in: expecting more packets (%zd/%d)\n", p->iov.size, ccid_header->dwLength); - return 0; + return; } if (s->bulk_out_pos < 10) { DPRINTF(s, 1, @@ -949,60 +943,52 @@ static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) } } s->bulk_out_pos = 0; - return 0; } -static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p) +static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p) { - int ret = 0; + int len = 0; - assert(p->iov.size > 0); ccid_bulk_in_get(s); if (s->current_bulk_in != NULL) { - ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos, + len = MIN(s->current_bulk_in->len - s->current_bulk_in->pos, p->iov.size); usb_packet_copy(p, s->current_bulk_in->data + - s->current_bulk_in->pos, ret); - s->current_bulk_in->pos += ret; + s->current_bulk_in->pos, len); + s->current_bulk_in->pos += len; if (s->current_bulk_in->pos == s->current_bulk_in->len) { ccid_bulk_in_release(s); } } else { /* return when device has no data - usb 2.0 spec Table 8-4 */ - ret = USB_RET_NAK; + p->status = USB_RET_NAK; } - if (ret > 0) { + if (len) { DPRINTF(s, D_MORE_INFO, "%s: %zd/%d req/act to guest (BULK_IN)\n", - __func__, p->iov.size, ret); + __func__, p->iov.size, len); } - if (ret != USB_RET_NAK && ret < p->iov.size) { + if (len < p->iov.size) { DPRINTF(s, 1, "%s: returning short (EREMOTEIO) %d < %zd\n", - __func__, ret, p->iov.size); + __func__, len, p->iov.size); } - return ret; } -static int ccid_handle_data(USBDevice *dev, USBPacket *p) +static void ccid_handle_data(USBDevice *dev, USBPacket *p) { USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); - int ret = 0; uint8_t buf[2]; switch (p->pid) { case USB_TOKEN_OUT: - ret = ccid_handle_bulk_out(s, p); + ccid_handle_bulk_out(s, p); break; case USB_TOKEN_IN: switch (p->ep->nr) { case CCID_BULK_IN_EP: - if (!p->iov.size) { - ret = USB_RET_NAK; - } else { - ret = ccid_bulk_in_copy_to_guest(s, p); - } + ccid_bulk_in_copy_to_guest(s, p); break; case CCID_INT_IN_EP: if (s->notify_slot_change) { @@ -1010,28 +996,27 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p) buf[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange; buf[1] = s->bmSlotICCState; usb_packet_copy(p, buf, 2); - ret = 2; s->notify_slot_change = false; s->bmSlotICCState &= ~SLOT_0_CHANGED_MASK; DPRINTF(s, D_INFO, "handle_data: int_in: notify_slot_change %X, " "requested len %zd\n", s->bmSlotICCState, p->iov.size); + } else { + p->status = USB_RET_NAK; } break; default: DPRINTF(s, 1, "Bad endpoint\n"); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } break; default: DPRINTF(s, 1, "Bad token\n"); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - - return ret; } static void ccid_handle_destroy(USBDevice *dev) diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index ff48d91049..5025597673 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -8,15 +8,15 @@ */ #include "qemu-common.h" -#include "qemu-option.h" -#include "qemu-config.h" +#include "qemu/option.h" +#include "qemu/config-file.h" #include "hw/usb.h" #include "hw/usb/desc.h" #include "hw/scsi.h" -#include "console.h" -#include "monitor.h" -#include "sysemu.h" -#include "blockdev.h" +#include "ui/console.h" +#include "monitor/monitor.h" +#include "sysemu/sysemu.h" +#include "sysemu/blockdev.h" //#define DEBUG_MSD @@ -78,6 +78,7 @@ enum { STR_SERIALNUMBER, STR_CONFIG_FULL, STR_CONFIG_HIGH, + STR_CONFIG_SUPER, }; static const USBDescStrings desc_strings = { @@ -86,6 +87,7 @@ static const USBDescStrings desc_strings = { [STR_SERIALNUMBER] = "1", [STR_CONFIG_FULL] = "Full speed config (usb 1.1)", [STR_CONFIG_HIGH] = "High speed config (usb 2.0)", + [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)", }; static const USBDescIface desc_iface_full = { @@ -158,6 +160,43 @@ static const USBDescDevice desc_device_high = { }, }; +static const USBDescIface desc_iface_super = { + .bInterfaceNumber = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_MASS_STORAGE, + .bInterfaceSubClass = 0x06, /* SCSI */ + .bInterfaceProtocol = 0x50, /* Bulk */ + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x01, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 1024, + .bMaxBurst = 15, + },{ + .bEndpointAddress = USB_DIR_OUT | 0x02, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 1024, + .bMaxBurst = 15, + }, + } +}; + +static const USBDescDevice desc_device_super = { + .bcdUSB = 0x0300, + .bMaxPacketSize0 = 9, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = STR_CONFIG_SUPER, + .bmAttributes = 0xc0, + .nif = 1, + .ifs = &desc_iface_super, + }, + }, +}; + static const USBDesc desc = { .id = { .idVendor = 0x46f4, /* CRC16() of "QEMU" */ @@ -167,15 +206,16 @@ static const USBDesc desc = { .iProduct = STR_PRODUCT, .iSerialNumber = STR_SERIALNUMBER, }, - .full = &desc_device_full, - .high = &desc_device_high, - .str = desc_strings, + .full = &desc_device_full, + .high = &desc_device_high, + .super = &desc_device_super, + .str = desc_strings, }; static void usb_msd_copy_data(MSDState *s, USBPacket *p) { uint32_t len; - len = p->iov.size - p->result; + len = p->iov.size - p->actual_length; if (len > s->scsi_len) len = s->scsi_len; usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len); @@ -223,7 +263,8 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len) if (p) { usb_msd_copy_data(s, p); p = s->packet; - if (p && p->result == p->iov.size) { + if (p && p->actual_length == p->iov.size) { + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ usb_msd_packet_complete(s); } } @@ -252,7 +293,7 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r s->mode = USB_MSDM_CBW; } else { if (s->data_len) { - int len = (p->iov.size - p->result); + int len = (p->iov.size - p->actual_length); usb_packet_skip(p, len); s->data_len -= len; } @@ -260,6 +301,7 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r s->mode = USB_MSDM_CSW; } } + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ usb_msd_packet_complete(s); } else if (s->data_len == 0) { s->mode = USB_MSDM_CSW; @@ -290,14 +332,14 @@ static void usb_msd_handle_reset(USBDevice *dev) assert(s->req == NULL); if (s->packet) { - s->packet->result = USB_RET_STALL; + s->packet->status = USB_RET_STALL; usb_msd_packet_complete(s); } s->mode = USB_MSDM_CBW; } -static int usb_msd_handle_control(USBDevice *dev, USBPacket *p, +static void usb_msd_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { MSDState *s = (MSDState *)dev; @@ -305,29 +347,25 @@ static int usb_msd_handle_control(USBDevice *dev, USBPacket *p, ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } - ret = 0; switch (request) { case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: - ret = 0; break; /* Class specific requests. */ case ClassInterfaceOutRequest | MassStorageReset: /* Reset state ready for the next CBW. */ s->mode = USB_MSDM_CBW; - ret = 0; break; case ClassInterfaceRequest | GetMaxLun: data[0] = 0; - ret = 1; + p->actual_length = 1; break; default: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p) @@ -342,11 +380,10 @@ static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p) } } -static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) +static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) { MSDState *s = (MSDState *)dev; uint32_t tag; - int ret = 0; struct usb_msd_cbw cbw; uint8_t devep = p->ep->nr; @@ -393,7 +430,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) { scsi_req_continue(s->req); } - ret = p->result; break; case USB_MSDM_DATAOUT: @@ -406,7 +442,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) usb_msd_copy_data(s, p); } if (le32_to_cpu(s->csw.residue)) { - int len = p->iov.size - p->result; + int len = p->iov.size - p->actual_length; if (len) { usb_packet_skip(p, len); s->data_len -= len; @@ -415,12 +451,10 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) } } } - if (p->result < p->iov.size) { + if (p->actual_length < p->iov.size) { DPRINTF("Deferring packet %p [wait data-out]\n", p); s->packet = p; - ret = USB_RET_ASYNC; - } else { - ret = p->result; + p->status = USB_RET_ASYNC; } break; @@ -441,7 +475,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) } /* Waiting for SCSI write to complete. */ s->packet = p; - ret = USB_RET_ASYNC; + p->status = USB_RET_ASYNC; break; case USB_MSDM_CSW: @@ -453,11 +487,10 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) /* still in flight */ DPRINTF("Deferring packet %p [wait status]\n", p); s->packet = p; - ret = USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } else { usb_msd_send_status(s, p); s->mode = USB_MSDM_CBW; - ret = 13; } break; @@ -468,7 +501,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) usb_msd_copy_data(s, p); } if (le32_to_cpu(s->csw.residue)) { - int len = p->iov.size - p->result; + int len = p->iov.size - p->actual_length; if (len) { usb_packet_skip(p, len); s->data_len -= len; @@ -477,12 +510,10 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) } } } - if (p->result < p->iov.size) { + if (p->actual_length < p->iov.size) { DPRINTF("Deferring packet %p [wait data-in]\n", p); s->packet = p; - ret = USB_RET_ASYNC; - } else { - ret = p->result; + p->status = USB_RET_ASYNC; } break; @@ -495,11 +526,9 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) default: DPRINTF("Bad token\n"); fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - - return ret; } static void usb_msd_password_cb(void *opaque, int err) diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 9b02ff48fa..9a0088928f 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -10,8 +10,8 @@ */ #include "qemu-common.h" -#include "qemu-option.h" -#include "qemu-config.h" +#include "qemu/option.h" +#include "qemu/config-file.h" #include "trace.h" #include "hw/usb.h" @@ -223,7 +223,7 @@ static const USBDescDevice desc_device_high = { static const USBDesc desc = { .id = { .idVendor = 0x46f4, /* CRC16() of "QEMU" */ - .idProduct = 0x0002, + .idProduct = 0x0003, .bcdDevice = 0, .iManufacturer = STR_MANUFACTURER, .iProduct = STR_PRODUCT, @@ -256,10 +256,10 @@ static void usb_uas_send_status_bh(void *opaque) uas->status = NULL; usb_packet_copy(p, &st->status, st->length); - p->result = st->length; QTAILQ_REMOVE(&uas->results, st, next); g_free(st); + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ usb_packet_complete(&uas->dev, p); } @@ -349,6 +349,7 @@ static void usb_uas_complete_data_packet(UASRequest *req) p = req->data; req->data = NULL; req->data_async = false; + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ usb_packet_complete(&req->uas->dev, p); } @@ -357,16 +358,16 @@ static void usb_uas_copy_data(UASRequest *req) uint32_t length; length = MIN(req->buf_size - req->buf_off, - req->data->iov.size - req->data->result); + req->data->iov.size - req->data->actual_length); trace_usb_uas_xfer_data(req->uas->dev.addr, req->tag, length, - req->data->result, req->data->iov.size, + req->data->actual_length, req->data->iov.size, req->buf_off, req->buf_size); usb_packet_copy(req->data, scsi_req_get_buf(req->req) + req->buf_off, length); req->buf_off += length; req->data_off += length; - if (req->data->result == req->data->iov.size) { + if (req->data->actual_length == req->data->iov.size) { usb_uas_complete_data_packet(req); } if (req->buf_size && req->buf_off == req->buf_size) { @@ -424,6 +425,7 @@ static void usb_uas_scsi_free_request(SCSIBus *bus, void *priv) } QTAILQ_REMOVE(&uas->requests, req, next); g_free(req); + usb_uas_start_next_transfer(uas); } static UASRequest *usb_uas_find_request(UASDevice *uas, uint16_t tag) @@ -456,7 +458,6 @@ static void usb_uas_scsi_command_complete(SCSIRequest *r, uint32_t status, size_t resid) { UASRequest *req = r->hba_private; - UASDevice *uas = req->uas; trace_usb_uas_scsi_complete(req->uas->dev.addr, req->tag, status, resid); req->complete = true; @@ -465,7 +466,6 @@ static void usb_uas_scsi_command_complete(SCSIRequest *r, } usb_uas_queue_sense(req, status); scsi_req_unref(req->req); - usb_uas_start_next_transfer(uas); } static void usb_uas_scsi_request_cancelled(SCSIRequest *r) @@ -505,17 +505,17 @@ static void usb_uas_handle_reset(USBDevice *dev) } } -static int usb_uas_handle_control(USBDevice *dev, USBPacket *p, +static void usb_uas_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { int ret; ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } fprintf(stderr, "%s: unhandled control request\n", __func__); - return USB_RET_STALL; + p->status = USB_RET_STALL; } static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p) @@ -577,7 +577,6 @@ bad_target: */ usb_uas_queue_response(uas, req->tag, UAS_RC_INVALID_INFO_UNIT, 0); g_free(req); - return; } static void usb_uas_task(UASDevice *uas, uas_ui *ui) @@ -641,16 +640,15 @@ bad_target: incorrect_lun: usb_uas_queue_response(uas, tag, UAS_RC_INCORRECT_LUN, 0); - return; } -static int usb_uas_handle_data(USBDevice *dev, USBPacket *p) +static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) { UASDevice *uas = DO_UPCAST(UASDevice, dev, dev); uas_ui ui; UASStatus *st; UASRequest *req; - int length, ret = 0; + int length; switch (p->ep->nr) { case UAS_PIPE_ID_COMMAND: @@ -659,16 +657,14 @@ static int usb_uas_handle_data(USBDevice *dev, USBPacket *p) switch (ui.hdr.id) { case UAS_UI_COMMAND: usb_uas_command(uas, &ui); - ret = length; break; case UAS_UI_TASK_MGMT: usb_uas_task(uas, &ui); - ret = length; break; default: fprintf(stderr, "%s: unknown command ui: id 0x%x\n", __func__, ui.hdr.id); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } break; @@ -677,11 +673,10 @@ static int usb_uas_handle_data(USBDevice *dev, USBPacket *p) if (st == NULL) { assert(uas->status == NULL); uas->status = p; - ret = USB_RET_ASYNC; + p->status = USB_RET_ASYNC; break; } usb_packet_copy(p, &st->status, st->length); - ret = st->length; QTAILQ_REMOVE(&uas->results, st, next); g_free(st); break; @@ -690,28 +685,26 @@ static int usb_uas_handle_data(USBDevice *dev, USBPacket *p) req = (p->ep->nr == UAS_PIPE_ID_DATA_IN) ? uas->datain : uas->dataout; if (req == NULL) { fprintf(stderr, "%s: no inflight request\n", __func__); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } scsi_req_ref(req->req); req->data = p; usb_uas_copy_data(req); - if (p->result == p->iov.size || req->complete) { + if (p->actual_length == p->iov.size || req->complete) { req->data = NULL; - ret = p->result; } else { req->data_async = true; - ret = USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } scsi_req_unref(req->req); usb_uas_start_next_transfer(uas); break; default: fprintf(stderr, "%s: invalid endpoint %d\n", __func__, p->ep->nr); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } static void usb_uas_handle_destroy(USBDevice *dev) diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index ed9a5ee358..9ab368a6c5 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -26,7 +26,7 @@ * THE SOFTWARE. */ #include "hw/hw.h" -#include "console.h" +#include "ui/console.h" #include "hw/usb.h" #include "hw/usb/desc.h" @@ -43,6 +43,7 @@ typedef struct USBWacomState { USBDevice dev; + USBEndpoint *intr; QEMUPutMouseEntry *eh_entry; int dx, dy, dz, buttons_state; int x, y; @@ -137,6 +138,7 @@ static void usb_mouse_event(void *opaque, s->dz += dz1; s->buttons_state = buttons_state; s->changed = 1; + usb_wakeup(s->intr); } static void usb_wacom_event(void *opaque, @@ -150,6 +152,7 @@ static void usb_wacom_event(void *opaque, s->dz += dz; s->buttons_state = buttons_state; s->changed = 1; + usb_wakeup(s->intr); } static inline int int_clamp(int val, int vmin, int vmax) @@ -250,7 +253,7 @@ static void usb_wacom_handle_reset(USBDevice *dev) s->mode = WACOM_MODE_HID; } -static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p, +static void usb_wacom_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBWacomState *s = (USBWacomState *) dev; @@ -258,10 +261,9 @@ static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p, ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } - ret = 0; switch (request) { case WACOM_SET_REPORT: if (s->mouse_grabbed) { @@ -269,61 +271,58 @@ static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p, s->mouse_grabbed = 0; } s->mode = data[0]; - ret = 0; break; case WACOM_GET_REPORT: data[0] = 0; data[1] = s->mode; - ret = 2; + p->actual_length = 2; break; /* USB HID requests */ case HID_GET_REPORT: if (s->mode == WACOM_MODE_HID) - ret = usb_mouse_poll(s, data, length); + p->actual_length = usb_mouse_poll(s, data, length); else if (s->mode == WACOM_MODE_WACOM) - ret = usb_wacom_poll(s, data, length); + p->actual_length = usb_wacom_poll(s, data, length); break; case HID_GET_IDLE: - ret = 1; data[0] = s->idle; + p->actual_length = 1; break; case HID_SET_IDLE: s->idle = (uint8_t) (value >> 8); - ret = 0; break; default: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } -static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p) +static void usb_wacom_handle_data(USBDevice *dev, USBPacket *p) { USBWacomState *s = (USBWacomState *) dev; uint8_t buf[p->iov.size]; - int ret = 0; + int len = 0; switch (p->pid) { case USB_TOKEN_IN: if (p->ep->nr == 1) { - if (!(s->changed || s->idle)) - return USB_RET_NAK; + if (!(s->changed || s->idle)) { + p->status = USB_RET_NAK; + return; + } s->changed = 0; if (s->mode == WACOM_MODE_HID) - ret = usb_mouse_poll(s, buf, p->iov.size); + len = usb_mouse_poll(s, buf, p->iov.size); else if (s->mode == WACOM_MODE_WACOM) - ret = usb_wacom_poll(s, buf, p->iov.size); - usb_packet_copy(p, buf, ret); + len = usb_wacom_poll(s, buf, p->iov.size); + usb_packet_copy(p, buf, len); break; } /* Fall through. */ case USB_TOKEN_OUT: default: - ret = USB_RET_STALL; - break; + p->status = USB_RET_STALL; } - return ret; } static void usb_wacom_handle_destroy(USBDevice *dev) @@ -341,6 +340,7 @@ static int usb_wacom_initfn(USBDevice *dev) USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev); usb_desc_create_serial(dev); usb_desc_init(dev); + s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); s->changed = 1; return 0; } diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c new file mode 100644 index 0000000000..0eb78269f7 --- /dev/null +++ b/hw/usb/hcd-ehci-pci.c @@ -0,0 +1,228 @@ +/* + * QEMU USB EHCI Emulation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or(at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw/usb/hcd-ehci.h" +#include "qemu/range.h" + +typedef struct EHCIPCIInfo { + const char *name; + uint16_t vendor_id; + uint16_t device_id; + uint8_t revision; +} EHCIPCIInfo; + +static int usb_ehci_pci_initfn(PCIDevice *dev) +{ + EHCIPCIState *i = PCI_EHCI(dev); + EHCIState *s = &i->ehci; + uint8_t *pci_conf = dev->config; + + pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20); + + /* capabilities pointer */ + pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00); + /* pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50); */ + + pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */ + pci_set_byte(&pci_conf[PCI_MIN_GNT], 0); + pci_set_byte(&pci_conf[PCI_MAX_LAT], 0); + + /* pci_conf[0x50] = 0x01; *//* power management caps */ + + pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); /* release # (2.1.4) */ + pci_set_byte(&pci_conf[0x61], 0x20); /* frame length adjustment (2.1.5) */ + pci_set_word(&pci_conf[0x62], 0x00); /* port wake up capability (2.1.6) */ + + pci_conf[0x64] = 0x00; + pci_conf[0x65] = 0x00; + pci_conf[0x66] = 0x00; + pci_conf[0x67] = 0x00; + pci_conf[0x68] = 0x01; + pci_conf[0x69] = 0x00; + pci_conf[0x6a] = 0x00; + pci_conf[0x6b] = 0x00; /* USBLEGSUP */ + pci_conf[0x6c] = 0x00; + pci_conf[0x6d] = 0x00; + pci_conf[0x6e] = 0x00; + pci_conf[0x6f] = 0xc0; /* USBLEFCTLSTS */ + + s->caps[0x09] = 0x68; /* EECP */ + + s->irq = dev->irq[3]; + s->dma = pci_dma_context(dev); + + s->capsbase = 0x00; + s->opregbase = 0x20; + + usb_ehci_initfn(s, DEVICE(dev)); + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem); + + return 0; +} + +static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr, + uint32_t val, int l) +{ + EHCIPCIState *i = PCI_EHCI(dev); + bool busmaster; + + pci_default_write_config(dev, addr, val, l); + + if (!range_covers_byte(addr, l, PCI_COMMAND)) { + return; + } + busmaster = pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_MASTER; + i->ehci.dma = busmaster ? pci_dma_context(dev) : NULL; +} + +static Property ehci_pci_properties[] = { + DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128), + DEFINE_PROP_END_OF_LIST(), +}; + +static const VMStateDescription vmstate_ehci_pci = { + .name = "ehci", + .version_id = 2, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState), + VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState), + VMSTATE_END_OF_LIST() + } +}; + +static void ehci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = usb_ehci_pci_initfn; + k->class_id = PCI_CLASS_SERIAL_USB; + k->config_write = usb_ehci_pci_write_config; + k->no_hotplug = 1; + dc->vmsd = &vmstate_ehci_pci; + dc->props = ehci_pci_properties; +} + +static const TypeInfo ehci_pci_type_info = { + .name = TYPE_PCI_EHCI, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(EHCIPCIState), + .abstract = true, + .class_init = ehci_class_init, +}; + +static void ehci_data_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + EHCIPCIInfo *i = data; + + k->vendor_id = i->vendor_id; + k->device_id = i->device_id; + k->revision = i->revision; +} + +static struct EHCIPCIInfo ehci_pci_info[] = { + { + .name = "usb-ehci", + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */ + .revision = 0x10, + },{ + .name = "ich9-usb-ehci1", /* 00:1d.7 */ + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1, + .revision = 0x03, + },{ + .name = "ich9-usb-ehci2", /* 00:1a.7 */ + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI2, + .revision = 0x03, + } +}; + +static void ehci_pci_register_types(void) +{ + TypeInfo ehci_type_info = { + .parent = TYPE_PCI_EHCI, + .class_init = ehci_data_class_init, + }; + int i; + + type_register_static(&ehci_pci_type_info); + + for (i = 0; i < ARRAY_SIZE(ehci_pci_info); i++) { + ehci_type_info.name = ehci_pci_info[i].name; + ehci_type_info.class_data = ehci_pci_info + i; + type_register(&ehci_type_info); + } +} + +type_init(ehci_pci_register_types) + +struct ehci_companions { + const char *name; + int func; + int port; +}; + +static const struct ehci_companions ich9_1d[] = { + { .name = "ich9-usb-uhci1", .func = 0, .port = 0 }, + { .name = "ich9-usb-uhci2", .func = 1, .port = 2 }, + { .name = "ich9-usb-uhci3", .func = 2, .port = 4 }, +}; + +static const struct ehci_companions ich9_1a[] = { + { .name = "ich9-usb-uhci4", .func = 0, .port = 0 }, + { .name = "ich9-usb-uhci5", .func = 1, .port = 2 }, + { .name = "ich9-usb-uhci6", .func = 2, .port = 4 }, +}; + +int ehci_create_ich9_with_companions(PCIBus *bus, int slot) +{ + const struct ehci_companions *comp; + PCIDevice *ehci, *uhci; + BusState *usbbus; + const char *name; + int i; + + switch (slot) { + case 0x1d: + name = "ich9-usb-ehci1"; + comp = ich9_1d; + break; + case 0x1a: + name = "ich9-usb-ehci2"; + comp = ich9_1a; + break; + default: + return -1; + } + + ehci = pci_create_multifunction(bus, PCI_DEVFN(slot, 7), true, name); + qdev_init_nofail(&ehci->qdev); + usbbus = QLIST_FIRST(&ehci->qdev.child_bus); + + for (i = 0; i < 3; i++) { + uhci = pci_create_multifunction(bus, PCI_DEVFN(slot, comp[i].func), + true, comp[i].name); + qdev_prop_set_string(&uhci->qdev, "masterbus", usbbus->name); + qdev_prop_set_uint32(&uhci->qdev, "firstport", comp[i].port); + qdev_init_nofail(&uhci->qdev); + } + return 0; +} diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c new file mode 100644 index 0000000000..b68a66a63b --- /dev/null +++ b/hw/usb/hcd-ehci-sysbus.c @@ -0,0 +1,105 @@ +/* + * QEMU USB EHCI Emulation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or(at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw/usb/hcd-ehci.h" + +static const VMStateDescription vmstate_ehci_sysbus = { + .name = "ehci-sysbus", + .version_id = 2, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(ehci, EHCISysBusState, 2, vmstate_ehci, EHCIState), + VMSTATE_END_OF_LIST() + } +}; + +static Property ehci_sysbus_properties[] = { + DEFINE_PROP_UINT32("maxframes", EHCISysBusState, ehci.maxframes, 128), + DEFINE_PROP_END_OF_LIST(), +}; + +static int usb_ehci_sysbus_initfn(SysBusDevice *dev) +{ + EHCISysBusState *i = SYS_BUS_EHCI(dev); + SysBusEHCIClass *sec = SYS_BUS_EHCI_GET_CLASS(dev); + EHCIState *s = &i->ehci; + + s->capsbase = sec->capsbase; + s->opregbase = sec->opregbase; + s->dma = &dma_context_memory; + + usb_ehci_initfn(s, DEVICE(dev)); + sysbus_init_irq(dev, &s->irq); + sysbus_init_mmio(dev, &s->mem); + return 0; +} + +static void ehci_sysbus_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = usb_ehci_sysbus_initfn; + dc->vmsd = &vmstate_ehci_sysbus; + dc->props = ehci_sysbus_properties; +} + +static const TypeInfo ehci_type_info = { + .name = TYPE_SYS_BUS_EHCI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(EHCISysBusState), + .abstract = true, + .class_init = ehci_sysbus_class_init, + .class_size = sizeof(SysBusEHCIClass), +}; + +static void ehci_xlnx_class_init(ObjectClass *oc, void *data) +{ + SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + + sec->capsbase = 0x100; + sec->opregbase = 0x140; +} + +static const TypeInfo ehci_xlnx_type_info = { + .name = "xlnx,ps7-usb", + .parent = TYPE_SYS_BUS_EHCI, + .class_init = ehci_xlnx_class_init, +}; + +static void ehci_exynos4210_class_init(ObjectClass *oc, void *data) +{ + SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + + sec->capsbase = 0x0; + sec->opregbase = 0x10; +} + +static const TypeInfo ehci_exynos4210_type_info = { + .name = TYPE_EXYNOS4210_EHCI, + .parent = TYPE_SYS_BUS_EHCI, + .class_init = ehci_exynos4210_class_init, +}; + +static void ehci_sysbus_register_types(void) +{ + type_register_static(&ehci_type_info); + type_register_static(&ehci_xlnx_type_info); + type_register_static(&ehci_exynos4210_type_info); +} + +type_init(ehci_sysbus_register_types) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 104c21d315..320b7e7239 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -2,6 +2,11 @@ * QEMU USB EHCI Emulation * * Copyright(c) 2008 Emutex Ltd. (address@hidden) + * Copyright(c) 2011-2012 Red Hat, Inc. + * + * Red Hat Authors: + * Gerd Hoffmann <kraxel@redhat.com> + * Hans de Goede <hdegoede@redhat.com> * * EHCI project was started by Mark Burkley, with contributions by * Niels de Vos. David S. Ahern continued working on it. Kevin Wolf, @@ -22,40 +27,18 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "hw/hw.h" -#include "qemu-timer.h" -#include "hw/usb.h" -#include "hw/pci.h" -#include "monitor.h" -#include "trace.h" -#include "dma.h" - -#define EHCI_DEBUG 0 - -#if EHCI_DEBUG -#define DPRINTF printf -#else -#define DPRINTF(...) -#endif - -/* internal processing - reset HC to try and recover */ -#define USB_RET_PROCERR (-99) - -#define MMIO_SIZE 0x1000 +#include "hw/usb/hcd-ehci.h" /* Capability Registers Base Address - section 2.2 */ -#define CAPREGBASE 0x0000 -#define CAPLENGTH CAPREGBASE + 0x0000 // 1-byte, 0x0001 reserved -#define HCIVERSION CAPREGBASE + 0x0002 // 2-bytes, i/f version # -#define HCSPARAMS CAPREGBASE + 0x0004 // 4-bytes, structural params -#define HCCPARAMS CAPREGBASE + 0x0008 // 4-bytes, capability params +#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */ +#define HCIVERSION 0x0002 /* 2-bytes, i/f version # */ +#define HCSPARAMS 0x0004 /* 4-bytes, structural params */ +#define HCCPARAMS 0x0008 /* 4-bytes, capability params */ #define EECP HCCPARAMS + 1 -#define HCSPPORTROUTE1 CAPREGBASE + 0x000c -#define HCSPPORTROUTE2 CAPREGBASE + 0x0010 +#define HCSPPORTROUTE1 0x000c +#define HCSPPORTROUTE2 0x0010 -#define OPREGBASE 0x0020 // Operational Registers Base Address - -#define USBCMD OPREGBASE + 0x0000 +#define USBCMD 0x0000 #define USBCMD_RUNSTOP (1 << 0) // run / Stop #define USBCMD_HCRESET (1 << 1) // HC Reset #define USBCMD_FLS (3 << 2) // Frame List Size @@ -69,7 +52,7 @@ #define USBCMD_ITC (0x7f << 16) // Int Threshold Control #define USBCMD_ITC_SH 16 // Int Threshold Control Shift -#define USBSTS OPREGBASE + 0x0004 +#define USBSTS 0x0004 #define USBSTS_RO_MASK 0x0000003f #define USBSTS_INT (1 << 0) // USB Interrupt #define USBSTS_ERRINT (1 << 1) // Error Interrupt @@ -86,20 +69,17 @@ * Interrupt enable bits correspond to the interrupt active bits in USBSTS * so no need to redefine here. */ -#define USBINTR OPREGBASE + 0x0008 +#define USBINTR 0x0008 #define USBINTR_MASK 0x0000003f -#define FRINDEX OPREGBASE + 0x000c -#define CTRLDSSEGMENT OPREGBASE + 0x0010 -#define PERIODICLISTBASE OPREGBASE + 0x0014 -#define ASYNCLISTADDR OPREGBASE + 0x0018 +#define FRINDEX 0x000c +#define CTRLDSSEGMENT 0x0010 +#define PERIODICLISTBASE 0x0014 +#define ASYNCLISTADDR 0x0018 #define ASYNCLISTADDR_MASK 0xffffffe0 -#define CONFIGFLAG OPREGBASE + 0x0040 +#define CONFIGFLAG 0x0040 -#define PORTSC (OPREGBASE + 0x0044) -#define PORTSC_BEGIN PORTSC -#define PORTSC_END (PORTSC + 4 * NB_PORTS) /* * Bits that are reserved or are read-only are masked out of values * written to us by software @@ -129,11 +109,13 @@ #define FRAME_TIMER_FREQ 1000 #define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ) +#define UFRAME_TIMER_NS (FRAME_TIMER_NS / 8) #define NB_MAXINTRATE 8 // Max rate at which controller issues ints -#define NB_PORTS 6 // Number of downstream ports #define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction #define MAX_QH 100 // Max allowable queue heads in a chain +#define MIN_UFR_PER_TICK 24 /* Min frames to process when catching up */ +#define PERIODIC_ACTIVE 512 /* Micro-frames */ /* Internal periodic / asynchronous schedule state machine states */ @@ -167,274 +149,6 @@ typedef enum { #define NLPTR_TYPE_STITD 2 // split xaction, isoc xfer descriptor #define NLPTR_TYPE_FSTN 3 // frame span traversal node - -/* EHCI spec version 1.0 Section 3.3 - */ -typedef struct EHCIitd { - uint32_t next; - - uint32_t transact[8]; -#define ITD_XACT_ACTIVE (1 << 31) -#define ITD_XACT_DBERROR (1 << 30) -#define ITD_XACT_BABBLE (1 << 29) -#define ITD_XACT_XACTERR (1 << 28) -#define ITD_XACT_LENGTH_MASK 0x0fff0000 -#define ITD_XACT_LENGTH_SH 16 -#define ITD_XACT_IOC (1 << 15) -#define ITD_XACT_PGSEL_MASK 0x00007000 -#define ITD_XACT_PGSEL_SH 12 -#define ITD_XACT_OFFSET_MASK 0x00000fff - - uint32_t bufptr[7]; -#define ITD_BUFPTR_MASK 0xfffff000 -#define ITD_BUFPTR_SH 12 -#define ITD_BUFPTR_EP_MASK 0x00000f00 -#define ITD_BUFPTR_EP_SH 8 -#define ITD_BUFPTR_DEVADDR_MASK 0x0000007f -#define ITD_BUFPTR_DEVADDR_SH 0 -#define ITD_BUFPTR_DIRECTION (1 << 11) -#define ITD_BUFPTR_MAXPKT_MASK 0x000007ff -#define ITD_BUFPTR_MAXPKT_SH 0 -#define ITD_BUFPTR_MULT_MASK 0x00000003 -#define ITD_BUFPTR_MULT_SH 0 -} EHCIitd; - -/* EHCI spec version 1.0 Section 3.4 - */ -typedef struct EHCIsitd { - uint32_t next; // Standard next link pointer - uint32_t epchar; -#define SITD_EPCHAR_IO (1 << 31) -#define SITD_EPCHAR_PORTNUM_MASK 0x7f000000 -#define SITD_EPCHAR_PORTNUM_SH 24 -#define SITD_EPCHAR_HUBADD_MASK 0x007f0000 -#define SITD_EPCHAR_HUBADDR_SH 16 -#define SITD_EPCHAR_EPNUM_MASK 0x00000f00 -#define SITD_EPCHAR_EPNUM_SH 8 -#define SITD_EPCHAR_DEVADDR_MASK 0x0000007f - - uint32_t uframe; -#define SITD_UFRAME_CMASK_MASK 0x0000ff00 -#define SITD_UFRAME_CMASK_SH 8 -#define SITD_UFRAME_SMASK_MASK 0x000000ff - - uint32_t results; -#define SITD_RESULTS_IOC (1 << 31) -#define SITD_RESULTS_PGSEL (1 << 30) -#define SITD_RESULTS_TBYTES_MASK 0x03ff0000 -#define SITD_RESULTS_TYBYTES_SH 16 -#define SITD_RESULTS_CPROGMASK_MASK 0x0000ff00 -#define SITD_RESULTS_CPROGMASK_SH 8 -#define SITD_RESULTS_ACTIVE (1 << 7) -#define SITD_RESULTS_ERR (1 << 6) -#define SITD_RESULTS_DBERR (1 << 5) -#define SITD_RESULTS_BABBLE (1 << 4) -#define SITD_RESULTS_XACTERR (1 << 3) -#define SITD_RESULTS_MISSEDUF (1 << 2) -#define SITD_RESULTS_SPLITXSTATE (1 << 1) - - uint32_t bufptr[2]; -#define SITD_BUFPTR_MASK 0xfffff000 -#define SITD_BUFPTR_CURROFF_MASK 0x00000fff -#define SITD_BUFPTR_TPOS_MASK 0x00000018 -#define SITD_BUFPTR_TPOS_SH 3 -#define SITD_BUFPTR_TCNT_MASK 0x00000007 - - uint32_t backptr; // Standard next link pointer -} EHCIsitd; - -/* EHCI spec version 1.0 Section 3.5 - */ -typedef struct EHCIqtd { - uint32_t next; // Standard next link pointer - uint32_t altnext; // Standard next link pointer - uint32_t token; -#define QTD_TOKEN_DTOGGLE (1 << 31) -#define QTD_TOKEN_TBYTES_MASK 0x7fff0000 -#define QTD_TOKEN_TBYTES_SH 16 -#define QTD_TOKEN_IOC (1 << 15) -#define QTD_TOKEN_CPAGE_MASK 0x00007000 -#define QTD_TOKEN_CPAGE_SH 12 -#define QTD_TOKEN_CERR_MASK 0x00000c00 -#define QTD_TOKEN_CERR_SH 10 -#define QTD_TOKEN_PID_MASK 0x00000300 -#define QTD_TOKEN_PID_SH 8 -#define QTD_TOKEN_ACTIVE (1 << 7) -#define QTD_TOKEN_HALT (1 << 6) -#define QTD_TOKEN_DBERR (1 << 5) -#define QTD_TOKEN_BABBLE (1 << 4) -#define QTD_TOKEN_XACTERR (1 << 3) -#define QTD_TOKEN_MISSEDUF (1 << 2) -#define QTD_TOKEN_SPLITXSTATE (1 << 1) -#define QTD_TOKEN_PING (1 << 0) - - uint32_t bufptr[5]; // Standard buffer pointer -#define QTD_BUFPTR_MASK 0xfffff000 -#define QTD_BUFPTR_SH 12 -} EHCIqtd; - -/* EHCI spec version 1.0 Section 3.6 - */ -typedef struct EHCIqh { - uint32_t next; // Standard next link pointer - - /* endpoint characteristics */ - uint32_t epchar; -#define QH_EPCHAR_RL_MASK 0xf0000000 -#define QH_EPCHAR_RL_SH 28 -#define QH_EPCHAR_C (1 << 27) -#define QH_EPCHAR_MPLEN_MASK 0x07FF0000 -#define QH_EPCHAR_MPLEN_SH 16 -#define QH_EPCHAR_H (1 << 15) -#define QH_EPCHAR_DTC (1 << 14) -#define QH_EPCHAR_EPS_MASK 0x00003000 -#define QH_EPCHAR_EPS_SH 12 -#define EHCI_QH_EPS_FULL 0 -#define EHCI_QH_EPS_LOW 1 -#define EHCI_QH_EPS_HIGH 2 -#define EHCI_QH_EPS_RESERVED 3 - -#define QH_EPCHAR_EP_MASK 0x00000f00 -#define QH_EPCHAR_EP_SH 8 -#define QH_EPCHAR_I (1 << 7) -#define QH_EPCHAR_DEVADDR_MASK 0x0000007f -#define QH_EPCHAR_DEVADDR_SH 0 - - /* endpoint capabilities */ - uint32_t epcap; -#define QH_EPCAP_MULT_MASK 0xc0000000 -#define QH_EPCAP_MULT_SH 30 -#define QH_EPCAP_PORTNUM_MASK 0x3f800000 -#define QH_EPCAP_PORTNUM_SH 23 -#define QH_EPCAP_HUBADDR_MASK 0x007f0000 -#define QH_EPCAP_HUBADDR_SH 16 -#define QH_EPCAP_CMASK_MASK 0x0000ff00 -#define QH_EPCAP_CMASK_SH 8 -#define QH_EPCAP_SMASK_MASK 0x000000ff -#define QH_EPCAP_SMASK_SH 0 - - uint32_t current_qtd; // Standard next link pointer - uint32_t next_qtd; // Standard next link pointer - uint32_t altnext_qtd; -#define QH_ALTNEXT_NAKCNT_MASK 0x0000001e -#define QH_ALTNEXT_NAKCNT_SH 1 - - uint32_t token; // Same as QTD token - uint32_t bufptr[5]; // Standard buffer pointer -#define BUFPTR_CPROGMASK_MASK 0x000000ff -#define BUFPTR_FRAMETAG_MASK 0x0000001f -#define BUFPTR_SBYTES_MASK 0x00000fe0 -#define BUFPTR_SBYTES_SH 5 -} EHCIqh; - -/* EHCI spec version 1.0 Section 3.7 - */ -typedef struct EHCIfstn { - uint32_t next; // Standard next link pointer - uint32_t backptr; // Standard next link pointer -} EHCIfstn; - -typedef struct EHCIPacket EHCIPacket; -typedef struct EHCIQueue EHCIQueue; -typedef struct EHCIState EHCIState; - -enum async_state { - EHCI_ASYNC_NONE = 0, - EHCI_ASYNC_INFLIGHT, - EHCI_ASYNC_FINISHED, -}; - -struct EHCIPacket { - EHCIQueue *queue; - QTAILQ_ENTRY(EHCIPacket) next; - - EHCIqtd qtd; /* copy of current QTD (being worked on) */ - uint32_t qtdaddr; /* address QTD read from */ - - USBPacket packet; - QEMUSGList sgl; - int pid; - uint32_t tbytes; - enum async_state async; - int usb_status; -}; - -struct EHCIQueue { - EHCIState *ehci; - QTAILQ_ENTRY(EHCIQueue) next; - uint32_t seen; - uint64_t ts; - int async; - int revalidate; - - /* cached data from guest - needs to be flushed - * when guest removes an entry (doorbell, handshake sequence) - */ - EHCIqh qh; /* copy of current QH (being worked on) */ - uint32_t qhaddr; /* address QH read from */ - uint32_t qtdaddr; /* address QTD read from */ - USBDevice *dev; - QTAILQ_HEAD(, EHCIPacket) packets; -}; - -typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead; - -struct EHCIState { - PCIDevice dev; - USBBus bus; - qemu_irq irq; - MemoryRegion mem; - int companion_count; - - /* properties */ - uint32_t maxframes; - - /* - * EHCI spec version 1.0 Section 2.3 - * Host Controller Operational Registers - */ - union { - uint8_t mmio[MMIO_SIZE]; - struct { - uint8_t cap[OPREGBASE]; - uint32_t usbcmd; - uint32_t usbsts; - uint32_t usbintr; - uint32_t frindex; - uint32_t ctrldssegment; - uint32_t periodiclistbase; - uint32_t asynclistaddr; - uint32_t notused[9]; - uint32_t configflag; - uint32_t portsc[NB_PORTS]; - }; - }; - - /* - * Internal states, shadow registers, etc - */ - QEMUTimer *frame_timer; - QEMUBH *async_bh; - uint32_t astate; /* Current state in asynchronous schedule */ - uint32_t pstate; /* Current state in periodic schedule */ - USBPort ports[NB_PORTS]; - USBPort *companion_ports[NB_PORTS]; - uint32_t usbsts_pending; - uint32_t usbsts_frindex; - EHCIQueueHead aqueues; - EHCIQueueHead pqueues; - - /* which address to look at next */ - uint32_t a_fetch_addr; - uint32_t p_fetch_addr; - - USBPacket ipacket; - QEMUSGList isgl; - - uint64_t last_run_ns; - uint32_t async_stepdown; -}; - #define SET_LAST_RUN_CLOCK(s) \ (s)->last_run_ns = qemu_get_clock_ns(vm_clock); @@ -466,25 +180,21 @@ static const char *ehci_state_names[] = { }; static const char *ehci_mmio_names[] = { - [CAPLENGTH] = "CAPLENGTH", - [HCIVERSION] = "HCIVERSION", - [HCSPARAMS] = "HCSPARAMS", - [HCCPARAMS] = "HCCPARAMS", [USBCMD] = "USBCMD", [USBSTS] = "USBSTS", [USBINTR] = "USBINTR", [FRINDEX] = "FRINDEX", [PERIODICLISTBASE] = "P-LIST BASE", [ASYNCLISTADDR] = "A-LIST ADDR", - [PORTSC_BEGIN] = "PORTSC #0", - [PORTSC_BEGIN + 4] = "PORTSC #1", - [PORTSC_BEGIN + 8] = "PORTSC #2", - [PORTSC_BEGIN + 12] = "PORTSC #3", - [PORTSC_BEGIN + 16] = "PORTSC #4", - [PORTSC_BEGIN + 20] = "PORTSC #5", [CONFIGFLAG] = "CONFIGFLAG", }; +static int ehci_state_executing(EHCIQueue *q); +static int ehci_state_writeback(EHCIQueue *q); +static int ehci_state_advqueue(EHCIQueue *q); +static int ehci_fill_queue(EHCIPacket *p); +static void ehci_free_packet(EHCIPacket *p); + static const char *nr2str(const char **n, size_t len, uint32_t nr) { if (nr < len && n[nr] != NULL) { @@ -499,7 +209,7 @@ static const char *state2str(uint32_t state) return nr2str(ehci_state_names, ARRAY_SIZE(ehci_state_names), state); } -static const char *addr2str(target_phys_addr_t addr) +static const char *addr2str(hwaddr addr) { return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr); } @@ -575,7 +285,12 @@ static inline void ehci_update_irq(EHCIState *s) /* flag interrupt condition */ static inline void ehci_raise_irq(EHCIState *s, int intr) { - s->usbsts_pending |= intr; + if (intr & (USBSTS_PCD | USBSTS_FLR | USBSTS_HSE)) { + s->usbsts |= intr; + ehci_update_irq(s); + } else { + s->usbsts_pending |= intr; + } } /* @@ -653,7 +368,7 @@ static int ehci_get_fetch_addr(EHCIState *s, int async) return async ? s->a_fetch_addr : s->p_fetch_addr; } -static void ehci_trace_qh(EHCIQueue *q, target_phys_addr_t addr, EHCIqh *qh) +static void ehci_trace_qh(EHCIQueue *q, hwaddr addr, EHCIqh *qh) { /* need three here due to argument count limits */ trace_usb_ehci_qh_ptrs(q, addr, qh->next, @@ -671,7 +386,7 @@ static void ehci_trace_qh(EHCIQueue *q, target_phys_addr_t addr, EHCIqh *qh) (bool)(qh->epchar & QH_EPCHAR_I)); } -static void ehci_trace_qtd(EHCIQueue *q, target_phys_addr_t addr, EHCIqtd *qtd) +static void ehci_trace_qtd(EHCIQueue *q, hwaddr addr, EHCIqtd *qtd) { /* need three here due to argument count limits */ trace_usb_ehci_qtd_ptrs(q, addr, qtd->next, qtd->altnext); @@ -688,7 +403,7 @@ static void ehci_trace_qtd(EHCIQueue *q, target_phys_addr_t addr, EHCIqtd *qtd) (bool)(qtd->token & QTD_TOKEN_XACTERR)); } -static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd) +static void ehci_trace_itd(EHCIState *s, hwaddr addr, EHCIitd *itd) { trace_usb_ehci_itd(addr, itd->next, get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT), @@ -697,13 +412,19 @@ static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd) get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR)); } -static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr, +static void ehci_trace_sitd(EHCIState *s, hwaddr addr, EHCIsitd *sitd) { trace_usb_ehci_sitd(addr, sitd->next, (bool)(sitd->results & SITD_RESULTS_ACTIVE)); } +static void ehci_trace_guest_bug(EHCIState *s, const char *message) +{ + trace_usb_ehci_guest_bug(message); + fprintf(stderr, "ehci warning: %s\n", message); +} + static inline bool ehci_enabled(EHCIState *s) { return s->usbcmd & USBCMD_RUNSTOP; @@ -719,6 +440,136 @@ static inline bool ehci_periodic_enabled(EHCIState *s) return ehci_enabled(s) && (s->usbcmd & USBCMD_PSE); } +/* Get an array of dwords from main memory */ +static inline int get_dwords(EHCIState *ehci, uint32_t addr, + uint32_t *buf, int num) +{ + int i; + + if (!ehci->dma) { + ehci_raise_irq(ehci, USBSTS_HSE); + ehci->usbcmd &= ~USBCMD_RUNSTOP; + trace_usb_ehci_dma_error(); + return -1; + } + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { + dma_memory_read(ehci->dma, addr, buf, sizeof(*buf)); + *buf = le32_to_cpu(*buf); + } + + return num; +} + +/* Put an array of dwords in to main memory */ +static inline int put_dwords(EHCIState *ehci, uint32_t addr, + uint32_t *buf, int num) +{ + int i; + + if (!ehci->dma) { + ehci_raise_irq(ehci, USBSTS_HSE); + ehci->usbcmd &= ~USBCMD_RUNSTOP; + trace_usb_ehci_dma_error(); + return -1; + } + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { + uint32_t tmp = cpu_to_le32(*buf); + dma_memory_write(ehci->dma, addr, &tmp, sizeof(tmp)); + } + + return num; +} + +static int ehci_get_pid(EHCIqtd *qtd) +{ + switch (get_field(qtd->token, QTD_TOKEN_PID)) { + case 0: + return USB_TOKEN_OUT; + case 1: + return USB_TOKEN_IN; + case 2: + return USB_TOKEN_SETUP; + default: + fprintf(stderr, "bad token\n"); + return 0; + } +} + +static bool ehci_verify_qh(EHCIQueue *q, EHCIqh *qh) +{ + uint32_t devaddr = get_field(qh->epchar, QH_EPCHAR_DEVADDR); + uint32_t endp = get_field(qh->epchar, QH_EPCHAR_EP); + if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) || + (endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) || + (qh->current_qtd != q->qh.current_qtd) || + (q->async && qh->next_qtd != q->qh.next_qtd) || + (memcmp(&qh->altnext_qtd, &q->qh.altnext_qtd, + 7 * sizeof(uint32_t)) != 0) || + (q->dev != NULL && q->dev->addr != devaddr)) { + return false; + } else { + return true; + } +} + +static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd) +{ + if (p->qtdaddr != p->queue->qtdaddr || + (p->queue->async && !NLPTR_TBIT(p->qtd.next) && + (p->qtd.next != qtd->next)) || + (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd->altnext)) || + p->qtd.token != qtd->token || + p->qtd.bufptr[0] != qtd->bufptr[0]) { + return false; + } else { + return true; + } +} + +static bool ehci_verify_pid(EHCIQueue *q, EHCIqtd *qtd) +{ + int ep = get_field(q->qh.epchar, QH_EPCHAR_EP); + int pid = ehci_get_pid(qtd); + + /* Note the pid changing is normal for ep 0 (the control ep) */ + if (q->last_pid && ep != 0 && pid != q->last_pid) { + return false; + } else { + return true; + } +} + +/* Finish executing and writeback a packet outside of the regular + fetchqh -> fetchqtd -> execute -> writeback cycle */ +static void ehci_writeback_async_complete_packet(EHCIPacket *p) +{ + EHCIQueue *q = p->queue; + EHCIqtd qtd; + EHCIqh qh; + int state; + + /* Verify the qh + qtd, like we do when going through fetchqh & fetchqtd */ + get_dwords(q->ehci, NLPTR_GET(q->qhaddr), + (uint32_t *) &qh, sizeof(EHCIqh) >> 2); + get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), + (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2); + if (!ehci_verify_qh(q, &qh) || !ehci_verify_qtd(p, &qtd)) { + p->async = EHCI_ASYNC_INITIALIZED; + ehci_free_packet(p); + return; + } + + state = ehci_get_state(q->ehci, q->async); + ehci_state_executing(q); + ehci_state_writeback(q); /* Frees the packet! */ + if (!(q->qh.token & QTD_TOKEN_HALT)) { + ehci_state_advqueue(q); + } + ehci_set_state(q->ehci, q->async, state); +} + /* packet management */ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q) @@ -735,9 +586,19 @@ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q) static void ehci_free_packet(EHCIPacket *p) { + if (p->async == EHCI_ASYNC_FINISHED) { + ehci_writeback_async_complete_packet(p); + return; + } trace_usb_ehci_packet_action(p->queue, p, "free"); + if (p->async == EHCI_ASYNC_INITIALIZED) { + usb_packet_unmap(&p->packet, &p->sgl); + qemu_sglist_destroy(&p->sgl); + } if (p->async == EHCI_ASYNC_INFLIGHT) { usb_cancel_packet(&p->packet); + usb_packet_unmap(&p->packet, &p->sgl); + qemu_sglist_destroy(&p->sgl); } QTAILQ_REMOVE(&p->queue->packets, p, next); usb_packet_cleanup(&p->packet); @@ -761,14 +622,59 @@ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async) return q; } -static void ehci_free_queue(EHCIQueue *q) +static void ehci_queue_stopped(EHCIQueue *q) +{ + int endp = get_field(q->qh.epchar, QH_EPCHAR_EP); + + if (!q->last_pid || !q->dev) { + return; + } + + usb_device_ep_stopped(q->dev, usb_ep_get(q->dev, q->last_pid, endp)); +} + +static int ehci_cancel_queue(EHCIQueue *q) { - EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues; EHCIPacket *p; + int packets = 0; - trace_usb_ehci_queue_action(q, "free"); - while ((p = QTAILQ_FIRST(&q->packets)) != NULL) { + p = QTAILQ_FIRST(&q->packets); + if (p == NULL) { + goto leave; + } + + trace_usb_ehci_queue_action(q, "cancel"); + do { ehci_free_packet(p); + packets++; + } while ((p = QTAILQ_FIRST(&q->packets)) != NULL); + +leave: + ehci_queue_stopped(q); + return packets; +} + +static int ehci_reset_queue(EHCIQueue *q) +{ + int packets; + + trace_usb_ehci_queue_action(q, "reset"); + packets = ehci_cancel_queue(q); + q->dev = NULL; + q->qtdaddr = 0; + q->last_pid = 0; + return packets; +} + +static void ehci_free_queue(EHCIQueue *q, const char *warn) +{ + EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues; + int cancelled; + + trace_usb_ehci_queue_action(q, "free"); + cancelled = ehci_cancel_queue(q); + if (warn && cancelled > 0) { + ehci_trace_guest_bug(q->ehci, warn); } QTAILQ_REMOVE(head, q, next); g_free(q); @@ -788,20 +694,10 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, return NULL; } -static void ehci_queues_tag_unused_async(EHCIState *ehci) -{ - EHCIQueue *q; - - QTAILQ_FOREACH(q, &ehci->aqueues, next) { - if (!q->seen) { - q->revalidate = 1; - } - } -} - static void ehci_queues_rip_unused(EHCIState *ehci, int async) { EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; + const char *warn = async ? "guest unlinked busy QH" : NULL; uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4; EHCIQueue *q, *tmp; @@ -814,7 +710,19 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async) if (ehci->last_run_ns < q->ts + maxage) { continue; } - ehci_free_queue(q); + ehci_free_queue(q, warn); + } +} + +static void ehci_queues_rip_unseen(EHCIState *ehci, int async) +{ + EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; + EHCIQueue *q, *tmp; + + QTAILQ_FOREACH_SAFE(q, head, next, tmp) { + if (!q->seen) { + ehci_free_queue(q, NULL); + } } } @@ -827,17 +735,18 @@ static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async) if (q->dev != dev) { continue; } - ehci_free_queue(q); + ehci_free_queue(q, NULL); } } static void ehci_queues_rip_all(EHCIState *ehci, int async) { EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; + const char *warn = async ? "guest stopped busy async schedule" : NULL; EHCIQueue *q, *tmp; QTAILQ_FOREACH_SAFE(q, head, next, tmp) { - ehci_free_queue(q); + ehci_free_queue(q, warn); } } @@ -862,7 +771,6 @@ static void ehci_attach(USBPort *port) *portsc |= PORTSC_CSC; ehci_raise_irq(s, USBSTS_PCD); - ehci_commit_irq(s); } static void ehci_detach(USBPort *port) @@ -892,7 +800,6 @@ static void ehci_detach(USBPort *port) *portsc |= PORTSC_CSC; ehci_raise_irq(s, USBSTS_PCD); - ehci_commit_irq(s); } static void ehci_child_detach(USBPort *port, USBDevice *child) @@ -962,11 +869,24 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[], } s->companion_count++; - s->mmio[0x05] = (s->companion_count << 4) | portcount; + s->caps[0x05] = (s->companion_count << 4) | portcount; return 0; } +static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep) +{ + EHCIState *s = container_of(bus, EHCIState, bus); + uint32_t portsc = s->portsc[ep->dev->port->index]; + + if (portsc & PORTSC_POWNER) { + return; + } + + s->periodic_sched_active = PERIODIC_ACTIVE; + qemu_bh_schedule(s->async_bh); +} + static USBDevice *ehci_find_device(EHCIState *ehci, uint8_t addr) { USBDevice *dev; @@ -1007,7 +927,8 @@ static void ehci_reset(void *opaque) } } - memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE); + memset(&s->opreg, 0x00, sizeof(s->opreg)); + memset(&s->portsc, 0x00, sizeof(s->portsc)); s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH; s->usbsts = USBSTS_HALT; @@ -1034,50 +955,43 @@ static void ehci_reset(void *opaque) qemu_bh_cancel(s->async_bh); } -static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr) +static uint64_t ehci_caps_read(void *ptr, hwaddr addr, + unsigned size) { EHCIState *s = ptr; - uint32_t val; - - val = s->mmio[addr]; - - return val; + return s->caps[addr]; } -static uint32_t ehci_mem_readw(void *ptr, target_phys_addr_t addr) +static uint64_t ehci_opreg_read(void *ptr, hwaddr addr, + unsigned size) { EHCIState *s = ptr; uint32_t val; - val = s->mmio[addr] | (s->mmio[addr+1] << 8); + switch (addr) { + case FRINDEX: + /* Round down to mult of 8, else it can go backwards on migration */ + val = s->frindex & ~7; + break; + default: + val = s->opreg[addr >> 2]; + } + trace_usb_ehci_opreg_read(addr + s->opregbase, addr2str(addr), val); return val; } -static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr) +static uint64_t ehci_port_read(void *ptr, hwaddr addr, + unsigned size) { EHCIState *s = ptr; uint32_t val; - val = s->mmio[addr] | (s->mmio[addr+1] << 8) | - (s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24); - - trace_usb_ehci_mmio_readl(addr, addr2str(addr), val); + val = s->portsc[addr >> 2]; + trace_usb_ehci_portsc_read(addr + PORTSC_BEGIN, addr >> 2, val); return val; } -static void ehci_mem_writeb(void *ptr, target_phys_addr_t addr, uint32_t val) -{ - fprintf(stderr, "EHCI doesn't handle byte writes to MMIO\n"); - exit(1); -} - -static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val) -{ - fprintf(stderr, "EHCI doesn't handle 16-bit writes to MMIO\n"); - exit(1); -} - static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner) { USBDevice *dev = s->ports[port].dev; @@ -1106,11 +1020,17 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner) } } -static void handle_port_status_write(EHCIState *s, int port, uint32_t val) +static void ehci_port_write(void *ptr, hwaddr addr, + uint64_t val, unsigned size) { + EHCIState *s = ptr; + int port = addr >> 2; uint32_t *portsc = &s->portsc[port]; + uint32_t old = *portsc; USBDevice *dev = s->ports[port].dev; + trace_usb_ehci_portsc_write(addr + PORTSC_BEGIN, addr >> 2, val); + /* Clear rwc bits */ *portsc &= ~(val & PORTSC_RWC_MASK); /* The guest may clear, but not set the PED bit */ @@ -1142,39 +1062,20 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val) *portsc &= ~PORTSC_RO_MASK; *portsc |= val; + trace_usb_ehci_portsc_change(addr + PORTSC_BEGIN, addr >> 2, *portsc, old); } -static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) +static void ehci_opreg_write(void *ptr, hwaddr addr, + uint64_t val, unsigned size) { EHCIState *s = ptr; - uint32_t *mmio = (uint32_t *)(&s->mmio[addr]); + uint32_t *mmio = s->opreg + (addr >> 2); uint32_t old = *mmio; int i; - trace_usb_ehci_mmio_writel(addr, addr2str(addr), val); - - /* Only aligned reads are allowed on OHCI */ - if (addr & 3) { - fprintf(stderr, "usb-ehci: Mis-aligned write to addr 0x" - TARGET_FMT_plx "\n", addr); - return; - } - - if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) { - handle_port_status_write(s, (addr-PORTSC)/4, val); - trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old); - return; - } - - if (addr < OPREGBASE) { - fprintf(stderr, "usb-ehci: write attempt to read-only register" - TARGET_FMT_plx "\n", addr); - return; - } + trace_usb_ehci_opreg_write(addr + s->opregbase, addr2str(addr), val); - - /* Do any register specific pre-write processing here. */ - switch(addr) { + switch (addr) { case USBCMD: if (val & USBCMD_HCRESET) { ehci_reset(s); @@ -1182,21 +1083,32 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) break; } + /* not supporting dynamic frame list size at the moment */ + if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) { + fprintf(stderr, "attempt to set frame list size -- value %d\n", + (int)val & USBCMD_FLS); + val &= ~USBCMD_FLS; + } + + if (val & USBCMD_IAAD) { + /* + * Process IAAD immediately, otherwise the Linux IAAD watchdog may + * trigger and re-use a qh without us seeing the unlink. + */ + s->async_stepdown = 0; + qemu_bh_schedule(s->async_bh); + trace_usb_ehci_doorbell_ring(); + } + if (((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & val) != ((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & s->usbcmd)) { if (s->pstate == EST_INACTIVE) { SET_LAST_RUN_CLOCK(s); } + s->usbcmd = val; /* Set usbcmd for ehci_update_halt() */ ehci_update_halt(s); s->async_stepdown = 0; - qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock)); - } - - /* not supporting dynamic frame list size at the moment */ - if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) { - fprintf(stderr, "attempt to set frame list size -- value %d\n", - val & USBCMD_FLS); - val &= ~USBCMD_FLS; + qemu_bh_schedule(s->async_bh); } break; @@ -1209,10 +1121,14 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) case USBINTR: val &= USBINTR_MASK; + if (ehci_enabled(s) && (USBSTS_FLR & val)) { + qemu_bh_schedule(s->async_bh); + } break; case FRINDEX: - val &= 0x00003ff8; /* frindex is 14bits and always a multiple of 8 */ + val &= 0x00003fff; /* frindex is 14bits */ + s->usbsts_frindex = val; break; case CONFIGFLAG: @@ -1241,38 +1157,8 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) } *mmio = val; - trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old); -} - - -// TODO : Put in common header file, duplication from usb-ohci.c - -/* Get an array of dwords from main memory */ -static inline int get_dwords(EHCIState *ehci, uint32_t addr, - uint32_t *buf, int num) -{ - int i; - - for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { - pci_dma_read(&ehci->dev, addr, buf, sizeof(*buf)); - *buf = le32_to_cpu(*buf); - } - - return 1; -} - -/* Put an array of dwords in to main memory */ -static inline int put_dwords(EHCIState *ehci, uint32_t addr, - uint32_t *buf, int num) -{ - int i; - - for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { - uint32_t tmp = cpu_to_le32(*buf); - pci_dma_write(&ehci->dev, addr, &tmp, sizeof(tmp)); - } - - return 1; + trace_usb_ehci_opreg_change(addr + s->opregbase, addr2str(addr), + *mmio, old); } /* @@ -1352,12 +1238,12 @@ static int ehci_init_transfer(EHCIPacket *p) cpage = get_field(p->qtd.token, QTD_TOKEN_CPAGE); bytes = get_field(p->qtd.token, QTD_TOKEN_TBYTES); offset = p->qtd.bufptr[0] & ~QTD_BUFPTR_MASK; - pci_dma_sglist_init(&p->sgl, &p->queue->ehci->dev, 5); + qemu_sglist_init(&p->sgl, 5, p->queue->ehci->dma); while (bytes > 0) { if (cpage > 4) { fprintf(stderr, "cpage out of range (%d)\n", cpage); - return USB_RET_PROCERR; + return -1; } page = p->qtd.bufptr[cpage] & QTD_BUFPTR_MASK; @@ -1375,16 +1261,16 @@ static int ehci_init_transfer(EHCIPacket *p) return 0; } -static void ehci_finish_transfer(EHCIQueue *q, int status) +static void ehci_finish_transfer(EHCIQueue *q, int len) { uint32_t cpage, offset; - if (status > 0) { + if (len > 0) { /* update cpage & offset */ cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE); offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK; - offset += status; + offset += len; cpage += offset >> QTD_BUFPTR_SH; offset &= ~QTD_BUFPTR_MASK; @@ -1407,153 +1293,168 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) } p = container_of(packet, EHCIPacket, packet); - trace_usb_ehci_packet_action(p->queue, p, "wakeup"); assert(p->async == EHCI_ASYNC_INFLIGHT); + + if (packet->status == USB_RET_REMOVE_FROM_QUEUE) { + trace_usb_ehci_packet_action(p->queue, p, "remove"); + ehci_free_packet(p); + return; + } + + trace_usb_ehci_packet_action(p->queue, p, "wakeup"); p->async = EHCI_ASYNC_FINISHED; - p->usb_status = packet->result; - if (p->queue->async) { - qemu_bh_schedule(p->queue->ehci->async_bh); + if (!p->queue->async) { + s->periodic_sched_active = PERIODIC_ACTIVE; } + qemu_bh_schedule(s->async_bh); } static void ehci_execute_complete(EHCIQueue *q) { EHCIPacket *p = QTAILQ_FIRST(&q->packets); + uint32_t tbytes; assert(p != NULL); assert(p->qtdaddr == q->qtdaddr); - assert(p->async != EHCI_ASYNC_INFLIGHT); - p->async = EHCI_ASYNC_NONE; + assert(p->async == EHCI_ASYNC_INITIALIZED || + p->async == EHCI_ASYNC_FINISHED); - DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n", - q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status); + DPRINTF("execute_complete: qhaddr 0x%x, next 0x%x, qtdaddr 0x%x, " + "status %d, actual_length %d\n", + q->qhaddr, q->qh.next, q->qtdaddr, + p->packet.status, p->packet.actual_length); - if (p->usb_status < 0) { - switch (p->usb_status) { - case USB_RET_IOERROR: - case USB_RET_NODEV: - q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR); - set_field(&q->qh.token, 0, QTD_TOKEN_CERR); - ehci_raise_irq(q->ehci, USBSTS_ERRINT); - break; - case USB_RET_STALL: - q->qh.token |= QTD_TOKEN_HALT; - ehci_raise_irq(q->ehci, USBSTS_ERRINT); - break; - case USB_RET_NAK: - set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT); - return; /* We're not done yet with this transaction */ - case USB_RET_BABBLE: - q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE); - ehci_raise_irq(q->ehci, USBSTS_ERRINT); - break; - default: - /* should not be triggerable */ - fprintf(stderr, "USB invalid response %d\n", p->usb_status); - assert(0); - break; - } - } else if ((p->usb_status > p->tbytes) && (p->pid == USB_TOKEN_IN)) { - p->usb_status = USB_RET_BABBLE; + switch (p->packet.status) { + case USB_RET_SUCCESS: + break; + case USB_RET_IOERROR: + case USB_RET_NODEV: + q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR); + set_field(&q->qh.token, 0, QTD_TOKEN_CERR); + ehci_raise_irq(q->ehci, USBSTS_ERRINT); + break; + case USB_RET_STALL: + q->qh.token |= QTD_TOKEN_HALT; + ehci_raise_irq(q->ehci, USBSTS_ERRINT); + break; + case USB_RET_NAK: + set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT); + return; /* We're not done yet with this transaction */ + case USB_RET_BABBLE: q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE); ehci_raise_irq(q->ehci, USBSTS_ERRINT); - } else { - // TODO check 4.12 for splits + break; + default: + /* should not be triggerable */ + fprintf(stderr, "USB invalid response %d\n", p->packet.status); + assert(0); + break; + } - if (p->tbytes && p->pid == USB_TOKEN_IN) { - p->tbytes -= p->usb_status; - } else { - p->tbytes = 0; + /* TODO check 4.12 for splits */ + tbytes = get_field(q->qh.token, QTD_TOKEN_TBYTES); + if (tbytes && p->pid == USB_TOKEN_IN) { + tbytes -= p->packet.actual_length; + if (tbytes) { + /* 4.15.1.2 must raise int on a short input packet */ + ehci_raise_irq(q->ehci, USBSTS_INT); + if (q->async) { + q->ehci->int_req_by_async = true; + } } - - DPRINTF("updating tbytes to %d\n", p->tbytes); - set_field(&q->qh.token, p->tbytes, QTD_TOKEN_TBYTES); + } else { + tbytes = 0; } - ehci_finish_transfer(q, p->usb_status); + DPRINTF("updating tbytes to %d\n", tbytes); + set_field(&q->qh.token, tbytes, QTD_TOKEN_TBYTES); + + ehci_finish_transfer(q, p->packet.actual_length); usb_packet_unmap(&p->packet, &p->sgl); qemu_sglist_destroy(&p->sgl); + p->async = EHCI_ASYNC_NONE; q->qh.token ^= QTD_TOKEN_DTOGGLE; q->qh.token &= ~QTD_TOKEN_ACTIVE; if (q->qh.token & QTD_TOKEN_IOC) { ehci_raise_irq(q->ehci, USBSTS_INT); + if (q->async) { + q->ehci->int_req_by_async = true; + } } } -// 4.10.3 - +/* 4.10.3 returns "again" */ static int ehci_execute(EHCIPacket *p, const char *action) { USBEndpoint *ep; - int ret; int endp; + bool spd; + + assert(p->async == EHCI_ASYNC_NONE || + p->async == EHCI_ASYNC_INITIALIZED); if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) { fprintf(stderr, "Attempting to execute inactive qtd\n"); - return USB_RET_PROCERR; - } - - p->tbytes = (p->qtd.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH; - if (p->tbytes > BUFF_SIZE) { - fprintf(stderr, "Request for more bytes than allowed\n"); - return USB_RET_PROCERR; + return -1; } - p->pid = (p->qtd.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH; - switch (p->pid) { - case 0: - p->pid = USB_TOKEN_OUT; - break; - case 1: - p->pid = USB_TOKEN_IN; - break; - case 2: - p->pid = USB_TOKEN_SETUP; - break; - default: - fprintf(stderr, "bad token\n"); - break; + if (get_field(p->qtd.token, QTD_TOKEN_TBYTES) > BUFF_SIZE) { + ehci_trace_guest_bug(p->queue->ehci, + "guest requested more bytes than allowed"); + return -1; } - if (ehci_init_transfer(p) != 0) { - return USB_RET_PROCERR; + if (!ehci_verify_pid(p->queue, &p->qtd)) { + ehci_queue_stopped(p->queue); /* Mark the ep in the prev dir stopped */ } - + p->pid = ehci_get_pid(&p->qtd); + p->queue->last_pid = p->pid; endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP); ep = usb_ep_get(p->queue->dev, p->pid, endp); - usb_packet_setup(&p->packet, p->pid, ep); - usb_packet_map(&p->packet, &p->sgl); + if (p->async == EHCI_ASYNC_NONE) { + if (ehci_init_transfer(p) != 0) { + return -1; + } + + spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0); + usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr, spd, + (p->qtd.token & QTD_TOKEN_IOC) != 0); + usb_packet_map(&p->packet, &p->sgl); + p->async = EHCI_ASYNC_INITIALIZED; + } trace_usb_ehci_packet_action(p->queue, p, action); - ret = usb_handle_packet(p->queue->dev, &p->packet); - DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd " - "(total %d) endp %x ret %d\n", - q->qhaddr, q->qh.next, q->qtdaddr, q->pid, - q->packet.iov.size, q->tbytes, endp, ret); + usb_handle_packet(p->queue->dev, &p->packet); + DPRINTF("submit: qh 0x%x next 0x%x qtd 0x%x pid 0x%x len %zd endp 0x%x " + "status %d actual_length %d\n", p->queue->qhaddr, p->qtd.next, + p->qtdaddr, p->pid, p->packet.iov.size, endp, p->packet.status, + p->packet.actual_length); - if (ret > BUFF_SIZE) { + if (p->packet.actual_length > BUFF_SIZE) { fprintf(stderr, "ret from usb_handle_packet > BUFF_SIZE\n"); - return USB_RET_PROCERR; + return -1; } - return ret; + return 1; } /* 4.7.2 */ static int ehci_process_itd(EHCIState *ehci, - EHCIitd *itd) + EHCIitd *itd, + uint32_t addr) { USBDevice *dev; USBEndpoint *ep; - int ret; uint32_t i, len, pid, dir, devaddr, endp; uint32_t pg, off, ptr1, ptr2, max, mult; + ehci->periodic_sched_active = PERIODIC_ACTIVE; + dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION); devaddr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR); endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP); @@ -1573,10 +1474,10 @@ static int ehci_process_itd(EHCIState *ehci, } if (len > BUFF_SIZE) { - return USB_RET_PROCERR; + return -1; } - pci_dma_sglist_init(&ehci->isgl, &ehci->dev, 2); + qemu_sglist_init(&ehci->isgl, 2, ehci->dma); if (off + len > 4096) { /* transfer crosses page border */ uint32_t len2 = off + len - 4096; @@ -1591,49 +1492,49 @@ static int ehci_process_itd(EHCIState *ehci, dev = ehci_find_device(ehci, devaddr); ep = usb_ep_get(dev, pid, endp); - if (ep->type == USB_ENDPOINT_XFER_ISOC) { - usb_packet_setup(&ehci->ipacket, pid, ep); + if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) { + usb_packet_setup(&ehci->ipacket, pid, ep, addr, false, + (itd->transact[i] & ITD_XACT_IOC) != 0); usb_packet_map(&ehci->ipacket, &ehci->isgl); - ret = usb_handle_packet(dev, &ehci->ipacket); - assert(ret != USB_RET_ASYNC); + usb_handle_packet(dev, &ehci->ipacket); usb_packet_unmap(&ehci->ipacket, &ehci->isgl); } else { DPRINTF("ISOCH: attempt to addess non-iso endpoint\n"); - ret = USB_RET_NAK; + ehci->ipacket.status = USB_RET_NAK; + ehci->ipacket.actual_length = 0; } qemu_sglist_destroy(&ehci->isgl); - if (ret < 0) { - switch (ret) { - default: - fprintf(stderr, "Unexpected iso usb result: %d\n", ret); - /* Fall through */ - case USB_RET_IOERROR: - case USB_RET_NODEV: - /* 3.3.2: XACTERR is only allowed on IN transactions */ - if (dir) { - itd->transact[i] |= ITD_XACT_XACTERR; - ehci_raise_irq(ehci, USBSTS_ERRINT); - } - break; - case USB_RET_BABBLE: - itd->transact[i] |= ITD_XACT_BABBLE; + switch (ehci->ipacket.status) { + case USB_RET_SUCCESS: + break; + default: + fprintf(stderr, "Unexpected iso usb result: %d\n", + ehci->ipacket.status); + /* Fall through */ + case USB_RET_IOERROR: + case USB_RET_NODEV: + /* 3.3.2: XACTERR is only allowed on IN transactions */ + if (dir) { + itd->transact[i] |= ITD_XACT_XACTERR; ehci_raise_irq(ehci, USBSTS_ERRINT); - break; - case USB_RET_NAK: - /* no data for us, so do a zero-length transfer */ - ret = 0; - break; } + break; + case USB_RET_BABBLE: + itd->transact[i] |= ITD_XACT_BABBLE; + ehci_raise_irq(ehci, USBSTS_ERRINT); + break; + case USB_RET_NAK: + /* no data for us, so do a zero-length transfer */ + ehci->ipacket.actual_length = 0; + break; } - if (ret >= 0) { - if (!dir) { - /* OUT */ - set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH); - } else { - /* IN */ - set_field(&itd->transact[i], ret, ITD_XACT_LENGTH); - } + if (!dir) { + set_field(&itd->transact[i], len - ehci->ipacket.actual_length, + ITD_XACT_LENGTH); /* OUT */ + } else { + set_field(&itd->transact[i], ehci->ipacket.actual_length, + ITD_XACT_LENGTH); /* IN */ } if (itd->transact[i] & ITD_XACT_IOC) { ehci_raise_irq(ehci, USBSTS_INT); @@ -1664,8 +1565,10 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) /* Find the head of the list (4.9.1.1) */ for(i = 0; i < MAX_QH; i++) { - get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh, - sizeof(EHCIqh) >> 2); + if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh, + sizeof(EHCIqh) >> 2) < 0) { + return 0; + } ehci_trace_qh(NULL, NLPTR_GET(entry), &qh); if (qh.epchar & QH_EPCHAR_H) { @@ -1742,8 +1645,7 @@ out: static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) { - EHCIPacket *p; - uint32_t entry, devaddr; + uint32_t entry; EHCIQueue *q; EHCIqh qh; @@ -1752,7 +1654,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) if (NULL == q) { q = ehci_alloc_queue(ehci, entry, async); } - p = QTAILQ_FIRST(&q->packets); q->seen++; if (q->seen > 1) { @@ -1762,44 +1663,32 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) goto out; } - get_dwords(ehci, NLPTR_GET(q->qhaddr), - (uint32_t *) &qh, sizeof(EHCIqh) >> 2); - if (q->revalidate && (q->qh.epchar != qh.epchar || - q->qh.epcap != qh.epcap || - q->qh.current_qtd != qh.current_qtd)) { - ehci_free_queue(q); - q = ehci_alloc_queue(ehci, entry, async); - q->seen++; - p = NULL; + if (get_dwords(ehci, NLPTR_GET(q->qhaddr), + (uint32_t *) &qh, sizeof(EHCIqh) >> 2) < 0) { + q = NULL; + goto out; } - q->qh = qh; - q->revalidate = 0; - ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh); - - devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR); - if (q->dev != NULL && q->dev->addr != devaddr) { - if (!QTAILQ_EMPTY(&q->packets)) { - /* should not happen (guest bug) */ - while ((p = QTAILQ_FIRST(&q->packets)) != NULL) { - ehci_free_packet(p); - } + ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &qh); + + /* + * The overlay area of the qh should never be changed by the guest, + * except when idle, in which case the reset is a nop. + */ + if (!ehci_verify_qh(q, &qh)) { + if (ehci_reset_queue(q) > 0) { + ehci_trace_guest_bug(ehci, "guest updated active QH"); } - q->dev = NULL; - } - if (q->dev == NULL) { - q->dev = ehci_find_device(q->ehci, devaddr); } + q->qh = qh; - if (p && p->async == EHCI_ASYNC_INFLIGHT) { - /* I/O still in progress -- skip queue */ - ehci_set_state(ehci, async, EST_HORIZONTALQH); - goto out; + q->transact_ctr = get_field(q->qh.epcap, QH_EPCAP_MULT); + if (q->transact_ctr == 0) { /* Guest bug in some versions of windows */ + q->transact_ctr = 4; } - if (p && p->async == EHCI_ASYNC_FINISHED) { - /* I/O finished -- continue processing queue */ - trace_usb_ehci_packet_action(p->queue, p, "complete"); - ehci_set_state(ehci, async, EST_EXECUTING); - goto out; + + if (q->dev == NULL) { + q->dev = ehci_find_device(q->ehci, + get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)); } if (async && (q->qh.epchar & QH_EPCHAR_H)) { @@ -1852,11 +1741,13 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async) assert(!async); entry = ehci_get_fetch_addr(ehci, async); - get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd, - sizeof(EHCIitd) >> 2); + if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd, + sizeof(EHCIitd) >> 2) < 0) { + return -1; + } ehci_trace_itd(ehci, entry, &itd); - if (ehci_process_itd(ehci, &itd) != 0) { + if (ehci_process_itd(ehci, &itd, entry) != 0) { return -1; } @@ -1876,8 +1767,10 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async) assert(!async); entry = ehci_get_fetch_addr(ehci, async); - get_dwords(ehci, NLPTR_GET(entry), (uint32_t *)&sitd, - sizeof(EHCIsitd) >> 2); + if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *)&sitd, + sizeof(EHCIsitd) >> 2) < 0) { + return 0; + } ehci_trace_sitd(ehci, entry, &sitd); if (!(sitd.results & SITD_RESULTS_ACTIVE)) { @@ -1936,36 +1829,53 @@ static int ehci_state_fetchqtd(EHCIQueue *q) { EHCIqtd qtd; EHCIPacket *p; - int again = 0; + int again = 1; - get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd, - sizeof(EHCIqtd) >> 2); + if (get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd, + sizeof(EHCIqtd) >> 2) < 0) { + return 0; + } ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd); p = QTAILQ_FIRST(&q->packets); - while (p != NULL && p->qtdaddr != q->qtdaddr) { - /* should not happen (guest bug) */ - ehci_free_packet(p); - p = QTAILQ_FIRST(&q->packets); - } if (p != NULL) { - ehci_qh_do_overlay(q); - ehci_flush_qh(q); - if (p->async == EHCI_ASYNC_INFLIGHT) { - ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); + if (!ehci_verify_qtd(p, &qtd)) { + ehci_cancel_queue(q); + if (qtd.token & QTD_TOKEN_ACTIVE) { + ehci_trace_guest_bug(q->ehci, "guest updated active qTD"); + } + p = NULL; } else { + p->qtd = qtd; + ehci_qh_do_overlay(q); + } + } + + if (!(qtd.token & QTD_TOKEN_ACTIVE)) { + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); + } else if (p != NULL) { + switch (p->async) { + case EHCI_ASYNC_NONE: + case EHCI_ASYNC_INITIALIZED: + /* Not yet executed (MULT), or previously nacked (int) packet */ + ehci_set_state(q->ehci, q->async, EST_EXECUTE); + break; + case EHCI_ASYNC_INFLIGHT: + /* Check if the guest has added new tds to the queue */ + again = ehci_fill_queue(QTAILQ_LAST(&q->packets, pkts_head)); + /* Unfinished async handled packet, go horizontal */ + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); + break; + case EHCI_ASYNC_FINISHED: + /* Complete executing of the packet */ ehci_set_state(q->ehci, q->async, EST_EXECUTING); + break; } - again = 1; - } else if (qtd.token & QTD_TOKEN_ACTIVE) { + } else { p = ehci_alloc_packet(q); p->qtdaddr = q->qtdaddr; p->qtd = qtd; ehci_set_state(q->ehci, q->async, EST_EXECUTE); - again = 1; - } else { - ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); - again = 1; } return again; @@ -1986,33 +1896,52 @@ static int ehci_state_horizqh(EHCIQueue *q) return again; } -static void ehci_fill_queue(EHCIPacket *p) +/* Returns "again" */ +static int ehci_fill_queue(EHCIPacket *p) { + USBEndpoint *ep = p->packet.ep; EHCIQueue *q = p->queue; EHCIqtd qtd = p->qtd; uint32_t qtdaddr; for (;;) { - if (NLPTR_TBIT(qtd.altnext) == 0) { - break; - } if (NLPTR_TBIT(qtd.next) != 0) { break; } qtdaddr = qtd.next; - get_dwords(q->ehci, NLPTR_GET(qtdaddr), - (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2); + /* + * Detect circular td lists, Windows creates these, counting on the + * active bit going low after execution to make the queue stop. + */ + QTAILQ_FOREACH(p, &q->packets, next) { + if (p->qtdaddr == qtdaddr) { + goto leave; + } + } + if (get_dwords(q->ehci, NLPTR_GET(qtdaddr), + (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2) < 0) { + return -1; + } ehci_trace_qtd(q, NLPTR_GET(qtdaddr), &qtd); if (!(qtd.token & QTD_TOKEN_ACTIVE)) { break; } + if (!ehci_verify_pid(q, &qtd)) { + ehci_trace_guest_bug(q->ehci, "guest queued token with wrong pid"); + break; + } p = ehci_alloc_packet(q); p->qtdaddr = qtdaddr; p->qtd = qtd; - p->usb_status = ehci_execute(p, "queue"); - assert(p->usb_status == USB_RET_ASYNC); + if (ehci_execute(p, "queue") == -1) { + return -1; + } + assert(p->packet.status == USB_RET_ASYNC); p->async = EHCI_ASYNC_INFLIGHT; } +leave: + usb_device_flush_ep_queue(ep->dev, ep); + return 1; } static int ehci_state_execute(EHCIQueue *q) @@ -2029,33 +1958,32 @@ static int ehci_state_execute(EHCIQueue *q) // TODO verify enough time remains in the uframe as in 4.4.1.1 // TODO write back ptr to async list when done or out of time - // TODO Windows does not seem to ever set the MULT field - if (!q->async) { - int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT); - if (!transactCtr) { - ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); - again = 1; - goto out; - } + /* 4.10.3, bottom of page 82, go horizontal on transaction counter == 0 */ + if (!q->async && q->transact_ctr == 0) { + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); + again = 1; + goto out; } if (q->async) { ehci_set_usbsts(q->ehci, USBSTS_REC); } - p->usb_status = ehci_execute(p, "process"); - if (p->usb_status == USB_RET_PROCERR) { - again = -1; + again = ehci_execute(p, "process"); + if (again == -1) { goto out; } - if (p->usb_status == USB_RET_ASYNC) { + if (p->packet.status == USB_RET_ASYNC) { ehci_flush_qh(q); trace_usb_ehci_packet_action(p->queue, p, "async"); p->async = EHCI_ASYNC_INFLIGHT; ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); - again = 1; - ehci_fill_queue(p); + if (q->async) { + again = ehci_fill_queue(p); + } else { + again = 1; + } goto out; } @@ -2069,41 +1997,26 @@ out: static int ehci_state_executing(EHCIQueue *q) { EHCIPacket *p = QTAILQ_FIRST(&q->packets); - int again = 0; assert(p != NULL); assert(p->qtdaddr == q->qtdaddr); ehci_execute_complete(q); - if (p->usb_status == USB_RET_ASYNC) { - goto out; - } - if (p->usb_status == USB_RET_PROCERR) { - again = -1; - goto out; - } - // 4.10.3 - if (!q->async) { - int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT); - transactCtr--; - set_field(&q->qh.epcap, transactCtr, QH_EPCAP_MULT); - // 4.10.3, bottom of page 82, should exit this state when transaction - // counter decrements to 0 + /* 4.10.3 */ + if (!q->async && q->transact_ctr > 0) { + q->transact_ctr--; } /* 4.10.5 */ - if (p->usb_status == USB_RET_NAK) { + if (p->packet.status == USB_RET_NAK) { ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); } else { ehci_set_state(q->ehci, q->async, EST_WRITEBACK); } - again = 1; - -out: ehci_flush_qh(q); - return again; + return 1; } @@ -2208,6 +2121,9 @@ static void ehci_advance_state(EHCIState *ehci, int async) case EST_WRITEBACK: assert(q != NULL); again = ehci_state_writeback(q); + if (!async) { + ehci->periodic_sched_active = PERIODIC_ACTIVE; + } break; default: @@ -2266,8 +2182,8 @@ static void ehci_advance_async_state(EHCIState *ehci) */ if (ehci->usbcmd & USBCMD_IAAD) { /* Remove all unseen qhs from the async qhs queue */ - ehci_queues_tag_unused_async(ehci); - DPRINTF("ASYNC: doorbell request acknowledged\n"); + ehci_queues_rip_unseen(ehci, async); + trace_usb_ehci_doorbell_ack(); ehci->usbcmd &= ~USBCMD_IAAD; ehci_raise_irq(ehci, USBSTS_IAA); } @@ -2311,8 +2227,9 @@ static void ehci_advance_periodic_state(EHCIState *ehci) } list |= ((ehci->frindex & 0x1ff8) >> 1); - pci_dma_read(&ehci->dev, list, &entry, sizeof entry); - entry = le32_to_cpu(entry); + if (get_dwords(ehci, list, &entry, 1) < 0) { + break; + } DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n", ehci->frindex / 8, list, entry); @@ -2330,16 +2247,16 @@ static void ehci_advance_periodic_state(EHCIState *ehci) } } -static void ehci_update_frindex(EHCIState *ehci, int frames) +static void ehci_update_frindex(EHCIState *ehci, int uframes) { int i; - if (!ehci_enabled(ehci)) { + if (!ehci_enabled(ehci) && ehci->pstate == EST_INACTIVE) { return; } - for (i = 0; i < frames; i++) { - ehci->frindex += 8; + for (i = 0; i < uframes; i++) { + ehci->frindex++; if (ehci->frindex == 0x00002000) { ehci_raise_irq(ehci, USBSTS_FLR); @@ -2348,7 +2265,7 @@ static void ehci_update_frindex(EHCIState *ehci, int frames) if (ehci->frindex == 0x00004000) { ehci_raise_irq(ehci, USBSTS_FLR); ehci->frindex = 0; - if (ehci->usbsts_frindex > 0x00004000) { + if (ehci->usbsts_frindex >= 0x00004000) { ehci->usbsts_frindex -= 0x00004000; } else { ehci->usbsts_frindex = 0; @@ -2363,36 +2280,57 @@ static void ehci_frame_timer(void *opaque) int need_timer = 0; int64_t expire_time, t_now; uint64_t ns_elapsed; - int frames, skipped_frames; + int uframes, skipped_uframes; int i; t_now = qemu_get_clock_ns(vm_clock); ns_elapsed = t_now - ehci->last_run_ns; - frames = ns_elapsed / FRAME_TIMER_NS; + uframes = ns_elapsed / UFRAME_TIMER_NS; if (ehci_periodic_enabled(ehci) || ehci->pstate != EST_INACTIVE) { need_timer++; - ehci->async_stepdown = 0; - if (frames > ehci->maxframes) { - skipped_frames = frames - ehci->maxframes; - ehci_update_frindex(ehci, skipped_frames); - ehci->last_run_ns += FRAME_TIMER_NS * skipped_frames; - frames -= skipped_frames; - DPRINTF("WARNING - EHCI skipped %d frames\n", skipped_frames); + if (uframes > (ehci->maxframes * 8)) { + skipped_uframes = uframes - (ehci->maxframes * 8); + ehci_update_frindex(ehci, skipped_uframes); + ehci->last_run_ns += UFRAME_TIMER_NS * skipped_uframes; + uframes -= skipped_uframes; + DPRINTF("WARNING - EHCI skipped %d uframes\n", skipped_uframes); } - for (i = 0; i < frames; i++) { + for (i = 0; i < uframes; i++) { + /* + * If we're running behind schedule, we should not catch up + * too fast, as that will make some guests unhappy: + * 1) We must process a minimum of MIN_UFR_PER_TICK frames, + * otherwise we will never catch up + * 2) Process frames until the guest has requested an irq (IOC) + */ + if (i >= MIN_UFR_PER_TICK) { + ehci_commit_irq(ehci); + if ((ehci->usbsts & USBINTR_MASK) & ehci->usbintr) { + break; + } + } + if (ehci->periodic_sched_active) { + ehci->periodic_sched_active--; + } ehci_update_frindex(ehci, 1); - ehci_advance_periodic_state(ehci); - ehci->last_run_ns += FRAME_TIMER_NS; + if ((ehci->frindex & 7) == 0) { + ehci_advance_periodic_state(ehci); + } + ehci->last_run_ns += UFRAME_TIMER_NS; } } else { - if (ehci->async_stepdown < ehci->maxframes / 2) { - ehci->async_stepdown++; - } - ehci_update_frindex(ehci, frames); - ehci->last_run_ns += FRAME_TIMER_NS * frames; + ehci->periodic_sched_active = 0; + ehci_update_frindex(ehci, uframes); + ehci->last_run_ns += UFRAME_TIMER_NS * uframes; + } + + if (ehci->periodic_sched_active) { + ehci->async_stepdown = 0; + } else if (ehci->async_stepdown < ehci->maxframes / 2) { + ehci->async_stepdown++; } /* Async is not inside loop since it executes everything it can once @@ -2409,28 +2347,48 @@ static void ehci_frame_timer(void *opaque) ehci->async_stepdown = 0; } + if (ehci_enabled(ehci) && (ehci->usbintr & USBSTS_FLR)) { + need_timer++; + } + if (need_timer) { - expire_time = t_now + (get_ticks_per_sec() + /* If we've raised int, we speed up the timer, so that we quickly + * notice any new packets queued up in response */ + if (ehci->int_req_by_async && (ehci->usbsts & USBSTS_INT)) { + expire_time = t_now + get_ticks_per_sec() / (FRAME_TIMER_FREQ * 4); + ehci->int_req_by_async = false; + } else { + expire_time = t_now + (get_ticks_per_sec() * (ehci->async_stepdown+1) / FRAME_TIMER_FREQ); + } qemu_mod_timer(ehci->frame_timer, expire_time); } } -static void ehci_async_bh(void *opaque) -{ - EHCIState *ehci = opaque; - ehci_advance_async_state(ehci); -} +static const MemoryRegionOps ehci_mmio_caps_ops = { + .read = ehci_caps_read, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; -static const MemoryRegionOps ehci_mem_ops = { - .old_mmio = { - .read = { ehci_mem_readb, ehci_mem_readw, ehci_mem_readl }, - .write = { ehci_mem_writeb, ehci_mem_writew, ehci_mem_writel }, - }, +static const MemoryRegionOps ehci_mmio_opreg_ops = { + .read = ehci_opreg_read, + .write = ehci_opreg_write, + .valid.min_access_size = 4, + .valid.max_access_size = 4, .endianness = DEVICE_LITTLE_ENDIAN, }; -static int usb_ehci_initfn(PCIDevice *dev); +static const MemoryRegionOps ehci_mmio_port_ops = { + .read = ehci_port_read, + .write = ehci_port_write, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; static USBPortOps ehci_port_ops = { .attach = ehci_attach, @@ -2442,8 +2400,20 @@ static USBPortOps ehci_port_ops = { static USBBusOps ehci_bus_ops = { .register_companion = ehci_register_companion, + .wakeup_endpoint = ehci_wakeup_endpoint, }; +static void usb_ehci_pre_save(void *opaque) +{ + EHCIState *ehci = opaque; + uint32_t new_frindex; + + /* Round down frindex to a multiple of 8 for migration compatibility */ + new_frindex = ehci->frindex & ~7; + ehci->last_run_ns -= (ehci->frindex - new_frindex) * UFRAME_TIMER_NS; + ehci->frindex = new_frindex; +} + static int usb_ehci_post_load(void *opaque, int version_id) { EHCIState *s = opaque; @@ -2464,15 +2434,44 @@ static int usb_ehci_post_load(void *opaque, int version_id) return 0; } -static const VMStateDescription vmstate_ehci = { - .name = "ehci", - .version_id = 1, +static void usb_ehci_vm_state_change(void *opaque, int running, RunState state) +{ + EHCIState *ehci = opaque; + + /* + * We don't migrate the EHCIQueue-s, instead we rebuild them for the + * schedule in guest memory. We must do the rebuilt ASAP, so that + * USB-devices which have async handled packages have a packet in the + * ep queue to match the completion with. + */ + if (state == RUN_STATE_RUNNING) { + ehci_advance_async_state(ehci); + } + + /* + * The schedule rebuilt from guest memory could cause the migration dest + * to miss a QH unlink, and fail to cancel packets, since the unlinked QH + * will never have existed on the destination. Therefor we must flush the + * async schedule on savevm to catch any not yet noticed unlinks. + */ + if (state == RUN_STATE_SAVE_VM) { + ehci_advance_async_state(ehci); + ehci_queues_rip_unseen(ehci, 1); + } +} + +const VMStateDescription vmstate_ehci = { + .name = "ehci-core", + .version_id = 2, + .minimum_version_id = 1, + .pre_save = usb_ehci_pre_save, .post_load = usb_ehci_post_load, .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, EHCIState), /* mmio registers */ VMSTATE_UINT32(usbcmd, EHCIState), VMSTATE_UINT32(usbsts, EHCIState), + VMSTATE_UINT32_V(usbsts_pending, EHCIState, 2), + VMSTATE_UINT32_V(usbsts_frindex, EHCIState, 2), VMSTATE_UINT32(usbintr, EHCIState), VMSTATE_UINT32(frindex, EHCIState), VMSTATE_UINT32(ctrldssegment, EHCIState), @@ -2498,105 +2497,24 @@ static const VMStateDescription vmstate_ehci = { } }; -static Property ehci_properties[] = { - DEFINE_PROP_UINT32("maxframes", EHCIState, maxframes, 128), - DEFINE_PROP_END_OF_LIST(), -}; - -static void ehci_class_init(ObjectClass *klass, void *data) +void usb_ehci_initfn(EHCIState *s, DeviceState *dev) { - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->init = usb_ehci_initfn; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = PCI_DEVICE_ID_INTEL_82801D; /* ich4 */ - k->revision = 0x10; - k->class_id = PCI_CLASS_SERIAL_USB; - dc->vmsd = &vmstate_ehci; - dc->props = ehci_properties; -} - -static TypeInfo ehci_info = { - .name = "usb-ehci", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(EHCIState), - .class_init = ehci_class_init, -}; - -static void ich9_ehci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->init = usb_ehci_initfn; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1; - k->revision = 0x03; - k->class_id = PCI_CLASS_SERIAL_USB; - dc->vmsd = &vmstate_ehci; - dc->props = ehci_properties; -} - -static TypeInfo ich9_ehci_info = { - .name = "ich9-usb-ehci1", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(EHCIState), - .class_init = ich9_ehci_class_init, -}; - -static int usb_ehci_initfn(PCIDevice *dev) -{ - EHCIState *s = DO_UPCAST(EHCIState, dev, dev); - uint8_t *pci_conf = s->dev.config; int i; - pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20); - - /* capabilities pointer */ - pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00); - //pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50); - - pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */ - pci_set_byte(&pci_conf[PCI_MIN_GNT], 0); - pci_set_byte(&pci_conf[PCI_MAX_LAT], 0); - - // pci_conf[0x50] = 0x01; // power management caps - - pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); // release number (2.1.4) - pci_set_byte(&pci_conf[0x61], 0x20); // frame length adjustment (2.1.5) - pci_set_word(&pci_conf[0x62], 0x00); // port wake up capability (2.1.6) - - pci_conf[0x64] = 0x00; - pci_conf[0x65] = 0x00; - pci_conf[0x66] = 0x00; - pci_conf[0x67] = 0x00; - pci_conf[0x68] = 0x01; - pci_conf[0x69] = 0x00; - pci_conf[0x6a] = 0x00; - pci_conf[0x6b] = 0x00; // USBLEGSUP - pci_conf[0x6c] = 0x00; - pci_conf[0x6d] = 0x00; - pci_conf[0x6e] = 0x00; - pci_conf[0x6f] = 0xc0; // USBLEFCTLSTS - - // 2.2 host controller interface version - s->mmio[0x00] = (uint8_t) OPREGBASE; - s->mmio[0x01] = 0x00; - s->mmio[0x02] = 0x00; - s->mmio[0x03] = 0x01; // HC version - s->mmio[0x04] = NB_PORTS; // Number of downstream ports - s->mmio[0x05] = 0x00; // No companion ports at present - s->mmio[0x06] = 0x00; - s->mmio[0x07] = 0x00; - s->mmio[0x08] = 0x80; // We can cache whole frame, not 64-bit capable - s->mmio[0x09] = 0x68; // EECP - s->mmio[0x0a] = 0x00; - s->mmio[0x0b] = 0x00; - - s->irq = s->dev.irq[3]; - - usb_bus_new(&s->bus, &ehci_bus_ops, &s->dev.qdev); + /* 2.2 host controller interface version */ + s->caps[0x00] = (uint8_t)(s->opregbase - s->capsbase); + s->caps[0x01] = 0x00; + s->caps[0x02] = 0x00; + s->caps[0x03] = 0x01; /* HC version */ + s->caps[0x04] = NB_PORTS; /* Number of downstream ports */ + s->caps[0x05] = 0x00; /* No companion ports at present */ + s->caps[0x06] = 0x00; + s->caps[0x07] = 0x00; + s->caps[0x08] = 0x80; /* We can cache whole frame, no 64-bit */ + s->caps[0x0a] = 0x00; + s->caps[0x0b] = 0x00; + + usb_bus_new(&s->bus, &ehci_bus_ops, dev); for(i = 0; i < NB_PORTS; i++) { usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops, USB_SPEED_MASK_HIGH); @@ -2604,27 +2522,28 @@ static int usb_ehci_initfn(PCIDevice *dev) } s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s); - s->async_bh = qemu_bh_new(ehci_async_bh, s); + s->async_bh = qemu_bh_new(ehci_frame_timer, s); QTAILQ_INIT(&s->aqueues); QTAILQ_INIT(&s->pqueues); usb_packet_init(&s->ipacket); qemu_register_reset(ehci_reset, s); + qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s); - memory_region_init_io(&s->mem, &ehci_mem_ops, s, "ehci", MMIO_SIZE); - pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem); - - return 0; -} + memory_region_init(&s->mem, "ehci", MMIO_SIZE); + memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s, + "capabilities", CAPA_SIZE); + memory_region_init_io(&s->mem_opreg, &ehci_mmio_opreg_ops, s, + "operational", PORTSC_BEGIN); + memory_region_init_io(&s->mem_ports, &ehci_mmio_port_ops, s, + "ports", PORTSC_END - PORTSC_BEGIN); -static void ehci_register_types(void) -{ - type_register_static(&ehci_info); - type_register_static(&ich9_ehci_info); + memory_region_add_subregion(&s->mem, s->capsbase, &s->mem_caps); + memory_region_add_subregion(&s->mem, s->opregbase, &s->mem_opreg); + memory_region_add_subregion(&s->mem, s->opregbase + PORTSC_BEGIN, + &s->mem_ports); } -type_init(ehci_register_types) - /* * vim: expandtab ts=4 */ diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h new file mode 100644 index 0000000000..e95bb7ec46 --- /dev/null +++ b/hw/usb/hcd-ehci.h @@ -0,0 +1,366 @@ +/* + * QEMU USB EHCI Emulation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or(at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ +#ifndef HW_USB_EHCI_H +#define HW_USB_EHCI_H 1 + +#include "hw/hw.h" +#include "qemu/timer.h" +#include "hw/usb.h" +#include "monitor/monitor.h" +#include "trace.h" +#include "sysemu/dma.h" +#include "sysemu/sysemu.h" +#include "hw/pci/pci.h" +#include "hw/sysbus.h" + +#ifndef EHCI_DEBUG +#define EHCI_DEBUG 0 +#endif + +#if EHCI_DEBUG +#define DPRINTF printf +#else +#define DPRINTF(...) +#endif + +#define MMIO_SIZE 0x1000 +#define CAPA_SIZE 0x10 + +#define PORTSC 0x0044 +#define PORTSC_BEGIN PORTSC +#define PORTSC_END (PORTSC + 4 * NB_PORTS) + +#define NB_PORTS 6 /* Number of downstream ports */ + +typedef struct EHCIPacket EHCIPacket; +typedef struct EHCIQueue EHCIQueue; +typedef struct EHCIState EHCIState; + +/* EHCI spec version 1.0 Section 3.3 + */ +typedef struct EHCIitd { + uint32_t next; + + uint32_t transact[8]; +#define ITD_XACT_ACTIVE (1 << 31) +#define ITD_XACT_DBERROR (1 << 30) +#define ITD_XACT_BABBLE (1 << 29) +#define ITD_XACT_XACTERR (1 << 28) +#define ITD_XACT_LENGTH_MASK 0x0fff0000 +#define ITD_XACT_LENGTH_SH 16 +#define ITD_XACT_IOC (1 << 15) +#define ITD_XACT_PGSEL_MASK 0x00007000 +#define ITD_XACT_PGSEL_SH 12 +#define ITD_XACT_OFFSET_MASK 0x00000fff + + uint32_t bufptr[7]; +#define ITD_BUFPTR_MASK 0xfffff000 +#define ITD_BUFPTR_SH 12 +#define ITD_BUFPTR_EP_MASK 0x00000f00 +#define ITD_BUFPTR_EP_SH 8 +#define ITD_BUFPTR_DEVADDR_MASK 0x0000007f +#define ITD_BUFPTR_DEVADDR_SH 0 +#define ITD_BUFPTR_DIRECTION (1 << 11) +#define ITD_BUFPTR_MAXPKT_MASK 0x000007ff +#define ITD_BUFPTR_MAXPKT_SH 0 +#define ITD_BUFPTR_MULT_MASK 0x00000003 +#define ITD_BUFPTR_MULT_SH 0 +} EHCIitd; + +/* EHCI spec version 1.0 Section 3.4 + */ +typedef struct EHCIsitd { + uint32_t next; /* Standard next link pointer */ + uint32_t epchar; +#define SITD_EPCHAR_IO (1 << 31) +#define SITD_EPCHAR_PORTNUM_MASK 0x7f000000 +#define SITD_EPCHAR_PORTNUM_SH 24 +#define SITD_EPCHAR_HUBADD_MASK 0x007f0000 +#define SITD_EPCHAR_HUBADDR_SH 16 +#define SITD_EPCHAR_EPNUM_MASK 0x00000f00 +#define SITD_EPCHAR_EPNUM_SH 8 +#define SITD_EPCHAR_DEVADDR_MASK 0x0000007f + + uint32_t uframe; +#define SITD_UFRAME_CMASK_MASK 0x0000ff00 +#define SITD_UFRAME_CMASK_SH 8 +#define SITD_UFRAME_SMASK_MASK 0x000000ff + + uint32_t results; +#define SITD_RESULTS_IOC (1 << 31) +#define SITD_RESULTS_PGSEL (1 << 30) +#define SITD_RESULTS_TBYTES_MASK 0x03ff0000 +#define SITD_RESULTS_TYBYTES_SH 16 +#define SITD_RESULTS_CPROGMASK_MASK 0x0000ff00 +#define SITD_RESULTS_CPROGMASK_SH 8 +#define SITD_RESULTS_ACTIVE (1 << 7) +#define SITD_RESULTS_ERR (1 << 6) +#define SITD_RESULTS_DBERR (1 << 5) +#define SITD_RESULTS_BABBLE (1 << 4) +#define SITD_RESULTS_XACTERR (1 << 3) +#define SITD_RESULTS_MISSEDUF (1 << 2) +#define SITD_RESULTS_SPLITXSTATE (1 << 1) + + uint32_t bufptr[2]; +#define SITD_BUFPTR_MASK 0xfffff000 +#define SITD_BUFPTR_CURROFF_MASK 0x00000fff +#define SITD_BUFPTR_TPOS_MASK 0x00000018 +#define SITD_BUFPTR_TPOS_SH 3 +#define SITD_BUFPTR_TCNT_MASK 0x00000007 + + uint32_t backptr; /* Standard next link pointer */ +} EHCIsitd; + +/* EHCI spec version 1.0 Section 3.5 + */ +typedef struct EHCIqtd { + uint32_t next; /* Standard next link pointer */ + uint32_t altnext; /* Standard next link pointer */ + uint32_t token; +#define QTD_TOKEN_DTOGGLE (1 << 31) +#define QTD_TOKEN_TBYTES_MASK 0x7fff0000 +#define QTD_TOKEN_TBYTES_SH 16 +#define QTD_TOKEN_IOC (1 << 15) +#define QTD_TOKEN_CPAGE_MASK 0x00007000 +#define QTD_TOKEN_CPAGE_SH 12 +#define QTD_TOKEN_CERR_MASK 0x00000c00 +#define QTD_TOKEN_CERR_SH 10 +#define QTD_TOKEN_PID_MASK 0x00000300 +#define QTD_TOKEN_PID_SH 8 +#define QTD_TOKEN_ACTIVE (1 << 7) +#define QTD_TOKEN_HALT (1 << 6) +#define QTD_TOKEN_DBERR (1 << 5) +#define QTD_TOKEN_BABBLE (1 << 4) +#define QTD_TOKEN_XACTERR (1 << 3) +#define QTD_TOKEN_MISSEDUF (1 << 2) +#define QTD_TOKEN_SPLITXSTATE (1 << 1) +#define QTD_TOKEN_PING (1 << 0) + + uint32_t bufptr[5]; /* Standard buffer pointer */ +#define QTD_BUFPTR_MASK 0xfffff000 +#define QTD_BUFPTR_SH 12 +} EHCIqtd; + +/* EHCI spec version 1.0 Section 3.6 + */ +typedef struct EHCIqh { + uint32_t next; /* Standard next link pointer */ + + /* endpoint characteristics */ + uint32_t epchar; +#define QH_EPCHAR_RL_MASK 0xf0000000 +#define QH_EPCHAR_RL_SH 28 +#define QH_EPCHAR_C (1 << 27) +#define QH_EPCHAR_MPLEN_MASK 0x07FF0000 +#define QH_EPCHAR_MPLEN_SH 16 +#define QH_EPCHAR_H (1 << 15) +#define QH_EPCHAR_DTC (1 << 14) +#define QH_EPCHAR_EPS_MASK 0x00003000 +#define QH_EPCHAR_EPS_SH 12 +#define EHCI_QH_EPS_FULL 0 +#define EHCI_QH_EPS_LOW 1 +#define EHCI_QH_EPS_HIGH 2 +#define EHCI_QH_EPS_RESERVED 3 + +#define QH_EPCHAR_EP_MASK 0x00000f00 +#define QH_EPCHAR_EP_SH 8 +#define QH_EPCHAR_I (1 << 7) +#define QH_EPCHAR_DEVADDR_MASK 0x0000007f +#define QH_EPCHAR_DEVADDR_SH 0 + + /* endpoint capabilities */ + uint32_t epcap; +#define QH_EPCAP_MULT_MASK 0xc0000000 +#define QH_EPCAP_MULT_SH 30 +#define QH_EPCAP_PORTNUM_MASK 0x3f800000 +#define QH_EPCAP_PORTNUM_SH 23 +#define QH_EPCAP_HUBADDR_MASK 0x007f0000 +#define QH_EPCAP_HUBADDR_SH 16 +#define QH_EPCAP_CMASK_MASK 0x0000ff00 +#define QH_EPCAP_CMASK_SH 8 +#define QH_EPCAP_SMASK_MASK 0x000000ff +#define QH_EPCAP_SMASK_SH 0 + + uint32_t current_qtd; /* Standard next link pointer */ + uint32_t next_qtd; /* Standard next link pointer */ + uint32_t altnext_qtd; +#define QH_ALTNEXT_NAKCNT_MASK 0x0000001e +#define QH_ALTNEXT_NAKCNT_SH 1 + + uint32_t token; /* Same as QTD token */ + uint32_t bufptr[5]; /* Standard buffer pointer */ +#define BUFPTR_CPROGMASK_MASK 0x000000ff +#define BUFPTR_FRAMETAG_MASK 0x0000001f +#define BUFPTR_SBYTES_MASK 0x00000fe0 +#define BUFPTR_SBYTES_SH 5 +} EHCIqh; + +/* EHCI spec version 1.0 Section 3.7 + */ +typedef struct EHCIfstn { + uint32_t next; /* Standard next link pointer */ + uint32_t backptr; /* Standard next link pointer */ +} EHCIfstn; + +enum async_state { + EHCI_ASYNC_NONE = 0, + EHCI_ASYNC_INITIALIZED, + EHCI_ASYNC_INFLIGHT, + EHCI_ASYNC_FINISHED, +}; + +struct EHCIPacket { + EHCIQueue *queue; + QTAILQ_ENTRY(EHCIPacket) next; + + EHCIqtd qtd; /* copy of current QTD (being worked on) */ + uint32_t qtdaddr; /* address QTD read from */ + + USBPacket packet; + QEMUSGList sgl; + int pid; + enum async_state async; +}; + +struct EHCIQueue { + EHCIState *ehci; + QTAILQ_ENTRY(EHCIQueue) next; + uint32_t seen; + uint64_t ts; + int async; + int transact_ctr; + + /* cached data from guest - needs to be flushed + * when guest removes an entry (doorbell, handshake sequence) + */ + EHCIqh qh; /* copy of current QH (being worked on) */ + uint32_t qhaddr; /* address QH read from */ + uint32_t qtdaddr; /* address QTD read from */ + int last_pid; /* pid of last packet executed */ + USBDevice *dev; + QTAILQ_HEAD(pkts_head, EHCIPacket) packets; +}; + +typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead; + +struct EHCIState { + USBBus bus; + qemu_irq irq; + MemoryRegion mem; + DMAContext *dma; + MemoryRegion mem_caps; + MemoryRegion mem_opreg; + MemoryRegion mem_ports; + int companion_count; + uint16_t capsbase; + uint16_t opregbase; + + /* properties */ + uint32_t maxframes; + + /* + * EHCI spec version 1.0 Section 2.3 + * Host Controller Operational Registers + */ + uint8_t caps[CAPA_SIZE]; + union { + uint32_t opreg[PORTSC_BEGIN/sizeof(uint32_t)]; + struct { + uint32_t usbcmd; + uint32_t usbsts; + uint32_t usbintr; + uint32_t frindex; + uint32_t ctrldssegment; + uint32_t periodiclistbase; + uint32_t asynclistaddr; + uint32_t notused[9]; + uint32_t configflag; + }; + }; + uint32_t portsc[NB_PORTS]; + + /* + * Internal states, shadow registers, etc + */ + QEMUTimer *frame_timer; + QEMUBH *async_bh; + uint32_t astate; /* Current state in asynchronous schedule */ + uint32_t pstate; /* Current state in periodic schedule */ + USBPort ports[NB_PORTS]; + USBPort *companion_ports[NB_PORTS]; + uint32_t usbsts_pending; + uint32_t usbsts_frindex; + EHCIQueueHead aqueues; + EHCIQueueHead pqueues; + + /* which address to look at next */ + uint32_t a_fetch_addr; + uint32_t p_fetch_addr; + + USBPacket ipacket; + QEMUSGList isgl; + + uint64_t last_run_ns; + uint32_t async_stepdown; + uint32_t periodic_sched_active; + bool int_req_by_async; +}; + +extern const VMStateDescription vmstate_ehci; + +void usb_ehci_initfn(EHCIState *s, DeviceState *dev); + +#define TYPE_PCI_EHCI "pci-ehci-usb" +#define PCI_EHCI(obj) OBJECT_CHECK(EHCIPCIState, (obj), TYPE_PCI_EHCI) + +typedef struct EHCIPCIState { + /*< private >*/ + PCIDevice pcidev; + /*< public >*/ + + EHCIState ehci; +} EHCIPCIState; + + +#define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb" +#define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb" + +#define SYS_BUS_EHCI(obj) \ + OBJECT_CHECK(EHCISysBusState, (obj), TYPE_SYS_BUS_EHCI) +#define SYS_BUS_EHCI_CLASS(class) \ + OBJECT_CLASS_CHECK(SysBusEHCIClass, (class), TYPE_SYS_BUS_EHCI) +#define SYS_BUS_EHCI_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SysBusEHCIClass, (obj), TYPE_SYS_BUS_EHCI) + +typedef struct EHCISysBusState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + EHCIState ehci; +} EHCISysBusState; + +typedef struct SysBusEHCIClass { + /*< private >*/ + SysBusDeviceClass parent_class; + /*< public >*/ + + uint16_t capsbase; + uint16_t opregbase; +} SysBusEHCIClass; + +#endif diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c index fa9385ee49..64e9e834bf 100644 --- a/hw/usb/hcd-musb.c +++ b/hw/usb/hcd-musb.c @@ -21,7 +21,7 @@ * Only host-mode and non-DMA accesses are currently supported. */ #include "qemu-common.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "hw/usb.h" #include "hw/irq.h" #include "hw/hw.h" @@ -607,7 +607,6 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep, { USBDevice *dev; USBEndpoint *uep; - int ret; int idx = epnum && dir; int ttype; @@ -626,19 +625,25 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep, /* A wild guess on the FADDR semantics... */ dev = usb_find_device(&s->port, ep->faddr[idx]); uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf); - usb_packet_setup(&ep->packey[dir].p, pid, uep); + usb_packet_setup(&ep->packey[dir].p, pid, uep, + (dev->addr << 16) | (uep->nr << 8) | pid, false, true); usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len); ep->packey[dir].ep = ep; ep->packey[dir].dir = dir; - ret = usb_handle_packet(dev, &ep->packey[dir].p); + usb_handle_packet(dev, &ep->packey[dir].p); - if (ret == USB_RET_ASYNC) { + if (ep->packey[dir].p.status == USB_RET_ASYNC) { + usb_device_flush_ep_queue(dev, uep); ep->status[dir] = len; return; } - ep->status[dir] = ret; + if (ep->packey[dir].p.status == USB_RET_SUCCESS) { + ep->status[dir] = ep->packey[dir].p.actual_length; + } else { + ep->status[dir] = ep->packey[dir].p.status; + } musb_schedule_cb(&s->port, &ep->packey[dir].p); } @@ -752,7 +757,6 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque) if (ep->status[1] == USB_RET_STALL) { ep->status[1] = 0; - packey->result = 0; ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL; if (!epnum) @@ -791,14 +795,12 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque) /* TODO: check len for over/underruns of an OUT packet? */ /* TODO: perhaps make use of e->ext_size[1] here. */ - packey->result = ep->status[1]; - if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) { ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY; if (!epnum) ep->csr[0] |= MGC_M_CSR0_RXPKTRDY; - ep->rxcount = packey->result; /* XXX: MIN(packey->len, ep->maxp[1]); */ + ep->rxcount = ep->status[1]; /* XXX: MIN(packey->len, ep->maxp[1]); */ /* In DMA mode: assert DMA request for this EP */ } @@ -1235,7 +1237,7 @@ static void musb_ep_writeh(void *opaque, int ep, int addr, uint16_t value) } /* Generic control */ -static uint32_t musb_readb(void *opaque, target_phys_addr_t addr) +static uint32_t musb_readb(void *opaque, hwaddr addr) { MUSBState *s = (MUSBState *) opaque; int ep, i; @@ -1297,7 +1299,7 @@ static uint32_t musb_readb(void *opaque, target_phys_addr_t addr) }; } -static void musb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) +static void musb_writeb(void *opaque, hwaddr addr, uint32_t value) { MUSBState *s = (MUSBState *) opaque; int ep; @@ -1384,7 +1386,7 @@ static void musb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) }; } -static uint32_t musb_readh(void *opaque, target_phys_addr_t addr) +static uint32_t musb_readh(void *opaque, hwaddr addr) { MUSBState *s = (MUSBState *) opaque; int ep, i; @@ -1438,7 +1440,7 @@ static uint32_t musb_readh(void *opaque, target_phys_addr_t addr) }; } -static void musb_writeh(void *opaque, target_phys_addr_t addr, uint32_t value) +static void musb_writeh(void *opaque, hwaddr addr, uint32_t value) { MUSBState *s = (MUSBState *) opaque; int ep; @@ -1494,7 +1496,7 @@ static void musb_writeh(void *opaque, target_phys_addr_t addr, uint32_t value) }; } -static uint32_t musb_readw(void *opaque, target_phys_addr_t addr) +static uint32_t musb_readw(void *opaque, hwaddr addr) { MUSBState *s = (MUSBState *) opaque; int ep; @@ -1512,7 +1514,7 @@ static uint32_t musb_readw(void *opaque, target_phys_addr_t addr) }; } -static void musb_writew(void *opaque, target_phys_addr_t addr, uint32_t value) +static void musb_writew(void *opaque, hwaddr addr, uint32_t value) { MUSBState *s = (MUSBState *) opaque; int ep; diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 844e7ed166..29bafa6da9 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -27,9 +27,9 @@ */ #include "hw/hw.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "hw/usb.h" -#include "hw/pci.h" +#include "hw/pci/pci.h" #include "hw/sysbus.h" #include "hw/qdev-dma.h" @@ -430,6 +430,23 @@ static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr) return NULL; } +static void ohci_stop_endpoints(OHCIState *ohci) +{ + USBDevice *dev; + int i, j; + + for (i = 0; i < ohci->num_ports; i++) { + dev = ohci->rhport[i].port.dev; + if (dev && dev->attached) { + usb_device_ep_stopped(dev, &dev->ep_ctl); + for (j = 0; j < USB_MAX_ENDPOINTS; j++) { + usb_device_ep_stopped(dev, &dev->ep_in[j]); + usb_device_ep_stopped(dev, &dev->ep_out[j]); + } + } + } +} + /* Reset the controller */ static void ohci_reset(void *opaque) { @@ -478,6 +495,7 @@ static void ohci_reset(void *opaque) usb_cancel_packet(&ohci->usb_packet); ohci->async_td = 0; } + ohci_stop_endpoints(ohci); DPRINTF("usb-ohci: Reset %s\n", ohci->name); } @@ -807,18 +825,24 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, DMA_DIRECTION_TO_DEVICE); } - if (completion) { - ret = ohci->usb_packet.result; - } else { + if (!completion) { + bool int_req = relative_frame_number == frame_count && + OHCI_BM(iso_td.flags, TD_DI) == 0; dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN)); - usb_packet_setup(&ohci->usb_packet, pid, ep); + usb_packet_setup(&ohci->usb_packet, pid, ep, addr, false, int_req); usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len); - ret = usb_handle_packet(dev, &ohci->usb_packet); - if (ret == USB_RET_ASYNC) { + usb_handle_packet(dev, &ohci->usb_packet); + if (ohci->usb_packet.status == USB_RET_ASYNC) { + usb_device_flush_ep_queue(dev, ep); return 1; } } + if (ohci->usb_packet.status == USB_RET_SUCCESS) { + ret = ohci->usb_packet.actual_length; + } else { + ret = ohci->usb_packet.status; + } #ifdef DEBUG_ISOCH printf("so 0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu ret %d\n", @@ -994,7 +1018,6 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) } #endif if (completion) { - ret = ohci->usb_packet.result; ohci->async_td = 0; ohci->async_complete = 0; } else { @@ -1011,17 +1034,25 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) } dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN)); - usb_packet_setup(&ohci->usb_packet, pid, ep); + usb_packet_setup(&ohci->usb_packet, pid, ep, addr, !flag_r, + OHCI_BM(td.flags, TD_DI) == 0); usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen); - ret = usb_handle_packet(dev, &ohci->usb_packet); + usb_handle_packet(dev, &ohci->usb_packet); #ifdef DEBUG_PACKET - DPRINTF("ret=%d\n", ret); + DPRINTF("status=%d\n", ohci->usb_packet.status); #endif - if (ret == USB_RET_ASYNC) { + if (ohci->usb_packet.status == USB_RET_ASYNC) { + usb_device_flush_ep_queue(dev, ep); ohci->async_td = addr; return 1; } } + if (ohci->usb_packet.status == USB_RET_SUCCESS) { + ret = ohci->usb_packet.actual_length; + } else { + ret = ohci->usb_packet.status; + } + if (ret >= 0) { if (dir == OHCI_TD_DIR_IN) { ohci_copy_td(ohci, &td, ohci->usb_buf, ret, @@ -1134,6 +1165,8 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) if (ohci->async_td && addr == ohci->async_td) { usb_cancel_packet(&ohci->usb_packet); ohci->async_td = 0; + usb_device_ep_stopped(ohci->usb_packet.ep->dev, + ohci->usb_packet.ep); } continue; } @@ -1214,10 +1247,12 @@ static void ohci_frame_boundary(void *opaque) } /* Cancel all pending packets if either of the lists has been disabled. */ - if (ohci->async_td && - ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) { - usb_cancel_packet(&ohci->usb_packet); - ohci->async_td = 0; + if (ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) { + if (ohci->async_td) { + usb_cancel_packet(&ohci->usb_packet); + ohci->async_td = 0; + } + ohci_stop_endpoints(ohci); } ohci->old_ctl = ohci->ctl; ohci_process_lists(ohci, 0); @@ -1470,12 +1505,10 @@ static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) if (old_state != port->ctrl) ohci_set_interrupt(ohci, OHCI_INTR_RHSC); - - return; } static uint64_t ohci_mem_read(void *opaque, - target_phys_addr_t addr, + hwaddr addr, unsigned size) { OHCIState *ohci = opaque; @@ -1598,7 +1631,7 @@ static uint64_t ohci_mem_read(void *opaque, } static void ohci_mem_write(void *opaque, - target_phys_addr_t addr, + hwaddr addr, uint64_t val, unsigned size) { @@ -1848,7 +1881,7 @@ static int ohci_init_pxa(SysBusDevice *dev) /* Cannot fail as we pass NULL for masterbus */ usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset, NULL, 0, - NULL); + &dma_context_memory); sysbus_init_irq(dev, &s->ohci.irq); sysbus_init_mmio(dev, &s->ohci.mem); @@ -1871,6 +1904,7 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_APPLE; k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB; k->class_id = PCI_CLASS_SERIAL_USB; + k->no_hotplug = 1; dc->desc = "Apple USB Controller"; dc->props = ohci_pci_properties; } diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 1ace2a41da..60645aa21f 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -27,10 +27,10 @@ */ #include "hw/hw.h" #include "hw/usb.h" -#include "hw/pci.h" -#include "qemu-timer.h" -#include "iov.h" -#include "dma.h" +#include "hw/pci/pci.h" +#include "qemu/timer.h" +#include "qemu/iov.h" +#include "sysemu/dma.h" #include "trace.h" //#define DEBUG @@ -75,6 +75,11 @@ #define FRAME_MAX_LOOPS 256 +/* Must be large enough to handle 10 frame delay for initial isoc requests */ +#define QH_VALID 32 + +#define MAX_FRAMES_PER_TICK (QH_VALID / 2) + #define NB_PORTS 2 enum { @@ -88,6 +93,23 @@ enum { typedef struct UHCIState UHCIState; typedef struct UHCIAsync UHCIAsync; typedef struct UHCIQueue UHCIQueue; +typedef struct UHCIInfo UHCIInfo; +typedef struct UHCIPCIDeviceClass UHCIPCIDeviceClass; + +struct UHCIInfo { + const char *name; + uint16_t vendor_id; + uint16_t device_id; + uint8_t revision; + uint8_t irq_pin; + int (*initfn)(PCIDevice *dev); + bool unplug; +}; + +struct UHCIPCIDeviceClass { + PCIDeviceClass parent_class; + UHCIInfo info; +}; /* * Pending async transaction. @@ -100,16 +122,17 @@ struct UHCIAsync { QEMUSGList sgl; UHCIQueue *queue; QTAILQ_ENTRY(UHCIAsync) next; - uint32_t td; - uint8_t isoc; + uint32_t td_addr; uint8_t done; }; struct UHCIQueue { + uint32_t qh_addr; uint32_t token; UHCIState *uhci; + USBEndpoint *ep; QTAILQ_ENTRY(UHCIQueue) next; - QTAILQ_HEAD(, UHCIAsync) asyncs; + QTAILQ_HEAD(asyncs_head, UHCIAsync) asyncs; int8_t valid; }; @@ -134,6 +157,7 @@ struct UHCIState { QEMUBH *bh; uint32_t frame_bytes; uint32_t frame_bandwidth; + bool completions_only; UHCIPort ports[NB_PORTS]; /* Interrupts that should be raised at the end of the current frame. */ @@ -147,6 +171,7 @@ struct UHCIState { /* Properties */ char *masterbus; uint32_t firstport; + uint32_t maxframes; }; typedef struct UHCI_TD { @@ -161,57 +186,93 @@ typedef struct UHCI_QH { uint32_t el_link; } UHCI_QH; +static void uhci_async_cancel(UHCIAsync *async); +static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td); + static inline int32_t uhci_queue_token(UHCI_TD *td) { - /* covers ep, dev, pid -> identifies the endpoint */ - return td->token & 0x7ffff; + if ((td->token & (0xf << 15)) == 0) { + /* ctrl ep, cover ep and dev, not pid! */ + return td->token & 0x7ff00; + } else { + /* covers ep, dev, pid -> identifies the endpoint */ + return td->token & 0x7ffff; + } } -static UHCIQueue *uhci_queue_get(UHCIState *s, UHCI_TD *td) +static UHCIQueue *uhci_queue_new(UHCIState *s, uint32_t qh_addr, UHCI_TD *td, + USBEndpoint *ep) { - uint32_t token = uhci_queue_token(td); UHCIQueue *queue; - QTAILQ_FOREACH(queue, &s->queues, next) { - if (queue->token == token) { - return queue; - } - } - queue = g_new0(UHCIQueue, 1); queue->uhci = s; - queue->token = token; + queue->qh_addr = qh_addr; + queue->token = uhci_queue_token(td); + queue->ep = ep; QTAILQ_INIT(&queue->asyncs); QTAILQ_INSERT_HEAD(&s->queues, queue, next); + queue->valid = QH_VALID; trace_usb_uhci_queue_add(queue->token); return queue; } -static void uhci_queue_free(UHCIQueue *queue) +static void uhci_queue_free(UHCIQueue *queue, const char *reason) { UHCIState *s = queue->uhci; + UHCIAsync *async; + + while (!QTAILQ_EMPTY(&queue->asyncs)) { + async = QTAILQ_FIRST(&queue->asyncs); + uhci_async_cancel(async); + } + usb_device_ep_stopped(queue->ep->dev, queue->ep); - trace_usb_uhci_queue_del(queue->token); + trace_usb_uhci_queue_del(queue->token, reason); QTAILQ_REMOVE(&s->queues, queue, next); g_free(queue); } -static UHCIAsync *uhci_async_alloc(UHCIQueue *queue, uint32_t addr) +static UHCIQueue *uhci_queue_find(UHCIState *s, UHCI_TD *td) +{ + uint32_t token = uhci_queue_token(td); + UHCIQueue *queue; + + QTAILQ_FOREACH(queue, &s->queues, next) { + if (queue->token == token) { + return queue; + } + } + return NULL; +} + +static bool uhci_queue_verify(UHCIQueue *queue, uint32_t qh_addr, UHCI_TD *td, + uint32_t td_addr, bool queuing) +{ + UHCIAsync *first = QTAILQ_FIRST(&queue->asyncs); + + return queue->qh_addr == qh_addr && + queue->token == uhci_queue_token(td) && + (queuing || !(td->ctrl & TD_CTRL_ACTIVE) || first == NULL || + first->td_addr == td_addr); +} + +static UHCIAsync *uhci_async_alloc(UHCIQueue *queue, uint32_t td_addr) { UHCIAsync *async = g_new0(UHCIAsync, 1); async->queue = queue; - async->td = addr; + async->td_addr = td_addr; usb_packet_init(&async->packet); pci_dma_sglist_init(&async->sgl, &queue->uhci->dev, 1); - trace_usb_uhci_packet_add(async->queue->token, async->td); + trace_usb_uhci_packet_add(async->queue->token, async->td_addr); return async; } static void uhci_async_free(UHCIAsync *async) { - trace_usb_uhci_packet_del(async->queue->token, async->td); + trace_usb_uhci_packet_del(async->queue->token, async->td_addr); usb_packet_cleanup(&async->packet); qemu_sglist_destroy(&async->sgl); g_free(async); @@ -221,21 +282,24 @@ static void uhci_async_link(UHCIAsync *async) { UHCIQueue *queue = async->queue; QTAILQ_INSERT_TAIL(&queue->asyncs, async, next); - trace_usb_uhci_packet_link_async(async->queue->token, async->td); + trace_usb_uhci_packet_link_async(async->queue->token, async->td_addr); } static void uhci_async_unlink(UHCIAsync *async) { UHCIQueue *queue = async->queue; QTAILQ_REMOVE(&queue->asyncs, async, next); - trace_usb_uhci_packet_unlink_async(async->queue->token, async->td); + trace_usb_uhci_packet_unlink_async(async->queue->token, async->td_addr); } static void uhci_async_cancel(UHCIAsync *async) { - trace_usb_uhci_packet_cancel(async->queue->token, async->td, async->done); + uhci_async_unlink(async); + trace_usb_uhci_packet_cancel(async->queue->token, async->td_addr, + async->done); if (!async->done) usb_cancel_packet(&async->packet); + usb_packet_unmap(&async->packet, &async->sgl); uhci_async_free(async); } @@ -258,34 +322,21 @@ static void uhci_async_validate_begin(UHCIState *s) static void uhci_async_validate_end(UHCIState *s) { UHCIQueue *queue, *n; - UHCIAsync *async; QTAILQ_FOREACH_SAFE(queue, &s->queues, next, n) { - if (queue->valid > 0) { - continue; - } - while (!QTAILQ_EMPTY(&queue->asyncs)) { - async = QTAILQ_FIRST(&queue->asyncs); - uhci_async_unlink(async); - uhci_async_cancel(async); + if (!queue->valid) { + uhci_queue_free(queue, "validate-end"); } - uhci_queue_free(queue); } } static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev) { - UHCIQueue *queue; - UHCIAsync *curr, *n; + UHCIQueue *queue, *n; - QTAILQ_FOREACH(queue, &s->queues, next) { - QTAILQ_FOREACH_SAFE(curr, &queue->asyncs, next, n) { - if (!usb_packet_is_inflight(&curr->packet) || - curr->packet.ep->dev != dev) { - continue; - } - uhci_async_unlink(curr); - uhci_async_cancel(curr); + QTAILQ_FOREACH_SAFE(queue, &s->queues, next, n) { + if (queue->ep->dev == dev) { + uhci_queue_free(queue, "cancel-device"); } } } @@ -293,38 +344,24 @@ static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev) static void uhci_async_cancel_all(UHCIState *s) { UHCIQueue *queue, *nq; - UHCIAsync *curr, *n; QTAILQ_FOREACH_SAFE(queue, &s->queues, next, nq) { - QTAILQ_FOREACH_SAFE(curr, &queue->asyncs, next, n) { - uhci_async_unlink(curr); - uhci_async_cancel(curr); - } - uhci_queue_free(queue); + uhci_queue_free(queue, "cancel-all"); } } -static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, UHCI_TD *td) +static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t td_addr) { - uint32_t token = uhci_queue_token(td); UHCIQueue *queue; UHCIAsync *async; QTAILQ_FOREACH(queue, &s->queues, next) { - if (queue->token == token) { - break; - } - } - if (queue == NULL) { - return NULL; - } - - QTAILQ_FOREACH(async, &queue->asyncs, next) { - if (async->td == addr) { - return async; + QTAILQ_FOREACH(async, &queue->asyncs, next) { + if (async->td_addr == td_addr) { + return async; + } } } - return NULL; } @@ -401,7 +438,7 @@ static int uhci_post_load(void *opaque, int version_id) static const VMStateDescription vmstate_uhci = { .name = "uhci", - .version_id = 2, + .version_id = 3, .minimum_version_id = 1, .minimum_version_id_old = 1, .post_load = uhci_post_load, @@ -419,44 +456,16 @@ static const VMStateDescription vmstate_uhci = { VMSTATE_UINT8(status2, UHCIState), VMSTATE_TIMER(frame_timer, UHCIState), VMSTATE_INT64_V(expire_time, UHCIState, 2), + VMSTATE_UINT32_V(pending_int_mask, UHCIState, 3), VMSTATE_END_OF_LIST() } }; -static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) -{ - UHCIState *s = opaque; - - addr &= 0x1f; - switch(addr) { - case 0x0c: - s->sof_timing = val; - break; - } -} - -static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr) -{ - UHCIState *s = opaque; - uint32_t val; - - addr &= 0x1f; - switch(addr) { - case 0x0c: - val = s->sof_timing; - break; - default: - val = 0xff; - break; - } - return val; -} - -static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) +static void uhci_port_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { UHCIState *s = opaque; - addr &= 0x1f; trace_usb_uhci_mmio_writew(addr, val); switch(addr) { @@ -466,7 +475,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) trace_usb_uhci_schedule_start(); s->expire_time = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / FRAME_TIMER_FREQ); - qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock)); + qemu_mod_timer(s->frame_timer, s->expire_time); s->status &= ~UHCI_STS_HCHALTED; } else if (!(val & UHCI_CMD_RS)) { s->status |= UHCI_STS_HCHALTED; @@ -505,6 +514,17 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) if (s->status & UHCI_STS_HCHALTED) s->frnum = val & 0x7ff; break; + case 0x08: + s->fl_base_addr &= 0xffff0000; + s->fl_base_addr |= val & ~0xfff; + break; + case 0x0a: + s->fl_base_addr &= 0x0000ffff; + s->fl_base_addr |= (val << 16); + break; + case 0x0c: + s->sof_timing = val & 0xff; + break; case 0x10 ... 0x1f: { UHCIPort *port; @@ -524,6 +544,10 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) } } port->ctrl &= UHCI_PORT_READ_ONLY; + /* enabled may only be set if a device is connected */ + if (!(port->ctrl & UHCI_PORT_CCS)) { + val &= ~UHCI_PORT_EN; + } port->ctrl |= (val & ~UHCI_PORT_READ_ONLY); /* some bits are reset when a '1' is written to them */ port->ctrl &= ~(val & UHCI_PORT_WRITE_CLEAR); @@ -532,12 +556,11 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr) +static uint64_t uhci_port_read(void *opaque, hwaddr addr, unsigned size) { UHCIState *s = opaque; uint32_t val; - addr &= 0x1f; switch(addr) { case 0x00: val = s->cmd; @@ -551,6 +574,15 @@ static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr) case 0x06: val = s->frnum; break; + case 0x08: + val = s->fl_base_addr & 0xffff; + break; + case 0x0a: + val = (s->fl_base_addr >> 16) & 0xffff; + break; + case 0x0c: + val = s->sof_timing; + break; case 0x10 ... 0x1f: { UHCIPort *port; @@ -573,38 +605,6 @@ static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr) return val; } -static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val) -{ - UHCIState *s = opaque; - - addr &= 0x1f; - trace_usb_uhci_mmio_writel(addr, val); - - switch(addr) { - case 0x08: - s->fl_base_addr = val & ~0xfff; - break; - } -} - -static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr) -{ - UHCIState *s = opaque; - uint32_t val; - - addr &= 0x1f; - switch(addr) { - case 0x08: - val = s->fl_base_addr; - break; - default: - val = 0xffffffff; - break; - } - trace_usb_uhci_mmio_readl(addr, val); - return val; -} - /* signal resume if controller suspended */ static void uhci_resume (void *opaque) { @@ -695,30 +695,75 @@ static USBDevice *uhci_find_device(UHCIState *s, uint8_t addr) return NULL; } -static void uhci_async_complete(USBPort *port, USBPacket *packet); -static void uhci_process_frame(UHCIState *s); +static void uhci_read_td(UHCIState *s, UHCI_TD *td, uint32_t link) +{ + pci_dma_read(&s->dev, link & ~0xf, td, sizeof(*td)); + le32_to_cpus(&td->link); + le32_to_cpus(&td->ctrl); + le32_to_cpus(&td->token); + le32_to_cpus(&td->buffer); +} + +static int uhci_handle_td_error(UHCIState *s, UHCI_TD *td, uint32_t td_addr, + int status, uint32_t *int_mask) +{ + uint32_t queue_token = uhci_queue_token(td); + int ret; + + switch (status) { + case USB_RET_NAK: + td->ctrl |= TD_CTRL_NAK; + return TD_RESULT_NEXT_QH; + + case USB_RET_STALL: + td->ctrl |= TD_CTRL_STALL; + trace_usb_uhci_packet_complete_stall(queue_token, td_addr); + ret = TD_RESULT_NEXT_QH; + break; + + case USB_RET_BABBLE: + td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL; + /* frame interrupted */ + trace_usb_uhci_packet_complete_babble(queue_token, td_addr); + ret = TD_RESULT_STOP_FRAME; + break; + + case USB_RET_IOERROR: + case USB_RET_NODEV: + default: + td->ctrl |= TD_CTRL_TIMEOUT; + td->ctrl &= ~(3 << TD_CTRL_ERROR_SHIFT); + trace_usb_uhci_packet_complete_error(queue_token, td_addr); + ret = TD_RESULT_NEXT_QH; + break; + } + + td->ctrl &= ~TD_CTRL_ACTIVE; + s->status |= UHCI_STS_USBERR; + if (td->ctrl & TD_CTRL_IOC) { + *int_mask |= 0x01; + } + uhci_update_irq(s); + return ret; +} -/* return -1 if fatal error (frame must be stopped) - 0 if TD successful - 1 if TD unsuccessful or inactive -*/ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_t *int_mask) { - int len = 0, max_len, err, ret; + int len = 0, max_len; uint8_t pid; max_len = ((td->token >> 21) + 1) & 0x7ff; pid = td->token & 0xff; - ret = async->packet.result; - if (td->ctrl & TD_CTRL_IOS) td->ctrl &= ~TD_CTRL_ACTIVE; - if (ret < 0) - goto out; + if (async->packet.status != USB_RET_SUCCESS) { + return uhci_handle_td_error(s, td, async->td_addr, + async->packet.status, int_mask); + } - len = async->packet.result; + len = async->packet.actual_length; td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff); /* The NAK bit may have been set by a previous frame, so clear it @@ -729,163 +774,151 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_ *int_mask |= 0x01; if (pid == USB_TOKEN_IN) { - if (len > max_len) { - ret = USB_RET_BABBLE; - goto out; - } - if ((td->ctrl & TD_CTRL_SPD) && len < max_len) { *int_mask |= 0x02; /* short packet: do not update QH */ trace_usb_uhci_packet_complete_shortxfer(async->queue->token, - async->td); + async->td_addr); return TD_RESULT_NEXT_QH; } } /* success */ - trace_usb_uhci_packet_complete_success(async->queue->token, async->td); + trace_usb_uhci_packet_complete_success(async->queue->token, + async->td_addr); return TD_RESULT_COMPLETE; +} -out: - switch(ret) { - case USB_RET_STALL: - td->ctrl |= TD_CTRL_STALL; - td->ctrl &= ~TD_CTRL_ACTIVE; - s->status |= UHCI_STS_USBERR; - if (td->ctrl & TD_CTRL_IOC) { - *int_mask |= 0x01; - } - uhci_update_irq(s); - trace_usb_uhci_packet_complete_stall(async->queue->token, async->td); - return TD_RESULT_NEXT_QH; +static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, + UHCI_TD *td, uint32_t td_addr, uint32_t *int_mask) +{ + int ret, max_len; + bool spd; + bool queuing = (q != NULL); + uint8_t pid = td->token & 0xff; + UHCIAsync *async = uhci_async_find_td(s, td_addr); - case USB_RET_BABBLE: - td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL; - td->ctrl &= ~TD_CTRL_ACTIVE; - s->status |= UHCI_STS_USBERR; - if (td->ctrl & TD_CTRL_IOC) { - *int_mask |= 0x01; + if (async) { + if (uhci_queue_verify(async->queue, qh_addr, td, td_addr, queuing)) { + assert(q == NULL || q == async->queue); + q = async->queue; + } else { + uhci_queue_free(async->queue, "guest re-used pending td"); + async = NULL; } - uhci_update_irq(s); - /* frame interrupted */ - trace_usb_uhci_packet_complete_babble(async->queue->token, async->td); - return TD_RESULT_STOP_FRAME; - - case USB_RET_NAK: - td->ctrl |= TD_CTRL_NAK; - if (pid == USB_TOKEN_SETUP) - break; - return TD_RESULT_NEXT_QH; - - case USB_RET_IOERROR: - case USB_RET_NODEV: - default: - break; } - /* Retry the TD if error count is not zero */ - - td->ctrl |= TD_CTRL_TIMEOUT; - err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3; - if (err != 0) { - err--; - if (err == 0) { - td->ctrl &= ~TD_CTRL_ACTIVE; - s->status |= UHCI_STS_USBERR; - if (td->ctrl & TD_CTRL_IOC) - *int_mask |= 0x01; - uhci_update_irq(s); - trace_usb_uhci_packet_complete_error(async->queue->token, - async->td); + if (q == NULL) { + q = uhci_queue_find(s, td); + if (q && !uhci_queue_verify(q, qh_addr, td, td_addr, queuing)) { + uhci_queue_free(q, "guest re-used qh"); + q = NULL; } } - td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | - (err << TD_CTRL_ERROR_SHIFT); - return TD_RESULT_NEXT_QH; -} -static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, - uint32_t *int_mask, bool queuing) -{ - UHCIAsync *async; - int len = 0, max_len; - uint8_t pid; - USBDevice *dev; - USBEndpoint *ep; + if (q) { + q->valid = QH_VALID; + } /* Is active ? */ - if (!(td->ctrl & TD_CTRL_ACTIVE)) + if (!(td->ctrl & TD_CTRL_ACTIVE)) { + if (async) { + /* Guest marked a pending td non-active, cancel the queue */ + uhci_queue_free(async->queue, "pending td non-active"); + } + /* + * ehci11d spec page 22: "Even if the Active bit in the TD is already + * cleared when the TD is fetched ... an IOC interrupt is generated" + */ + if (td->ctrl & TD_CTRL_IOC) { + *int_mask |= 0x01; + } return TD_RESULT_NEXT_QH; + } - async = uhci_async_find_td(s, addr, td); if (async) { - /* Already submitted */ - async->queue->valid = 32; - - if (!async->done) - return TD_RESULT_ASYNC_CONT; if (queuing) { /* we are busy filling the queue, we are not prepared to consume completed packages then, just leave them in async state */ return TD_RESULT_ASYNC_CONT; } + if (!async->done) { + UHCI_TD last_td; + UHCIAsync *last = QTAILQ_LAST(&async->queue->asyncs, asyncs_head); + /* + * While we are waiting for the current td to complete, the guest + * may have added more tds to the queue. Note we re-read the td + * rather then caching it, as we want to see guest made changes! + */ + uhci_read_td(s, &last_td, last->td_addr); + uhci_queue_fill(async->queue, &last_td); + return TD_RESULT_ASYNC_CONT; + } uhci_async_unlink(async); goto done; } + if (s->completions_only) { + return TD_RESULT_ASYNC_CONT; + } + /* Allocate new packet */ - async = uhci_async_alloc(uhci_queue_get(s, td), addr); + if (q == NULL) { + USBDevice *dev = uhci_find_device(s, (td->token >> 8) & 0x7f); + USBEndpoint *ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf); - /* valid needs to be large enough to handle 10 frame delay - * for initial isochronous requests - */ - async->queue->valid = 32; - async->isoc = td->ctrl & TD_CTRL_IOS; + if (ep == NULL) { + return uhci_handle_td_error(s, td, td_addr, USB_RET_NODEV, + int_mask); + } + q = uhci_queue_new(s, qh_addr, td, ep); + } + async = uhci_async_alloc(q, td_addr); max_len = ((td->token >> 21) + 1) & 0x7ff; - pid = td->token & 0xff; - - dev = uhci_find_device(s, (td->token >> 8) & 0x7f); - ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf); - usb_packet_setup(&async->packet, pid, ep); + spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0); + usb_packet_setup(&async->packet, pid, q->ep, td_addr, spd, + (td->ctrl & TD_CTRL_IOC) != 0); qemu_sglist_add(&async->sgl, td->buffer, max_len); usb_packet_map(&async->packet, &async->sgl); switch(pid) { case USB_TOKEN_OUT: case USB_TOKEN_SETUP: - len = usb_handle_packet(dev, &async->packet); - if (len >= 0) - len = max_len; + usb_handle_packet(q->ep->dev, &async->packet); + if (async->packet.status == USB_RET_SUCCESS) { + async->packet.actual_length = max_len; + } break; case USB_TOKEN_IN: - len = usb_handle_packet(dev, &async->packet); + usb_handle_packet(q->ep->dev, &async->packet); break; default: /* invalid pid : frame interrupted */ + usb_packet_unmap(&async->packet, &async->sgl); uhci_async_free(async); s->status |= UHCI_STS_HCPERR; uhci_update_irq(s); return TD_RESULT_STOP_FRAME; } - - if (len == USB_RET_ASYNC) { + + if (async->packet.status == USB_RET_ASYNC) { uhci_async_link(async); + if (!queuing) { + uhci_queue_fill(q, td); + } return TD_RESULT_ASYNC_START; } - async->packet.result = len; - done: - len = uhci_complete_td(s, td, async, int_mask); + ret = uhci_complete_td(s, td, async, int_mask); usb_packet_unmap(&async->packet, &async->sgl); uhci_async_free(async); - return len; + return ret; } static void uhci_async_complete(USBPort *port, USBPacket *packet) @@ -893,31 +926,15 @@ static void uhci_async_complete(USBPort *port, USBPacket *packet) UHCIAsync *async = container_of(packet, UHCIAsync, packet); UHCIState *s = async->queue->uhci; - if (async->isoc) { - UHCI_TD td; - uint32_t link = async->td; - uint32_t int_mask = 0, val; - - pci_dma_read(&s->dev, link & ~0xf, &td, sizeof(td)); - le32_to_cpus(&td.link); - le32_to_cpus(&td.ctrl); - le32_to_cpus(&td.token); - le32_to_cpus(&td.buffer); - - uhci_async_unlink(async); - uhci_complete_td(s, &td, async, &int_mask); - s->pending_int_mask |= int_mask; - - /* update the status bits of the TD */ - val = cpu_to_le32(td.ctrl); - pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val)); - uhci_async_free(async); - } else { - async->done = 1; - if (s->frame_bytes < s->frame_bandwidth) { - qemu_bh_schedule(s->bh); - } + if (packet->status == USB_RET_REMOVE_FROM_QUEUE) { + uhci_async_cancel(async); + return; } + + async->done = 1; + /* Force processing of this packet *now*, needed for migration */ + s->completions_only = true; + qemu_bh_schedule(s->bh); } static int is_valid(uint32_t link) @@ -962,28 +979,23 @@ static int qhdb_insert(QhDb *db, uint32_t addr) return 0; } -static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) +static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td) { uint32_t int_mask = 0; uint32_t plink = td->link; - uint32_t token = uhci_queue_token(td); UHCI_TD ptd; int ret; while (is_valid(plink)) { - pci_dma_read(&s->dev, plink & ~0xf, &ptd, sizeof(ptd)); - le32_to_cpus(&ptd.link); - le32_to_cpus(&ptd.ctrl); - le32_to_cpus(&ptd.token); - le32_to_cpus(&ptd.buffer); + uhci_read_td(q->uhci, &ptd, plink); if (!(ptd.ctrl & TD_CTRL_ACTIVE)) { break; } - if (uhci_queue_token(&ptd) != token) { + if (uhci_queue_token(&ptd) != q->token) { break; } trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token); - ret = uhci_handle_td(s, plink, &ptd, &int_mask, true); + ret = uhci_handle_td(q->uhci, q, q->qh_addr, &ptd, plink, &int_mask); if (ret == TD_RESULT_ASYNC_CONT) { break; } @@ -991,6 +1003,7 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) assert(int_mask == 0); plink = ptd.link; } + usb_device_flush_ep_queue(q->ep->dev, q->ep); } static void uhci_process_frame(UHCIState *s) @@ -1013,7 +1026,7 @@ static void uhci_process_frame(UHCIState *s) qhdb_reset(&qhdb); for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) { - if (s->frame_bytes >= s->frame_bandwidth) { + if (!s->completions_only && s->frame_bytes >= s->frame_bandwidth) { /* We've reached the usb 1.1 bandwidth, which is 1280 bytes/frame, stop processing */ trace_usb_uhci_frame_stop_bandwidth(); @@ -1059,15 +1072,11 @@ static void uhci_process_frame(UHCIState *s) } /* TD */ - pci_dma_read(&s->dev, link & ~0xf, &td, sizeof(td)); - le32_to_cpus(&td.link); - le32_to_cpus(&td.ctrl); - le32_to_cpus(&td.token); - le32_to_cpus(&td.buffer); + uhci_read_td(s, &td, link); trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token); old_td_ctrl = td.ctrl; - ret = uhci_handle_td(s, link, &td, &int_mask, false); + ret = uhci_handle_td(s, NULL, curr_qh, &td, link, &int_mask); if (old_td_ctrl != td.ctrl) { /* update the status bits of the TD */ val = cpu_to_le32(td.ctrl); @@ -1086,9 +1095,6 @@ static void uhci_process_frame(UHCIState *s) case TD_RESULT_ASYNC_START: trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf); - if (is_valid(td.link)) { - uhci_fill_queue(s, &td); - } link = curr_qh ? qh.link : td.link; continue; @@ -1132,10 +1138,11 @@ static void uhci_bh(void *opaque) static void uhci_frame_timer(void *opaque) { UHCIState *s = opaque; + uint64_t t_now, t_last_run; + int i, frames; + const uint64_t frame_t = get_ticks_per_sec() / FRAME_TIMER_FREQ; - /* prepare the timer for the next frame */ - s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ); - s->frame_bytes = 0; + s->completions_only = false; qemu_bh_cancel(s->bh); if (!(s->cmd & UHCI_CMD_RS)) { @@ -1148,7 +1155,35 @@ static void uhci_frame_timer(void *opaque) return; } - /* Complete the previous frame */ + /* We still store expire_time in our state, for migration */ + t_last_run = s->expire_time - frame_t; + t_now = qemu_get_clock_ns(vm_clock); + + /* Process up to MAX_FRAMES_PER_TICK frames */ + frames = (t_now - t_last_run) / frame_t; + if (frames > s->maxframes) { + int skipped = frames - s->maxframes; + s->expire_time += skipped * frame_t; + s->frnum = (s->frnum + skipped) & 0x7ff; + frames -= skipped; + } + if (frames > MAX_FRAMES_PER_TICK) { + frames = MAX_FRAMES_PER_TICK; + } + + for (i = 0; i < frames; i++) { + s->frame_bytes = 0; + trace_usb_uhci_frame_start(s->frnum); + uhci_async_validate_begin(s); + uhci_process_frame(s); + uhci_async_validate_end(s); + /* The spec says frnum is the frame currently being processed, and + * the guest must look at frnum - 1 on interrupt, so inc frnum now */ + s->frnum = (s->frnum + 1) & 0x7ff; + s->expire_time += frame_t; + } + + /* Complete the previous frame(s) */ if (s->pending_int_mask) { s->status2 |= s->pending_int_mask; s->status |= UHCI_STS_USBINT; @@ -1156,32 +1191,17 @@ static void uhci_frame_timer(void *opaque) } s->pending_int_mask = 0; - /* Start new frame */ - s->frnum = (s->frnum + 1) & 0x7ff; - - trace_usb_uhci_frame_start(s->frnum); - - uhci_async_validate_begin(s); - - uhci_process_frame(s); - - uhci_async_validate_end(s); - - qemu_mod_timer(s->frame_timer, s->expire_time); + qemu_mod_timer(s->frame_timer, t_now + frame_t); } -static const MemoryRegionPortio uhci_portio[] = { - { 0, 32, 2, .write = uhci_ioport_writew, }, - { 0, 32, 2, .read = uhci_ioport_readw, }, - { 0, 32, 4, .write = uhci_ioport_writel, }, - { 0, 32, 4, .read = uhci_ioport_readl, }, - { 0, 32, 1, .write = uhci_ioport_writeb, }, - { 0, 32, 1, .read = uhci_ioport_readb, }, - PORTIO_END_OF_LIST() -}; - static const MemoryRegionOps uhci_ioport_ops = { - .old_portio = uhci_portio, + .read = uhci_port_read, + .write = uhci_port_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 2, + .impl.max_access_size = 2, + .endianness = DEVICE_LITTLE_ENDIAN, }; static USBPortOps uhci_port_ops = { @@ -1198,6 +1218,7 @@ static USBBusOps uhci_bus_ops = { static int usb_uhci_common_initfn(PCIDevice *dev) { PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); + UHCIPCIDeviceClass *u = container_of(pc, UHCIPCIDeviceClass, parent_class); UHCIState *s = DO_UPCAST(UHCIState, dev, dev); uint8_t *pci_conf = s->dev.config; int i; @@ -1206,20 +1227,7 @@ static int usb_uhci_common_initfn(PCIDevice *dev) /* TODO: reset value should be 0. */ pci_conf[USB_SBRN] = USB_RELEASE_1; // release number - switch (pc->device_id) { - case PCI_DEVICE_ID_INTEL_82801I_UHCI1: - s->irq_pin = 0; /* A */ - break; - case PCI_DEVICE_ID_INTEL_82801I_UHCI2: - s->irq_pin = 1; /* B */ - break; - case PCI_DEVICE_ID_INTEL_82801I_UHCI3: - s->irq_pin = 2; /* C */ - break; - default: - s->irq_pin = 3; /* D */ - break; - } + s->irq_pin = u->info.irq_pin; pci_config_set_interrupt_pin(pci_conf, s->irq_pin + 1); if (s->masterbus) { @@ -1280,146 +1288,112 @@ static Property uhci_properties[] = { DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280), + DEFINE_PROP_UINT32("maxframes", UHCIState, maxframes, 128), DEFINE_PROP_END_OF_LIST(), }; -static void piix3_uhci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->init = usb_uhci_common_initfn; - k->exit = usb_uhci_exit; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = PCI_DEVICE_ID_INTEL_82371SB_2; - k->revision = 0x01; - k->class_id = PCI_CLASS_SERIAL_USB; - dc->vmsd = &vmstate_uhci; - dc->props = uhci_properties; -} - -static TypeInfo piix3_uhci_info = { - .name = "piix3-usb-uhci", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(UHCIState), - .class_init = piix3_uhci_class_init, -}; - -static void piix4_uhci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->init = usb_uhci_common_initfn; - k->exit = usb_uhci_exit; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = PCI_DEVICE_ID_INTEL_82371AB_2; - k->revision = 0x01; - k->class_id = PCI_CLASS_SERIAL_USB; - dc->vmsd = &vmstate_uhci; - dc->props = uhci_properties; -} - -static TypeInfo piix4_uhci_info = { - .name = "piix4-usb-uhci", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(UHCIState), - .class_init = piix4_uhci_class_init, -}; - -static void vt82c686b_uhci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->init = usb_uhci_vt82c686b_initfn; - k->exit = usb_uhci_exit; - k->vendor_id = PCI_VENDOR_ID_VIA; - k->device_id = PCI_DEVICE_ID_VIA_UHCI; - k->revision = 0x01; - k->class_id = PCI_CLASS_SERIAL_USB; - dc->vmsd = &vmstate_uhci; - dc->props = uhci_properties; -} - -static TypeInfo vt82c686b_uhci_info = { - .name = "vt82c686b-usb-uhci", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(UHCIState), - .class_init = vt82c686b_uhci_class_init, -}; - -static void ich9_uhci1_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->init = usb_uhci_common_initfn; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1; - k->revision = 0x03; - k->class_id = PCI_CLASS_SERIAL_USB; - dc->vmsd = &vmstate_uhci; - dc->props = uhci_properties; -} - -static TypeInfo ich9_uhci1_info = { - .name = "ich9-usb-uhci1", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(UHCIState), - .class_init = ich9_uhci1_class_init, -}; - -static void ich9_uhci2_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->init = usb_uhci_common_initfn; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2; - k->revision = 0x03; - k->class_id = PCI_CLASS_SERIAL_USB; - dc->vmsd = &vmstate_uhci; - dc->props = uhci_properties; -} - -static TypeInfo ich9_uhci2_info = { - .name = "ich9-usb-uhci2", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(UHCIState), - .class_init = ich9_uhci2_class_init, -}; - -static void ich9_uhci3_class_init(ObjectClass *klass, void *data) +static void uhci_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->init = usb_uhci_common_initfn; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3; - k->revision = 0x03; - k->class_id = PCI_CLASS_SERIAL_USB; + UHCIPCIDeviceClass *u = container_of(k, UHCIPCIDeviceClass, parent_class); + UHCIInfo *info = data; + + k->init = info->initfn ? info->initfn : usb_uhci_common_initfn; + k->exit = info->unplug ? usb_uhci_exit : NULL; + k->vendor_id = info->vendor_id; + k->device_id = info->device_id; + k->revision = info->revision; + k->class_id = PCI_CLASS_SERIAL_USB; + k->no_hotplug = 1; dc->vmsd = &vmstate_uhci; dc->props = uhci_properties; + u->info = *info; } -static TypeInfo ich9_uhci3_info = { - .name = "ich9-usb-uhci3", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(UHCIState), - .class_init = ich9_uhci3_class_init, +static UHCIInfo uhci_info[] = { + { + .name = "piix3-usb-uhci", + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82371SB_2, + .revision = 0x01, + .irq_pin = 3, + .unplug = true, + },{ + .name = "piix4-usb-uhci", + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82371AB_2, + .revision = 0x01, + .irq_pin = 3, + .unplug = true, + },{ + .name = "vt82c686b-usb-uhci", + .vendor_id = PCI_VENDOR_ID_VIA, + .device_id = PCI_DEVICE_ID_VIA_UHCI, + .revision = 0x01, + .irq_pin = 3, + .initfn = usb_uhci_vt82c686b_initfn, + .unplug = true, + },{ + .name = "ich9-usb-uhci1", /* 00:1d.0 */ + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1, + .revision = 0x03, + .irq_pin = 0, + .unplug = false, + },{ + .name = "ich9-usb-uhci2", /* 00:1d.1 */ + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2, + .revision = 0x03, + .irq_pin = 1, + .unplug = false, + },{ + .name = "ich9-usb-uhci3", /* 00:1d.2 */ + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3, + .revision = 0x03, + .irq_pin = 2, + .unplug = false, + },{ + .name = "ich9-usb-uhci4", /* 00:1a.0 */ + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI4, + .revision = 0x03, + .irq_pin = 0, + .unplug = false, + },{ + .name = "ich9-usb-uhci5", /* 00:1a.1 */ + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI5, + .revision = 0x03, + .irq_pin = 1, + .unplug = false, + },{ + .name = "ich9-usb-uhci6", /* 00:1a.2 */ + .vendor_id = PCI_VENDOR_ID_INTEL, + .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI6, + .revision = 0x03, + .irq_pin = 2, + .unplug = false, + } }; static void uhci_register_types(void) { - type_register_static(&piix3_uhci_info); - type_register_static(&piix4_uhci_info); - type_register_static(&vt82c686b_uhci_info); - type_register_static(&ich9_uhci1_info); - type_register_static(&ich9_uhci2_info); - type_register_static(&ich9_uhci3_info); + TypeInfo uhci_type_info = { + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(UHCIState), + .class_size = sizeof(UHCIPCIDeviceClass), + .class_init = uhci_class_init, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(uhci_info); i++) { + uhci_type_info.name = uhci_info[i].name; + uhci_type_info.class_data = uhci_info + i; + type_register(&uhci_type_info); + } } type_init(uhci_register_types) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 6c2ff024e0..9132920932 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -19,10 +19,11 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include "hw/hw.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "hw/usb.h" -#include "hw/pci.h" -#include "hw/msi.h" +#include "hw/pci/pci.h" +#include "hw/pci/msi.h" +#include "hw/pci/msix.h" #include "trace.h" //#define DEBUG_XHCI @@ -36,17 +37,14 @@ #define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \ __func__, __LINE__); abort(); } while (0) -#define MAXSLOTS 8 -#define MAXINTRS 1 +#define MAXPORTS_2 15 +#define MAXPORTS_3 15 -#define USB2_PORTS 4 -#define USB3_PORTS 4 - -#define MAXPORTS (USB2_PORTS+USB3_PORTS) +#define MAXPORTS (MAXPORTS_2+MAXPORTS_3) +#define MAXSLOTS 64 +#define MAXINTRS 16 #define TD_QUEUE 24 -#define BG_XFERS 8 -#define BG_PKTS 8 /* Very pessimistic, let's hope it's enough for all cases */ #define EV_QUEUE (((3*TD_QUEUE)+16)*MAXSLOTS) @@ -55,24 +53,28 @@ #define ER_FULL_HACK #define LEN_CAP 0x40 -#define OFF_OPER LEN_CAP #define LEN_OPER (0x400 + 0x10 * MAXPORTS) -#define OFF_RUNTIME ((OFF_OPER + LEN_OPER + 0x20) & ~0x1f) -#define LEN_RUNTIME (0x20 + MAXINTRS * 0x20) -#define OFF_DOORBELL (OFF_RUNTIME + LEN_RUNTIME) +#define LEN_RUNTIME ((MAXINTRS + 1) * 0x20) #define LEN_DOORBELL ((MAXSLOTS + 1) * 0x20) +#define OFF_OPER LEN_CAP +#define OFF_RUNTIME 0x1000 +#define OFF_DOORBELL 0x2000 +#define OFF_MSIX_TABLE 0x3000 +#define OFF_MSIX_PBA 0x3800 /* must be power of 2 */ -#define LEN_REGS 0x2000 +#define LEN_REGS 0x4000 +#if (OFF_OPER + LEN_OPER) > OFF_RUNTIME +#error Increase OFF_RUNTIME +#endif +#if (OFF_RUNTIME + LEN_RUNTIME) > OFF_DOORBELL +#error Increase OFF_DOORBELL +#endif #if (OFF_DOORBELL + LEN_DOORBELL) > LEN_REGS # error Increase LEN_REGS #endif -#if MAXINTRS > 1 -# error TODO: only one interrupter supported -#endif - /* bit definitions */ #define USBCMD_RS (1<<0) #define USBCMD_HCRST (1<<1) @@ -144,6 +146,21 @@ typedef struct XHCITRB { bool ccs; } XHCITRB; +enum { + PLS_U0 = 0, + PLS_U1 = 1, + PLS_U2 = 2, + PLS_U3 = 3, + PLS_DISABLED = 4, + PLS_RX_DETECT = 5, + PLS_INACTIVE = 6, + PLS_POLLING = 7, + PLS_RECOVERY = 8, + PLS_HOT_RESET = 9, + PLS_COMPILANCE_MODE = 10, + PLS_TEST_MODE = 11, + PLS_RESUME = 15, +}; typedef enum TRBType { TRB_RESERVED = 0, @@ -258,6 +275,10 @@ typedef enum TRBCCode { #define TRB_LK_TC (1<<1) +#define TRB_INTR_SHIFT 22 +#define TRB_INTR_MASK 0x3ff +#define TRB_INTR(t) (((t).status >> TRB_INTR_SHIFT) & TRB_INTR_MASK) + #define EP_TYPE_MASK 0x7 #define EP_TYPE_SHIFT 3 @@ -279,6 +300,18 @@ typedef enum TRBCCode { #define SLOT_CONTEXT_ENTRIES_MASK 0x1f #define SLOT_CONTEXT_ENTRIES_SHIFT 27 +typedef struct XHCIState XHCIState; + +#define get_field(data, field) \ + (((data) >> field##_SHIFT) & field##_MASK) + +#define set_field(data, newval, field) do { \ + uint32_t val = *data; \ + val &= ~(field##_MASK << field##_SHIFT); \ + val |= ((newval) & field##_MASK) << field##_SHIFT; \ + *data = val; \ + } while (0) + typedef enum EPType { ET_INVALID = 0, ET_ISO_OUT, @@ -297,64 +330,68 @@ typedef struct XHCIRing { } XHCIRing; typedef struct XHCIPort { - USBPort port; + XHCIState *xhci; uint32_t portsc; + uint32_t portnr; + USBPort *uport; + uint32_t speedmask; + char name[16]; + MemoryRegion mem; } XHCIPort; -struct XHCIState; -typedef struct XHCIState XHCIState; - typedef struct XHCITransfer { XHCIState *xhci; USBPacket packet; + QEMUSGList sgl; bool running_async; bool running_retry; bool cancelled; bool complete; - bool backgrounded; + bool int_req; unsigned int iso_pkts; unsigned int slotid; unsigned int epid; bool in_xfer; bool iso_xfer; - bool bg_xfer; unsigned int trb_count; unsigned int trb_alloced; XHCITRB *trbs; - unsigned int data_length; - unsigned int data_alloced; - uint8_t *data; - TRBCCode status; unsigned int pkts; unsigned int pktsize; unsigned int cur_pkt; + + uint64_t mfindex_kick; } XHCITransfer; typedef struct XHCIEPContext { + XHCIState *xhci; + unsigned int slotid; + unsigned int epid; + XHCIRing ring; unsigned int next_xfer; unsigned int comp_xfer; XHCITransfer transfers[TD_QUEUE]; XHCITransfer *retry; - bool bg_running; - bool bg_updating; - unsigned int next_bg; - XHCITransfer bg_transfers[BG_XFERS]; EPType type; dma_addr_t pctx; unsigned int max_psize; - bool has_bg; uint32_t state; + + /* iso xfer scheduling */ + unsigned int interval; + int64_t mfindex_last; + QEMUTimer *kick_timer; } XHCIEPContext; typedef struct XHCISlot { bool enabled; dma_addr_t ctx; - unsigned int port; + USBPort *uport; unsigned int devaddr; XHCIEPContext * eps[31]; } XHCISlot; @@ -369,15 +406,46 @@ typedef struct XHCIEvent { uint8_t epid; } XHCIEvent; +typedef struct XHCIInterrupter { + uint32_t iman; + uint32_t imod; + uint32_t erstsz; + uint32_t erstba_low; + uint32_t erstba_high; + uint32_t erdp_low; + uint32_t erdp_high; + + bool msix_used, er_pcs, er_full; + + dma_addr_t er_start; + uint32_t er_size; + unsigned int er_ep_idx; + + XHCIEvent ev_buffer[EV_QUEUE]; + unsigned int ev_buffer_put; + unsigned int ev_buffer_get; + +} XHCIInterrupter; + struct XHCIState { PCIDevice pci_dev; USBBus bus; qemu_irq irq; MemoryRegion mem; + MemoryRegion mem_cap; + MemoryRegion mem_oper; + MemoryRegion mem_runtime; + MemoryRegion mem_doorbell; const char *name; - uint32_t msi; unsigned int devaddr; + /* properties */ + uint32_t numports_2; + uint32_t numports_3; + uint32_t numintrs; + uint32_t numslots; + uint32_t flags; + /* Operational Registers */ uint32_t usbcmd; uint32_t usbsts; @@ -388,29 +456,15 @@ struct XHCIState { uint32_t dcbaap_high; uint32_t config; + USBPort uports[MAX(MAXPORTS_2, MAXPORTS_3)]; XHCIPort ports[MAXPORTS]; XHCISlot slots[MAXSLOTS]; + uint32_t numports; /* Runtime Registers */ - uint32_t mfindex; - /* note: we only support one interrupter */ - uint32_t iman; - uint32_t imod; - uint32_t erstsz; - uint32_t erstba_low; - uint32_t erstba_high; - uint32_t erdp_low; - uint32_t erdp_high; - - dma_addr_t er_start; - uint32_t er_size; - bool er_pcs; - unsigned int er_ep_idx; - bool er_full; - - XHCIEvent ev_buffer[EV_QUEUE]; - unsigned int ev_buffer_put; - unsigned int ev_buffer_get; + int64_t mfindex_start; + QEMUTimer *mfwrap_timer; + XHCIInterrupter intr[MAXINTRS]; XHCIRing cmd_ring; }; @@ -422,6 +476,18 @@ typedef struct XHCIEvRingSeg { uint32_t rsvd; } XHCIEvRingSeg; +enum xhci_flags { + XHCI_FLAG_USE_MSI = 1, + XHCI_FLAG_USE_MSI_X, +}; + +static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, + unsigned int epid); +static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, + unsigned int epid); +static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v); +static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v); + static const char *TRBType_names[] = { [TRB_RESERVED] = "TRB_RESERVED", [TR_NORMAL] = "TR_NORMAL", @@ -460,6 +526,45 @@ static const char *TRBType_names[] = { [CR_VENDOR_NEC_CHALLENGE_RESPONSE] = "CR_VENDOR_NEC_CHALLENGE_RESPONSE", }; +static const char *TRBCCode_names[] = { + [CC_INVALID] = "CC_INVALID", + [CC_SUCCESS] = "CC_SUCCESS", + [CC_DATA_BUFFER_ERROR] = "CC_DATA_BUFFER_ERROR", + [CC_BABBLE_DETECTED] = "CC_BABBLE_DETECTED", + [CC_USB_TRANSACTION_ERROR] = "CC_USB_TRANSACTION_ERROR", + [CC_TRB_ERROR] = "CC_TRB_ERROR", + [CC_STALL_ERROR] = "CC_STALL_ERROR", + [CC_RESOURCE_ERROR] = "CC_RESOURCE_ERROR", + [CC_BANDWIDTH_ERROR] = "CC_BANDWIDTH_ERROR", + [CC_NO_SLOTS_ERROR] = "CC_NO_SLOTS_ERROR", + [CC_INVALID_STREAM_TYPE_ERROR] = "CC_INVALID_STREAM_TYPE_ERROR", + [CC_SLOT_NOT_ENABLED_ERROR] = "CC_SLOT_NOT_ENABLED_ERROR", + [CC_EP_NOT_ENABLED_ERROR] = "CC_EP_NOT_ENABLED_ERROR", + [CC_SHORT_PACKET] = "CC_SHORT_PACKET", + [CC_RING_UNDERRUN] = "CC_RING_UNDERRUN", + [CC_RING_OVERRUN] = "CC_RING_OVERRUN", + [CC_VF_ER_FULL] = "CC_VF_ER_FULL", + [CC_PARAMETER_ERROR] = "CC_PARAMETER_ERROR", + [CC_BANDWIDTH_OVERRUN] = "CC_BANDWIDTH_OVERRUN", + [CC_CONTEXT_STATE_ERROR] = "CC_CONTEXT_STATE_ERROR", + [CC_NO_PING_RESPONSE_ERROR] = "CC_NO_PING_RESPONSE_ERROR", + [CC_EVENT_RING_FULL_ERROR] = "CC_EVENT_RING_FULL_ERROR", + [CC_INCOMPATIBLE_DEVICE_ERROR] = "CC_INCOMPATIBLE_DEVICE_ERROR", + [CC_MISSED_SERVICE_ERROR] = "CC_MISSED_SERVICE_ERROR", + [CC_COMMAND_RING_STOPPED] = "CC_COMMAND_RING_STOPPED", + [CC_COMMAND_ABORTED] = "CC_COMMAND_ABORTED", + [CC_STOPPED] = "CC_STOPPED", + [CC_STOPPED_LENGTH_INVALID] = "CC_STOPPED_LENGTH_INVALID", + [CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR] + = "CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR", + [CC_ISOCH_BUFFER_OVERRUN] = "CC_ISOCH_BUFFER_OVERRUN", + [CC_EVENT_LOST_ERROR] = "CC_EVENT_LOST_ERROR", + [CC_UNDEFINED_ERROR] = "CC_UNDEFINED_ERROR", + [CC_INVALID_STREAM_ID_ERROR] = "CC_INVALID_STREAM_ID_ERROR", + [CC_SECONDARY_BANDWIDTH_ERROR] = "CC_SECONDARY_BANDWIDTH_ERROR", + [CC_SPLIT_TRANSACTION_ERROR] = "CC_SPLIT_TRANSACTION_ERROR", +}; + static const char *lookup_name(uint32_t index, const char **list, uint32_t llen) { if (index >= llen || list[index] == NULL) { @@ -474,8 +579,42 @@ static const char *trb_name(XHCITRB *trb) ARRAY_SIZE(TRBType_names)); } -static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, - unsigned int epid); +static const char *event_name(XHCIEvent *event) +{ + return lookup_name(event->ccode, TRBCCode_names, + ARRAY_SIZE(TRBCCode_names)); +} + +static uint64_t xhci_mfindex_get(XHCIState *xhci) +{ + int64_t now = qemu_get_clock_ns(vm_clock); + return (now - xhci->mfindex_start) / 125000; +} + +static void xhci_mfwrap_update(XHCIState *xhci) +{ + const uint32_t bits = USBCMD_RS | USBCMD_EWE; + uint32_t mfindex, left; + int64_t now; + + if ((xhci->usbcmd & bits) == bits) { + now = qemu_get_clock_ns(vm_clock); + mfindex = ((now - xhci->mfindex_start) / 125000) & 0x3fff; + left = 0x4000 - mfindex; + qemu_mod_timer(xhci->mfwrap_timer, now + left * 125000); + } else { + qemu_del_timer(xhci->mfwrap_timer); + } +} + +static void xhci_mfwrap_timer(void *opaque) +{ + XHCIState *xhci = opaque; + XHCIEvent wrap = { ER_MFINDEX_WRAP, CC_SUCCESS }; + + xhci_event(xhci, &wrap, 0); + xhci_mfwrap_update(xhci); +} static inline dma_addr_t xhci_addr64(uint32_t low, uint32_t high) { @@ -495,29 +634,134 @@ static inline dma_addr_t xhci_mask64(uint64_t addr) } } -static void xhci_irq_update(XHCIState *xhci) +static inline void xhci_dma_read_u32s(XHCIState *xhci, dma_addr_t addr, + uint32_t *buf, size_t len) +{ + int i; + + assert((len % sizeof(uint32_t)) == 0); + + pci_dma_read(&xhci->pci_dev, addr, buf, len); + + for (i = 0; i < (len / sizeof(uint32_t)); i++) { + buf[i] = le32_to_cpu(buf[i]); + } +} + +static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr, + uint32_t *buf, size_t len) +{ + int i; + uint32_t tmp[len / sizeof(uint32_t)]; + + assert((len % sizeof(uint32_t)) == 0); + + for (i = 0; i < (len / sizeof(uint32_t)); i++) { + tmp[i] = cpu_to_le32(buf[i]); + } + pci_dma_write(&xhci->pci_dev, addr, tmp, len); +} + +static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport) +{ + int index; + + if (!uport->dev) { + return NULL; + } + switch (uport->dev->speed) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + index = uport->index; + break; + case USB_SPEED_SUPER: + index = uport->index + xhci->numports_2; + break; + default: + return NULL; + } + return &xhci->ports[index]; +} + +static void xhci_intx_update(XHCIState *xhci) { int level = 0; - if (xhci->iman & IMAN_IP && xhci->iman & IMAN_IE && + if (msix_enabled(&xhci->pci_dev) || + msi_enabled(&xhci->pci_dev)) { + return; + } + + if (xhci->intr[0].iman & IMAN_IP && + xhci->intr[0].iman & IMAN_IE && xhci->usbcmd & USBCMD_INTE) { level = 1; } - if (xhci->msi && msi_enabled(&xhci->pci_dev)) { - if (level) { - trace_usb_xhci_irq_msi(0); - msi_notify(&xhci->pci_dev, 0); - } + trace_usb_xhci_irq_intx(level); + qemu_set_irq(xhci->irq, level); +} + +static void xhci_msix_update(XHCIState *xhci, int v) +{ + bool enabled; + + if (!msix_enabled(&xhci->pci_dev)) { + return; + } + + enabled = xhci->intr[v].iman & IMAN_IE; + if (enabled == xhci->intr[v].msix_used) { + return; + } + + if (enabled) { + trace_usb_xhci_irq_msix_use(v); + msix_vector_use(&xhci->pci_dev, v); + xhci->intr[v].msix_used = true; } else { - trace_usb_xhci_irq_intx(level); - qemu_set_irq(xhci->irq, level); + trace_usb_xhci_irq_msix_unuse(v); + msix_vector_unuse(&xhci->pci_dev, v); + xhci->intr[v].msix_used = false; + } +} + +static void xhci_intr_raise(XHCIState *xhci, int v) +{ + xhci->intr[v].erdp_low |= ERDP_EHB; + xhci->intr[v].iman |= IMAN_IP; + xhci->usbsts |= USBSTS_EINT; + + if (!(xhci->intr[v].iman & IMAN_IE)) { + return; + } + + if (!(xhci->usbcmd & USBCMD_INTE)) { + return; + } + + if (msix_enabled(&xhci->pci_dev)) { + trace_usb_xhci_irq_msix(v); + msix_notify(&xhci->pci_dev, v); + return; + } + + if (msi_enabled(&xhci->pci_dev)) { + trace_usb_xhci_irq_msi(v); + msi_notify(&xhci->pci_dev, v); + return; + } + + if (v == 0) { + trace_usb_xhci_irq_intx(1); + qemu_set_irq(xhci->irq, 1); } } static inline int xhci_running(XHCIState *xhci) { - return !(xhci->usbsts & USBSTS_HCH) && !xhci->er_full; + return !(xhci->usbsts & USBSTS_HCH) && !xhci->intr[0].er_full; } static void xhci_die(XHCIState *xhci) @@ -526,8 +770,9 @@ static void xhci_die(XHCIState *xhci) fprintf(stderr, "xhci: asserted controller error\n"); } -static void xhci_write_event(XHCIState *xhci, XHCIEvent *event) +static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v) { + XHCIInterrupter *intr = &xhci->intr[v]; XHCITRB ev_trb; dma_addr_t addr; @@ -535,26 +780,28 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event) ev_trb.status = cpu_to_le32(event->length | (event->ccode << 24)); ev_trb.control = (event->slotid << 24) | (event->epid << 16) | event->flags | (event->type << TRB_TYPE_SHIFT); - if (xhci->er_pcs) { + if (intr->er_pcs) { ev_trb.control |= TRB_C; } ev_trb.control = cpu_to_le32(ev_trb.control); - trace_usb_xhci_queue_event(xhci->er_ep_idx, trb_name(&ev_trb), - ev_trb.parameter, ev_trb.status, ev_trb.control); + trace_usb_xhci_queue_event(v, intr->er_ep_idx, trb_name(&ev_trb), + event_name(event), ev_trb.parameter, + ev_trb.status, ev_trb.control); - addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx; + addr = intr->er_start + TRB_SIZE*intr->er_ep_idx; pci_dma_write(&xhci->pci_dev, addr, &ev_trb, TRB_SIZE); - xhci->er_ep_idx++; - if (xhci->er_ep_idx >= xhci->er_size) { - xhci->er_ep_idx = 0; - xhci->er_pcs = !xhci->er_pcs; + intr->er_ep_idx++; + if (intr->er_ep_idx >= intr->er_size) { + intr->er_ep_idx = 0; + intr->er_pcs = !intr->er_pcs; } } -static void xhci_events_update(XHCIState *xhci) +static void xhci_events_update(XHCIState *xhci, int v) { + XHCIInterrupter *intr = &xhci->intr[v]; dma_addr_t erdp; unsigned int dp_idx; bool do_irq = 0; @@ -563,122 +810,121 @@ static void xhci_events_update(XHCIState *xhci) return; } - erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high); - if (erdp < xhci->er_start || - erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) { + erdp = xhci_addr64(intr->erdp_low, intr->erdp_high); + if (erdp < intr->er_start || + erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) { fprintf(stderr, "xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp); - fprintf(stderr, "xhci: ER at "DMA_ADDR_FMT" len %d\n", - xhci->er_start, xhci->er_size); + fprintf(stderr, "xhci: ER[%d] at "DMA_ADDR_FMT" len %d\n", + v, intr->er_start, intr->er_size); xhci_die(xhci); return; } - dp_idx = (erdp - xhci->er_start) / TRB_SIZE; - assert(dp_idx < xhci->er_size); + dp_idx = (erdp - intr->er_start) / TRB_SIZE; + assert(dp_idx < intr->er_size); /* NEC didn't read section 4.9.4 of the spec (v1.0 p139 top Note) and thus * deadlocks when the ER is full. Hack it by holding off events until * the driver decides to free at least half of the ring */ - if (xhci->er_full) { - int er_free = dp_idx - xhci->er_ep_idx; + if (intr->er_full) { + int er_free = dp_idx - intr->er_ep_idx; if (er_free <= 0) { - er_free += xhci->er_size; + er_free += intr->er_size; } - if (er_free < (xhci->er_size/2)) { + if (er_free < (intr->er_size/2)) { DPRINTF("xhci_events_update(): event ring still " "more than half full (hack)\n"); return; } } - while (xhci->ev_buffer_put != xhci->ev_buffer_get) { - assert(xhci->er_full); - if (((xhci->er_ep_idx+1) % xhci->er_size) == dp_idx) { + while (intr->ev_buffer_put != intr->ev_buffer_get) { + assert(intr->er_full); + if (((intr->er_ep_idx+1) % intr->er_size) == dp_idx) { DPRINTF("xhci_events_update(): event ring full again\n"); #ifndef ER_FULL_HACK XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR}; - xhci_write_event(xhci, &full); + xhci_write_event(xhci, &full, v); #endif do_irq = 1; break; } - XHCIEvent *event = &xhci->ev_buffer[xhci->ev_buffer_get]; - xhci_write_event(xhci, event); - xhci->ev_buffer_get++; + XHCIEvent *event = &intr->ev_buffer[intr->ev_buffer_get]; + xhci_write_event(xhci, event, v); + intr->ev_buffer_get++; do_irq = 1; - if (xhci->ev_buffer_get == EV_QUEUE) { - xhci->ev_buffer_get = 0; + if (intr->ev_buffer_get == EV_QUEUE) { + intr->ev_buffer_get = 0; } } if (do_irq) { - xhci->erdp_low |= ERDP_EHB; - xhci->iman |= IMAN_IP; - xhci->usbsts |= USBSTS_EINT; - xhci_irq_update(xhci); + xhci_intr_raise(xhci, v); } - if (xhci->er_full && xhci->ev_buffer_put == xhci->ev_buffer_get) { + if (intr->er_full && intr->ev_buffer_put == intr->ev_buffer_get) { DPRINTF("xhci_events_update(): event ring no longer full\n"); - xhci->er_full = 0; + intr->er_full = 0; } - return; } -static void xhci_event(XHCIState *xhci, XHCIEvent *event) +static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v) { + XHCIInterrupter *intr; dma_addr_t erdp; unsigned int dp_idx; - if (xhci->er_full) { + if (v >= xhci->numintrs) { + DPRINTF("intr nr out of range (%d >= %d)\n", v, xhci->numintrs); + return; + } + intr = &xhci->intr[v]; + + if (intr->er_full) { DPRINTF("xhci_event(): ER full, queueing\n"); - if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) { + if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) { fprintf(stderr, "xhci: event queue full, dropping event!\n"); return; } - xhci->ev_buffer[xhci->ev_buffer_put++] = *event; - if (xhci->ev_buffer_put == EV_QUEUE) { - xhci->ev_buffer_put = 0; + intr->ev_buffer[intr->ev_buffer_put++] = *event; + if (intr->ev_buffer_put == EV_QUEUE) { + intr->ev_buffer_put = 0; } return; } - erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high); - if (erdp < xhci->er_start || - erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) { + erdp = xhci_addr64(intr->erdp_low, intr->erdp_high); + if (erdp < intr->er_start || + erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) { fprintf(stderr, "xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp); - fprintf(stderr, "xhci: ER at "DMA_ADDR_FMT" len %d\n", - xhci->er_start, xhci->er_size); + fprintf(stderr, "xhci: ER[%d] at "DMA_ADDR_FMT" len %d\n", + v, intr->er_start, intr->er_size); xhci_die(xhci); return; } - dp_idx = (erdp - xhci->er_start) / TRB_SIZE; - assert(dp_idx < xhci->er_size); + dp_idx = (erdp - intr->er_start) / TRB_SIZE; + assert(dp_idx < intr->er_size); - if ((xhci->er_ep_idx+1) % xhci->er_size == dp_idx) { + if ((intr->er_ep_idx+1) % intr->er_size == dp_idx) { DPRINTF("xhci_event(): ER full, queueing\n"); #ifndef ER_FULL_HACK XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR}; xhci_write_event(xhci, &full); #endif - xhci->er_full = 1; - if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) { + intr->er_full = 1; + if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) { fprintf(stderr, "xhci: event queue full, dropping event!\n"); return; } - xhci->ev_buffer[xhci->ev_buffer_put++] = *event; - if (xhci->ev_buffer_put == EV_QUEUE) { - xhci->ev_buffer_put = 0; + intr->ev_buffer[intr->ev_buffer_put++] = *event; + if (intr->ev_buffer_put == EV_QUEUE) { + intr->ev_buffer_put = 0; } } else { - xhci_write_event(xhci, event); + xhci_write_event(xhci, event, v); } - xhci->erdp_low |= ERDP_EHB; - xhci->iman |= IMAN_IP; - xhci->usbsts |= USBSTS_EINT; - - xhci_irq_update(xhci); + xhci_intr_raise(xhci, v); } static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring, @@ -770,17 +1016,24 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) } } -static void xhci_er_reset(XHCIState *xhci) +static void xhci_er_reset(XHCIState *xhci, int v) { + XHCIInterrupter *intr = &xhci->intr[v]; XHCIEvRingSeg seg; + if (intr->erstsz == 0) { + /* disabled */ + intr->er_start = 0; + intr->er_size = 0; + return; + } /* cache the (sole) event ring segment location */ - if (xhci->erstsz != 1) { - fprintf(stderr, "xhci: invalid value for ERSTSZ: %d\n", xhci->erstsz); + if (intr->erstsz != 1) { + fprintf(stderr, "xhci: invalid value for ERSTSZ: %d\n", intr->erstsz); xhci_die(xhci); return; } - dma_addr_t erstba = xhci_addr64(xhci->erstba_low, xhci->erstba_high); + dma_addr_t erstba = xhci_addr64(intr->erstba_low, intr->erstba_high); pci_dma_read(&xhci->pci_dev, erstba, &seg, sizeof(seg)); le32_to_cpus(&seg.addr_low); le32_to_cpus(&seg.addr_high); @@ -790,21 +1043,22 @@ static void xhci_er_reset(XHCIState *xhci) xhci_die(xhci); return; } - xhci->er_start = xhci_addr64(seg.addr_low, seg.addr_high); - xhci->er_size = seg.size; + intr->er_start = xhci_addr64(seg.addr_low, seg.addr_high); + intr->er_size = seg.size; - xhci->er_ep_idx = 0; - xhci->er_pcs = 1; - xhci->er_full = 0; + intr->er_ep_idx = 0; + intr->er_pcs = 1; + intr->er_full = 0; - DPRINTF("xhci: event ring:" DMA_ADDR_FMT " [%d]\n", - xhci->er_start, xhci->er_size); + DPRINTF("xhci: event ring[%d]:" DMA_ADDR_FMT " [%d]\n", + v, intr->er_start, intr->er_size); } static void xhci_run(XHCIState *xhci) { trace_usb_xhci_run(); xhci->usbsts &= ~USBSTS_HCH; + xhci->mfindex_start = qemu_get_clock_ns(vm_clock); } static void xhci_stop(XHCIState *xhci) @@ -818,21 +1072,24 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx, uint32_t state) { uint32_t ctx[5]; - if (epctx->state == state) { - return; - } - pci_dma_read(&xhci->pci_dev, epctx->pctx, ctx, sizeof(ctx)); + xhci_dma_read_u32s(xhci, epctx->pctx, ctx, sizeof(ctx)); ctx[0] &= ~EP_STATE_MASK; ctx[0] |= state; ctx[2] = epctx->ring.dequeue | epctx->ring.ccs; ctx[3] = (epctx->ring.dequeue >> 16) >> 16; DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n", epctx->pctx, state, ctx[3], ctx[2]); - pci_dma_write(&xhci->pci_dev, epctx->pctx, ctx, sizeof(ctx)); + xhci_dma_write_u32s(xhci, epctx->pctx, ctx, sizeof(ctx)); epctx->state = state; } +static void xhci_ep_kick_timer(void *opaque) +{ + XHCIEPContext *epctx = opaque; + xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid); +} + static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid, dma_addr_t pctx, uint32_t *ctx) @@ -843,17 +1100,19 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, int i; trace_usb_xhci_ep_enable(slotid, epid); - assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(slotid >= 1 && slotid <= xhci->numslots); assert(epid >= 1 && epid <= 31); slot = &xhci->slots[slotid-1]; if (slot->eps[epid-1]) { - fprintf(stderr, "xhci: slot %d ep %d already enabled!\n", slotid, epid); - return CC_TRB_ERROR; + xhci_disable_ep(xhci, slotid, epid); } epctx = g_malloc(sizeof(XHCIEPContext)); memset(epctx, 0, sizeof(XHCIEPContext)); + epctx->xhci = xhci; + epctx->slotid = slotid; + epctx->epid = epid; slot->eps[epid-1] = epctx; @@ -866,16 +1125,16 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, epctx->pctx = pctx; epctx->max_psize = ctx[1]>>16; epctx->max_psize *= 1+((ctx[1]>>8)&0xff); - epctx->has_bg = false; - if (epctx->type == ET_ISO_IN) { - epctx->has_bg = true; - } DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n", epid/2, epid%2, epctx->max_psize); for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) { usb_packet_init(&epctx->transfers[i].packet); } + epctx->interval = 1 << (ctx[0] >> 16) & 0xff; + epctx->mfindex_last = 0; + epctx->kick_timer = qemu_new_timer_ns(vm_clock, xhci_ep_kick_timer, epctx); + epctx->state = EP_RUNNING; ctx[0] &= ~EP_STATE_MASK; ctx[0] |= EP_RUNNING; @@ -883,13 +1142,43 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, return CC_SUCCESS; } +static int xhci_ep_nuke_one_xfer(XHCITransfer *t) +{ + int killed = 0; + + if (t->running_async) { + usb_cancel_packet(&t->packet); + t->running_async = 0; + t->cancelled = 1; + DPRINTF("xhci: cancelling transfer, waiting for it to complete\n"); + killed = 1; + } + if (t->running_retry) { + XHCIEPContext *epctx = t->xhci->slots[t->slotid-1].eps[t->epid-1]; + if (epctx) { + epctx->retry = NULL; + qemu_del_timer(epctx->kick_timer); + } + t->running_retry = 0; + } + if (t->trbs) { + g_free(t->trbs); + } + + t->trbs = NULL; + t->trb_count = t->trb_alloced = 0; + + return killed; +} + static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, unsigned int epid) { XHCISlot *slot; XHCIEPContext *epctx; int i, xferi, killed = 0; - assert(slotid >= 1 && slotid <= MAXSLOTS); + USBEndpoint *ep = NULL; + assert(slotid >= 1 && slotid <= xhci->numslots); assert(epid >= 1 && epid <= 31); DPRINTF("xhci_ep_nuke_xfers(%d, %d)\n", slotid, epid); @@ -904,52 +1193,14 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, xferi = epctx->next_xfer; for (i = 0; i < TD_QUEUE; i++) { - XHCITransfer *t = &epctx->transfers[xferi]; - if (t->running_async) { - usb_cancel_packet(&t->packet); - t->running_async = 0; - t->cancelled = 1; - DPRINTF("xhci: cancelling transfer %d, waiting for it to complete...\n", i); - killed++; + if (epctx->transfers[xferi].packet.ep) { + ep = epctx->transfers[xferi].packet.ep; } - if (t->running_retry) { - t->running_retry = 0; - epctx->retry = NULL; - } - if (t->backgrounded) { - t->backgrounded = 0; - } - if (t->trbs) { - g_free(t->trbs); - } - if (t->data) { - g_free(t->data); - } - - t->trbs = NULL; - t->data = NULL; - t->trb_count = t->trb_alloced = 0; - t->data_length = t->data_alloced = 0; + killed += xhci_ep_nuke_one_xfer(&epctx->transfers[xferi]); xferi = (xferi + 1) % TD_QUEUE; } - if (epctx->has_bg) { - xferi = epctx->next_bg; - for (i = 0; i < BG_XFERS; i++) { - XHCITransfer *t = &epctx->bg_transfers[xferi]; - if (t->running_async) { - usb_cancel_packet(&t->packet); - t->running_async = 0; - t->cancelled = 1; - DPRINTF("xhci: cancelling bg transfer %d, waiting for it to complete...\n", i); - killed++; - } - if (t->data) { - g_free(t->data); - } - - t->data = NULL; - xferi = (xferi + 1) % BG_XFERS; - } + if (ep) { + usb_device_ep_stopped(ep->dev, ep); } return killed; } @@ -961,7 +1212,7 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, XHCIEPContext *epctx; trace_usb_xhci_ep_disable(slotid, epid); - assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(slotid >= 1 && slotid <= xhci->numslots); assert(epid >= 1 && epid <= 31); slot = &xhci->slots[slotid-1]; @@ -977,6 +1228,7 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, xhci_set_ep_state(xhci, epctx, EP_DISABLED); + qemu_free_timer(epctx->kick_timer); g_free(epctx); slot->eps[epid-1] = NULL; @@ -990,7 +1242,7 @@ static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid, XHCIEPContext *epctx; trace_usb_xhci_ep_stop(slotid, epid); - assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(slotid >= 1 && slotid <= xhci->numslots); if (epid < 1 || epid > 31) { fprintf(stderr, "xhci: bad ep %d\n", epid); @@ -1024,7 +1276,7 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid, USBDevice *dev; trace_usb_xhci_ep_reset(slotid, epid); - assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(slotid >= 1 && slotid <= xhci->numslots); if (epid < 1 || epid > 31) { fprintf(stderr, "xhci: bad ep %d\n", epid); @@ -1057,7 +1309,7 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid, ep |= 0x80; } - dev = xhci->ports[xhci->slots[slotid-1].port-1].port.dev; + dev = xhci->slots[slotid-1].uport->dev; if (!dev) { return CC_USB_TRANSACTION_ERROR; } @@ -1074,14 +1326,14 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid, XHCIEPContext *epctx; dma_addr_t dequeue; - assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(slotid >= 1 && slotid <= xhci->numslots); if (epid < 1 || epid > 31) { fprintf(stderr, "xhci: bad ep %d\n", epid); return CC_TRB_ERROR; } - DPRINTF("xhci_set_ep_dequeue(%d, %d, %016"PRIx64")\n", slotid, epid, pdequeue); + trace_usb_xhci_ep_set_dequeue(slotid, epid, pdequeue); dequeue = xhci_mask64(pdequeue); slot = &xhci->slots[slotid-1]; @@ -1107,81 +1359,89 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid, return CC_SUCCESS; } -static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data, - unsigned int length, bool in_xfer, bool out_xfer, - bool report) +static int xhci_xfer_create_sgl(XHCITransfer *xfer, int in_xfer) { - int i; - uint32_t edtla = 0; - unsigned int transferred = 0; - unsigned int left = length; - bool reported = 0; - bool shortpkt = 0; - XHCIEvent event = {ER_TRANSFER, CC_SUCCESS}; XHCIState *xhci = xfer->xhci; + int i; - DPRINTF("xhci_xfer_data(len=%d, in_xfer=%d, out_xfer=%d, report=%d)\n", - length, in_xfer, out_xfer, report); - - assert(!(in_xfer && out_xfer)); - + xfer->int_req = false; + pci_dma_sglist_init(&xfer->sgl, &xhci->pci_dev, xfer->trb_count); for (i = 0; i < xfer->trb_count; i++) { XHCITRB *trb = &xfer->trbs[i]; dma_addr_t addr; unsigned int chunk = 0; + if (trb->control & TRB_TR_IOC) { + xfer->int_req = true; + } + switch (TRB_TYPE(*trb)) { case TR_DATA: if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) { fprintf(stderr, "xhci: data direction mismatch for TR_DATA\n"); - xhci_die(xhci); - return transferred; + goto err; } /* fallthrough */ case TR_NORMAL: case TR_ISOCH: addr = xhci_mask64(trb->parameter); chunk = trb->status & 0x1ffff; + if (trb->control & TRB_TR_IDT) { + if (chunk > 8 || in_xfer) { + fprintf(stderr, "xhci: invalid immediate data TRB\n"); + goto err; + } + qemu_sglist_add(&xfer->sgl, trb->addr, chunk); + } else { + qemu_sglist_add(&xfer->sgl, addr, chunk); + } + break; + } + } + + return 0; + +err: + qemu_sglist_destroy(&xfer->sgl); + xhci_die(xhci); + return -1; +} + +static void xhci_xfer_unmap(XHCITransfer *xfer) +{ + usb_packet_unmap(&xfer->packet, &xfer->sgl); + qemu_sglist_destroy(&xfer->sgl); +} + +static void xhci_xfer_report(XHCITransfer *xfer) +{ + uint32_t edtla = 0; + unsigned int left; + bool reported = 0; + bool shortpkt = 0; + XHCIEvent event = {ER_TRANSFER, CC_SUCCESS}; + XHCIState *xhci = xfer->xhci; + int i; + + left = xfer->packet.actual_length; + + for (i = 0; i < xfer->trb_count; i++) { + XHCITRB *trb = &xfer->trbs[i]; + unsigned int chunk = 0; + + switch (TRB_TYPE(*trb)) { + case TR_DATA: + case TR_NORMAL: + case TR_ISOCH: + chunk = trb->status & 0x1ffff; if (chunk > left) { chunk = left; - shortpkt = 1; - } - if (in_xfer || out_xfer) { - if (trb->control & TRB_TR_IDT) { - uint64_t idata; - if (chunk > 8 || in_xfer) { - fprintf(stderr, "xhci: invalid immediate data TRB\n"); - xhci_die(xhci); - return transferred; - } - idata = le64_to_cpu(trb->parameter); - memcpy(data, &idata, chunk); - } else { - DPRINTF("xhci_xfer_data: r/w(%d) %d bytes at " - DMA_ADDR_FMT "\n", in_xfer, chunk, addr); - if (in_xfer) { - pci_dma_write(&xhci->pci_dev, addr, data, chunk); - } else { - pci_dma_read(&xhci->pci_dev, addr, data, chunk); - } -#ifdef DEBUG_DATA - unsigned int count = chunk; - int i; - if (count > 16) { - count = 16; - } - DPRINTF(" ::"); - for (i = 0; i < count; i++) { - DPRINTF(" %02x", data[i]); - } - DPRINTF("\n"); -#endif + if (xfer->status == CC_SUCCESS) { + shortpkt = 1; } } left -= chunk; - data += chunk; edtla += chunk; - transferred += chunk; break; case TR_STATUS: reported = 0; @@ -1189,8 +1449,9 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data, break; } - if (report && !reported && (trb->control & TRB_TR_IOC || - (shortpkt && (trb->control & TRB_TR_ISP)))) { + if (!reported && ((trb->control & TRB_TR_IOC) || + (shortpkt && (trb->control & TRB_TR_ISP)) || + (xfer->status != CC_SUCCESS && left == 0))) { event.slotid = xfer->slotid; event.epid = xfer->epid; event.length = (trb->status & 0x1ffff) - chunk; @@ -1208,11 +1469,13 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data, DPRINTF("xhci_xfer_data: EDTLA=%d\n", event.length); edtla = 0; } - xhci_event(xhci, &event); + xhci_event(xhci, &event, TRB_INTR(*trb)); reported = 1; + if (xfer->status != CC_SUCCESS) { + return; + } } } - return transferred; } static void xhci_stall_ep(XHCITransfer *xfer) @@ -1231,184 +1494,47 @@ static void xhci_stall_ep(XHCITransfer *xfer) static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx); -static void xhci_bg_update(XHCIState *xhci, XHCIEPContext *epctx) -{ - if (epctx->bg_updating) { - return; - } - DPRINTF("xhci_bg_update(%p, %p)\n", xhci, epctx); - assert(epctx->has_bg); - DPRINTF("xhci: fg=%d bg=%d\n", epctx->comp_xfer, epctx->next_bg); - epctx->bg_updating = 1; - while (epctx->transfers[epctx->comp_xfer].backgrounded && - epctx->bg_transfers[epctx->next_bg].complete) { - XHCITransfer *fg = &epctx->transfers[epctx->comp_xfer]; - XHCITransfer *bg = &epctx->bg_transfers[epctx->next_bg]; -#if 0 - DPRINTF("xhci: completing fg %d from bg %d.%d (stat: %d)\n", - epctx->comp_xfer, epctx->next_bg, bg->cur_pkt, - bg->usbxfer->iso_packet_desc[bg->cur_pkt].status - ); -#endif - assert(epctx->type == ET_ISO_IN); - assert(bg->iso_xfer); - assert(bg->in_xfer); - uint8_t *p = bg->data + bg->cur_pkt * bg->pktsize; -#if 0 - int len = bg->usbxfer->iso_packet_desc[bg->cur_pkt].actual_length; - fg->status = libusb_to_ccode(bg->usbxfer->iso_packet_desc[bg->cur_pkt].status); -#else - int len = 0; - FIXME(); -#endif - fg->complete = 1; - fg->backgrounded = 0; - - if (fg->status == CC_STALL_ERROR) { - xhci_stall_ep(fg); - } - - xhci_xfer_data(fg, p, len, 1, 0, 1); - - epctx->comp_xfer++; - if (epctx->comp_xfer == TD_QUEUE) { - epctx->comp_xfer = 0; - } - DPRINTF("next fg xfer: %d\n", epctx->comp_xfer); - bg->cur_pkt++; - if (bg->cur_pkt == bg->pkts) { - bg->complete = 0; - if (xhci_submit(xhci, bg, epctx) < 0) { - fprintf(stderr, "xhci: bg resubmit failed\n"); - } - epctx->next_bg++; - if (epctx->next_bg == BG_XFERS) { - epctx->next_bg = 0; - } - DPRINTF("next bg xfer: %d\n", epctx->next_bg); - - xhci_kick_ep(xhci, fg->slotid, fg->epid); - } - } - epctx->bg_updating = 0; -} - -#if 0 -static void xhci_xfer_cb(struct libusb_transfer *transfer) +static int xhci_setup_packet(XHCITransfer *xfer) { - XHCIState *xhci; - XHCITransfer *xfer; - - xfer = (XHCITransfer *)transfer->user_data; - xhci = xfer->xhci; - - DPRINTF("xhci_xfer_cb(slot=%d, ep=%d, status=%d)\n", xfer->slotid, - xfer->epid, transfer->status); - - assert(xfer->slotid >= 1 && xfer->slotid <= MAXSLOTS); - assert(xfer->epid >= 1 && xfer->epid <= 31); - - if (xfer->cancelled) { - DPRINTF("xhci: transfer cancelled, not reporting anything\n"); - xfer->running = 0; - return; - } - - XHCIEPContext *epctx; - XHCISlot *slot; - slot = &xhci->slots[xfer->slotid-1]; - assert(slot->eps[xfer->epid-1]); - epctx = slot->eps[xfer->epid-1]; - - if (xfer->bg_xfer) { - DPRINTF("xhci: background transfer, updating\n"); - xfer->complete = 1; - xfer->running = 0; - xhci_bg_update(xhci, epctx); - return; - } - - if (xfer->iso_xfer) { - transfer->status = transfer->iso_packet_desc[0].status; - transfer->actual_length = transfer->iso_packet_desc[0].actual_length; - } - - xfer->status = libusb_to_ccode(transfer->status); - - xfer->complete = 1; - xfer->running = 0; - - if (transfer->status == LIBUSB_TRANSFER_STALL) - xhci_stall_ep(xhci, epctx, xfer); + XHCIState *xhci = xfer->xhci; + USBDevice *dev; + USBEndpoint *ep; + int dir; - DPRINTF("xhci: transfer actual length = %d\n", transfer->actual_length); + dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT; - if (xfer->in_xfer) { - if (xfer->epid == 1) { - xhci_xfer_data(xhci, xfer, xfer->data + 8, - transfer->actual_length, 1, 0, 1); - } else { - xhci_xfer_data(xhci, xfer, xfer->data, - transfer->actual_length, 1, 0, 1); - } + if (xfer->packet.ep) { + ep = xfer->packet.ep; + dev = ep->dev; } else { - xhci_xfer_data(xhci, xfer, NULL, transfer->actual_length, 0, 0, 1); - } - - xhci_kick_ep(xhci, xfer->slotid, xfer->epid); -} - -static int xhci_hle_control(XHCIState *xhci, XHCITransfer *xfer, - uint8_t bmRequestType, uint8_t bRequest, - uint16_t wValue, uint16_t wIndex, uint16_t wLength) -{ - uint16_t type_req = (bmRequestType << 8) | bRequest; - - switch (type_req) { - case 0x0000 | USB_REQ_SET_CONFIGURATION: - DPRINTF("xhci: HLE switch configuration\n"); - return xhci_switch_config(xhci, xfer->slotid, wValue) == 0; - case 0x0100 | USB_REQ_SET_INTERFACE: - DPRINTF("xhci: HLE set interface altsetting\n"); - return xhci_set_iface_alt(xhci, xfer->slotid, wIndex, wValue) == 0; - case 0x0200 | USB_REQ_CLEAR_FEATURE: - if (wValue == 0) { // endpoint halt - DPRINTF("xhci: HLE clear halt\n"); - return xhci_clear_halt(xhci, xfer->slotid, wIndex); - } - case 0x0000 | USB_REQ_SET_ADDRESS: - fprintf(stderr, "xhci: warn: illegal SET_ADDRESS request\n"); - return 0; - default: - return 0; + if (!xhci->slots[xfer->slotid-1].uport) { + fprintf(stderr, "xhci: slot %d has no device\n", + xfer->slotid); + return -1; + } + dev = xhci->slots[xfer->slotid-1].uport->dev; + ep = usb_ep_get(dev, dir, xfer->epid >> 1); } -} -#endif -static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev) -{ - USBEndpoint *ep; - int dir; - - dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT; - ep = usb_ep_get(dev, dir, xfer->epid >> 1); - usb_packet_setup(&xfer->packet, dir, ep); - usb_packet_addbuf(&xfer->packet, xfer->data, xfer->data_length); + xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN); /* Also sets int_req */ + usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr, false, + xfer->int_req); + usb_packet_map(&xfer->packet, &xfer->sgl); DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n", xfer->packet.pid, dev->addr, ep->nr); return 0; } -static int xhci_complete_packet(XHCITransfer *xfer, int ret) +static int xhci_complete_packet(XHCITransfer *xfer) { - if (ret == USB_RET_ASYNC) { + if (xfer->packet.status == USB_RET_ASYNC) { trace_usb_xhci_xfer_async(xfer); xfer->running_async = 1; xfer->running_retry = 0; xfer->complete = 0; xfer->cancelled = 0; return 0; - } else if (ret == USB_RET_NAK) { + } else if (xfer->packet.status == USB_RET_NAK) { trace_usb_xhci_xfer_nak(xfer); xfer->running_async = 0; xfer->running_retry = 1; @@ -1419,57 +1545,46 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret) xfer->running_async = 0; xfer->running_retry = 0; xfer->complete = 1; + xhci_xfer_unmap(xfer); } - if (ret >= 0) { + if (xfer->packet.status == USB_RET_SUCCESS) { + trace_usb_xhci_xfer_success(xfer, xfer->packet.actual_length); xfer->status = CC_SUCCESS; - xhci_xfer_data(xfer, xfer->data, ret, xfer->in_xfer, 0, 1); - trace_usb_xhci_xfer_success(xfer, ret); + xhci_xfer_report(xfer); return 0; } /* error */ - trace_usb_xhci_xfer_error(xfer, ret); - switch (ret) { + trace_usb_xhci_xfer_error(xfer, xfer->packet.status); + switch (xfer->packet.status) { case USB_RET_NODEV: xfer->status = CC_USB_TRANSACTION_ERROR; - xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1); + xhci_xfer_report(xfer); xhci_stall_ep(xfer); break; case USB_RET_STALL: xfer->status = CC_STALL_ERROR; - xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1); + xhci_xfer_report(xfer); xhci_stall_ep(xfer); break; default: - fprintf(stderr, "%s: FIXME: ret = %d\n", __FUNCTION__, ret); + fprintf(stderr, "%s: FIXME: status = %d\n", __func__, + xfer->packet.status); FIXME(); } return 0; } -static USBDevice *xhci_find_device(XHCIPort *port, uint8_t addr) -{ - if (!(port->portsc & PORTSC_PED)) { - return NULL; - } - return usb_find_device(&port->port, addr); -} - static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) { XHCITRB *trb_setup, *trb_status; uint8_t bmRequestType; - uint16_t wLength; - XHCIPort *port; - USBDevice *dev; - int ret; trb_setup = &xfer->trbs[0]; trb_status = &xfer->trbs[xfer->trb_count-1]; - trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, - trb_setup->parameter >> 48); + trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid); /* at most one Event Data TRB allowed after STATUS */ if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) { @@ -1498,93 +1613,87 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) } bmRequestType = trb_setup->parameter; - wLength = trb_setup->parameter >> 48; - - if (xfer->data && xfer->data_alloced < wLength) { - xfer->data_alloced = 0; - g_free(xfer->data); - xfer->data = NULL; - } - if (!xfer->data) { - DPRINTF("xhci: alloc %d bytes data\n", wLength); - xfer->data = g_malloc(wLength+1); - xfer->data_alloced = wLength; - } - xfer->data_length = wLength; - - port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1]; - dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr); - if (!dev) { - fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid, - xhci->slots[xfer->slotid-1].port); - return -1; - } xfer->in_xfer = bmRequestType & USB_DIR_IN; xfer->iso_xfer = false; - xhci_setup_packet(xfer, dev); - xfer->packet.parameter = trb_setup->parameter; - if (!xfer->in_xfer) { - xhci_xfer_data(xfer, xfer->data, wLength, 0, 1, 0); + if (xhci_setup_packet(xfer) < 0) { + return -1; } + xfer->packet.parameter = trb_setup->parameter; - ret = usb_handle_packet(dev, &xfer->packet); + usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); - xhci_complete_packet(xfer, ret); + xhci_complete_packet(xfer); if (!xfer->running_async && !xfer->running_retry) { xhci_kick_ep(xhci, xfer->slotid, xfer->epid); } return 0; } -static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) +static void xhci_calc_iso_kick(XHCIState *xhci, XHCITransfer *xfer, + XHCIEPContext *epctx, uint64_t mfindex) { - XHCIPort *port; - USBDevice *dev; - int ret; - - DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid); - - xfer->in_xfer = epctx->type>>2; - - if (xfer->data && xfer->data_alloced < xfer->data_length) { - xfer->data_alloced = 0; - g_free(xfer->data); - xfer->data = NULL; - } - if (!xfer->data && xfer->data_length) { - DPRINTF("xhci: alloc %d bytes data\n", xfer->data_length); - xfer->data = g_malloc(xfer->data_length); - xfer->data_alloced = xfer->data_length; - } - if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) { - if (!xfer->bg_xfer) { - xfer->pkts = 1; + if (xfer->trbs[0].control & TRB_TR_SIA) { + uint64_t asap = ((mfindex + epctx->interval - 1) & + ~(epctx->interval-1)); + if (asap >= epctx->mfindex_last && + asap <= epctx->mfindex_last + epctx->interval * 4) { + xfer->mfindex_kick = epctx->mfindex_last + epctx->interval; + } else { + xfer->mfindex_kick = asap; } } else { - xfer->pkts = 0; + xfer->mfindex_kick = (xfer->trbs[0].control >> TRB_TR_FRAMEID_SHIFT) + & TRB_TR_FRAMEID_MASK; + xfer->mfindex_kick |= mfindex & ~0x3fff; + if (xfer->mfindex_kick < mfindex) { + xfer->mfindex_kick += 0x4000; + } } +} - port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1]; - dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr); - if (!dev) { - fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid, - xhci->slots[xfer->slotid-1].port); - return -1; +static void xhci_check_iso_kick(XHCIState *xhci, XHCITransfer *xfer, + XHCIEPContext *epctx, uint64_t mfindex) +{ + if (xfer->mfindex_kick > mfindex) { + qemu_mod_timer(epctx->kick_timer, qemu_get_clock_ns(vm_clock) + + (xfer->mfindex_kick - mfindex) * 125000); + xfer->running_retry = 1; + } else { + epctx->mfindex_last = xfer->mfindex_kick; + qemu_del_timer(epctx->kick_timer); + xfer->running_retry = 0; } +} + + +static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) +{ + uint64_t mfindex; + + DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid); - xhci_setup_packet(xfer, dev); + xfer->in_xfer = epctx->type>>2; switch(epctx->type) { case ET_INTR_OUT: case ET_INTR_IN: case ET_BULK_OUT: case ET_BULK_IN: + xfer->pkts = 0; + xfer->iso_xfer = false; break; case ET_ISO_OUT: case ET_ISO_IN: - FIXME(); + xfer->pkts = 1; + xfer->iso_xfer = true; + mfindex = xhci_mfindex_get(xhci); + xhci_calc_iso_kick(xhci, xfer, epctx, mfindex); + xhci_check_iso_kick(xhci, xfer, epctx, mfindex); + if (xfer->running_retry) { + return -1; + } break; default: fprintf(stderr, "xhci: unknown or unhandled EP " @@ -1593,12 +1702,12 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx return -1; } - if (!xfer->in_xfer) { - xhci_xfer_data(xfer, xfer->data, xfer->data_length, 0, 1, 0); + if (xhci_setup_packet(xfer) < 0) { + return -1; } - ret = usb_handle_packet(dev, &xfer->packet); + usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); - xhci_complete_packet(xfer, ret); + xhci_complete_packet(xfer); if (!xfer->running_async && !xfer->running_retry) { xhci_kick_ep(xhci, xfer->slotid, xfer->epid); } @@ -1607,55 +1716,20 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) { - int i; - unsigned int length = 0; - XHCITRB *trb; - - for (i = 0; i < xfer->trb_count; i++) { - trb = &xfer->trbs[i]; - if (TRB_TYPE(*trb) == TR_NORMAL || TRB_TYPE(*trb) == TR_ISOCH) { - length += trb->status & 0x1ffff; - } - } - - trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, length); - - if (!epctx->has_bg) { - xfer->data_length = length; - xfer->backgrounded = 0; - return xhci_submit(xhci, xfer, epctx); - } else { - if (!epctx->bg_running) { - for (i = 0; i < BG_XFERS; i++) { - XHCITransfer *t = &epctx->bg_transfers[i]; - t->xhci = xhci; - t->epid = xfer->epid; - t->slotid = xfer->slotid; - t->pkts = BG_PKTS; - t->pktsize = epctx->max_psize; - t->data_length = t->pkts * t->pktsize; - t->bg_xfer = 1; - if (xhci_submit(xhci, t, epctx) < 0) { - fprintf(stderr, "xhci: bg submit failed\n"); - return -1; - } - } - epctx->bg_running = 1; - } - xfer->backgrounded = 1; - xhci_bg_update(xhci, epctx); - return 0; - } + trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid); + return xhci_submit(xhci, xfer, epctx); } static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid) { XHCIEPContext *epctx; + USBEndpoint *ep = NULL; + uint64_t mfindex; int length; int i; trace_usb_xhci_ep_kick(slotid, epid); - assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(slotid >= 1 && slotid <= xhci->numslots); assert(epid >= 1 && epid <= 31); if (!xhci->slots[slotid-1].enabled) { @@ -1670,18 +1744,34 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid } if (epctx->retry) { - /* retry nak'ed transfer */ XHCITransfer *xfer = epctx->retry; - int result; trace_usb_xhci_xfer_retry(xfer); assert(xfer->running_retry); - xhci_setup_packet(xfer, xfer->packet.ep->dev); - result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); - if (result == USB_RET_NAK) { - return; + if (xfer->iso_xfer) { + /* retry delayed iso transfer */ + mfindex = xhci_mfindex_get(xhci); + xhci_check_iso_kick(xhci, xfer, epctx, mfindex); + if (xfer->running_retry) { + return; + } + if (xhci_setup_packet(xfer) < 0) { + return; + } + usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); + assert(xfer->packet.status != USB_RET_NAK); + xhci_complete_packet(xfer); + } else { + /* retry nak'ed transfer */ + if (xhci_setup_packet(xfer) < 0) { + return; + } + usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); + if (xfer->packet.status == USB_RET_NAK) { + return; + } + xhci_complete_packet(xfer); } - xhci_complete_packet(xfer, result); assert(!xfer->running_retry); epctx->retry = NULL; } @@ -1695,7 +1785,7 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid while (1) { XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer]; - if (xfer->running_async || xfer->running_retry || xfer->backgrounded) { + if (xfer->running_async || xfer->running_retry) { break; } length = xhci_ring_chain_length(xhci, &epctx->ring); @@ -1726,14 +1816,18 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid if (epid == 1) { if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) { epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE; + ep = xfer->packet.ep; } else { fprintf(stderr, "xhci: error firing CTL transfer\n"); } } else { if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) { epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE; + ep = xfer->packet.ep; } else { - fprintf(stderr, "xhci: error firing data transfer\n"); + if (!xfer->iso_xfer) { + fprintf(stderr, "xhci: error firing data transfer\n"); + } } } @@ -1746,14 +1840,17 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid break; } } + if (ep) { + usb_device_flush_ep_queue(ep->dev, ep); + } } static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid) { trace_usb_xhci_slot_enable(slotid); - assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(slotid >= 1 && slotid <= xhci->numslots); xhci->slots[slotid-1].enabled = 1; - xhci->slots[slotid-1].port = 0; + xhci->slots[slotid-1].uport = NULL; memset(xhci->slots[slotid-1].eps, 0, sizeof(XHCIEPContext*)*31); return CC_SUCCESS; @@ -1764,7 +1861,7 @@ static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid) int i; trace_usb_xhci_slot_disable(slotid); - assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(slotid >= 1 && slotid <= xhci->numslots); for (i = 1; i <= 31; i++) { if (xhci->slots[slotid-1].eps[i-1]) { @@ -1776,32 +1873,57 @@ static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid) return CC_SUCCESS; } +static USBPort *xhci_lookup_uport(XHCIState *xhci, uint32_t *slot_ctx) +{ + USBPort *uport; + char path[32]; + int i, pos, port; + + port = (slot_ctx[1]>>16) & 0xFF; + port = xhci->ports[port-1].uport->index+1; + pos = snprintf(path, sizeof(path), "%d", port); + for (i = 0; i < 5; i++) { + port = (slot_ctx[0] >> 4*i) & 0x0f; + if (!port) { + break; + } + pos += snprintf(path + pos, sizeof(path) - pos, ".%d", port); + } + + QTAILQ_FOREACH(uport, &xhci->bus.used, next) { + if (strcmp(uport->path, path) == 0) { + return uport; + } + } + return NULL; +} + static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, uint64_t pictx, bool bsr) { XHCISlot *slot; + USBPort *uport; USBDevice *dev; dma_addr_t ictx, octx, dcbaap; uint64_t poctx; uint32_t ictl_ctx[2]; uint32_t slot_ctx[4]; uint32_t ep0_ctx[5]; - unsigned int port; int i; TRBCCode res; trace_usb_xhci_slot_address(slotid); - assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(slotid >= 1 && slotid <= xhci->numslots); dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high); - pci_dma_read(&xhci->pci_dev, dcbaap + 8*slotid, &poctx, sizeof(poctx)); + poctx = ldq_le_pci_dma(&xhci->pci_dev, dcbaap + 8*slotid); ictx = xhci_mask64(pictx); - octx = xhci_mask64(le64_to_cpu(poctx)); + octx = xhci_mask64(poctx); DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx); DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx); - pci_dma_read(&xhci->pci_dev, ictx, ictl_ctx, sizeof(ictl_ctx)); + xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx)); if (ictl_ctx[0] != 0x0 || ictl_ctx[1] != 0x3) { fprintf(stderr, "xhci: invalid input context control %08x %08x\n", @@ -1809,8 +1931,8 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, return CC_TRB_ERROR; } - pci_dma_read(&xhci->pci_dev, ictx+32, slot_ctx, sizeof(slot_ctx)); - pci_dma_read(&xhci->pci_dev, ictx+64, ep0_ctx, sizeof(ep0_ctx)); + xhci_dma_read_u32s(xhci, ictx+32, slot_ctx, sizeof(slot_ctx)); + xhci_dma_read_u32s(xhci, ictx+64, ep0_ctx, sizeof(ep0_ctx)); DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n", slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); @@ -1818,38 +1940,48 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n", ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]); - port = (slot_ctx[1]>>16) & 0xFF; - dev = xhci->ports[port-1].port.dev; - - if (port < 1 || port > MAXPORTS) { - fprintf(stderr, "xhci: bad port %d\n", port); + uport = xhci_lookup_uport(xhci, slot_ctx); + if (uport == NULL) { + fprintf(stderr, "xhci: port not found\n"); return CC_TRB_ERROR; - } else if (!dev) { - fprintf(stderr, "xhci: port %d not connected\n", port); + } + + dev = uport->dev; + if (!dev) { + fprintf(stderr, "xhci: port %s not connected\n", uport->path); return CC_USB_TRANSACTION_ERROR; } - for (i = 0; i < MAXSLOTS; i++) { - if (xhci->slots[i].port == port) { - fprintf(stderr, "xhci: port %d already assigned to slot %d\n", - port, i+1); + for (i = 0; i < xhci->numslots; i++) { + if (i == slotid-1) { + continue; + } + if (xhci->slots[i].uport == uport) { + fprintf(stderr, "xhci: port %s already assigned to slot %d\n", + uport->path, i+1); return CC_TRB_ERROR; } } slot = &xhci->slots[slotid-1]; - slot->port = port; + slot->uport = uport; slot->ctx = octx; if (bsr) { slot_ctx[3] = SLOT_DEFAULT << SLOT_STATE_SHIFT; } else { + USBPacket p; slot->devaddr = xhci->devaddr++; slot_ctx[3] = (SLOT_ADDRESSED << SLOT_STATE_SHIFT) | slot->devaddr; DPRINTF("xhci: device address is %d\n", slot->devaddr); - usb_device_handle_control(dev, NULL, + usb_device_reset(dev); + usb_packet_setup(&p, USB_TOKEN_OUT, + usb_ep_get(dev, USB_TOKEN_OUT, 0), + 0, false, false); + usb_device_handle_control(dev, &p, DeviceOutRequest | USB_REQ_SET_ADDRESS, slot->devaddr, 0, 0, NULL); + assert(p.status != USB_RET_ASYNC); } res = xhci_enable_ep(xhci, slotid, 1, octx+32, ep0_ctx); @@ -1859,8 +1991,8 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n", ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]); - pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); - pci_dma_write(&xhci->pci_dev, octx+32, ep0_ctx, sizeof(ep0_ctx)); + xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_write_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx)); return res; } @@ -1878,7 +2010,7 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, TRBCCode res; trace_usb_xhci_slot_configure(slotid); - assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(slotid >= 1 && slotid <= xhci->numslots); ictx = xhci_mask64(pictx); octx = xhci->slots[slotid-1].ctx; @@ -1893,17 +2025,17 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, } } - pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT); slot_ctx[3] |= SLOT_ADDRESSED << SLOT_STATE_SHIFT; DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n", slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); - pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); return CC_SUCCESS; } - pci_dma_read(&xhci->pci_dev, ictx, ictl_ctx, sizeof(ictl_ctx)); + xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx)); if ((ictl_ctx[0] & 0x3) != 0x0 || (ictl_ctx[1] & 0x3) != 0x1) { fprintf(stderr, "xhci: invalid input context control %08x %08x\n", @@ -1911,8 +2043,8 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, return CC_TRB_ERROR; } - pci_dma_read(&xhci->pci_dev, ictx+32, islot_ctx, sizeof(islot_ctx)); - pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_read_u32s(xhci, ictx+32, islot_ctx, sizeof(islot_ctx)); + xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); if (SLOT_STATE(slot_ctx[3]) < SLOT_ADDRESSED) { fprintf(stderr, "xhci: invalid slot state %08x\n", slot_ctx[3]); @@ -1924,8 +2056,7 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, xhci_disable_ep(xhci, slotid, i); } if (ictl_ctx[1] & (1<<i)) { - pci_dma_read(&xhci->pci_dev, ictx+32+(32*i), ep_ctx, - sizeof(ep_ctx)); + xhci_dma_read_u32s(xhci, ictx+32+(32*i), ep_ctx, sizeof(ep_ctx)); DPRINTF("xhci: input ep%d.%d context: %08x %08x %08x %08x %08x\n", i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2], ep_ctx[3], ep_ctx[4]); @@ -1937,7 +2068,7 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, DPRINTF("xhci: output ep%d.%d context: %08x %08x %08x %08x %08x\n", i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2], ep_ctx[3], ep_ctx[4]); - pci_dma_write(&xhci->pci_dev, octx+(32*i), ep_ctx, sizeof(ep_ctx)); + xhci_dma_write_u32s(xhci, octx+(32*i), ep_ctx, sizeof(ep_ctx)); } } @@ -1949,7 +2080,7 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n", slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); - pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); return CC_SUCCESS; } @@ -1966,7 +2097,7 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid, uint32_t slot_ctx[4]; trace_usb_xhci_slot_evaluate(slotid); - assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(slotid >= 1 && slotid <= xhci->numslots); ictx = xhci_mask64(pictx); octx = xhci->slots[slotid-1].ctx; @@ -1974,7 +2105,7 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid, DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx); DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx); - pci_dma_read(&xhci->pci_dev, ictx, ictl_ctx, sizeof(ictl_ctx)); + xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx)); if (ictl_ctx[0] != 0x0 || ictl_ctx[1] & ~0x3) { fprintf(stderr, "xhci: invalid input context control %08x %08x\n", @@ -1983,12 +2114,12 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid, } if (ictl_ctx[1] & 0x1) { - pci_dma_read(&xhci->pci_dev, ictx+32, islot_ctx, sizeof(islot_ctx)); + xhci_dma_read_u32s(xhci, ictx+32, islot_ctx, sizeof(islot_ctx)); DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n", islot_ctx[0], islot_ctx[1], islot_ctx[2], islot_ctx[3]); - pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); slot_ctx[1] &= ~0xFFFF; /* max exit latency */ slot_ctx[1] |= islot_ctx[1] & 0xFFFF; @@ -1998,17 +2129,17 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid, DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n", slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); - pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); } if (ictl_ctx[1] & 0x2) { - pci_dma_read(&xhci->pci_dev, ictx+64, iep0_ctx, sizeof(iep0_ctx)); + xhci_dma_read_u32s(xhci, ictx+64, iep0_ctx, sizeof(iep0_ctx)); DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n", iep0_ctx[0], iep0_ctx[1], iep0_ctx[2], iep0_ctx[3], iep0_ctx[4]); - pci_dma_read(&xhci->pci_dev, octx+32, ep0_ctx, sizeof(ep0_ctx)); + xhci_dma_read_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx)); ep0_ctx[1] &= ~0xFFFF0000; /* max packet size*/ ep0_ctx[1] |= iep0_ctx[1] & 0xFFFF0000; @@ -2016,7 +2147,7 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid, DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n", ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]); - pci_dma_write(&xhci->pci_dev, octx+32, ep0_ctx, sizeof(ep0_ctx)); + xhci_dma_write_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx)); } return CC_SUCCESS; @@ -2029,7 +2160,7 @@ static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid) int i; trace_usb_xhci_slot_reset(slotid); - assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(slotid >= 1 && slotid <= xhci->numslots); octx = xhci->slots[slotid-1].ctx; @@ -2041,12 +2172,12 @@ static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid) } } - pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT); slot_ctx[3] |= SLOT_DEFAULT << SLOT_STATE_SHIFT; DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n", slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); - pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); return CC_SUCCESS; } @@ -2055,7 +2186,7 @@ static unsigned int xhci_get_slot(XHCIState *xhci, XHCIEvent *event, XHCITRB *tr { unsigned int slotid; slotid = (trb->control >> TRB_CR_SLOTID_SHIFT) & TRB_CR_SLOTID_MASK; - if (slotid < 1 || slotid > MAXSLOTS) { + if (slotid < 1 || slotid > xhci->numslots) { fprintf(stderr, "xhci: bad slot id %d\n", slotid); event->ccode = CC_TRB_ERROR; return 0; @@ -2070,7 +2201,7 @@ static unsigned int xhci_get_slot(XHCIState *xhci, XHCIEvent *event, XHCITRB *tr static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx) { dma_addr_t ctx; - uint8_t bw_ctx[MAXPORTS+1]; + uint8_t bw_ctx[xhci->numports+1]; DPRINTF("xhci_get_port_bandwidth()\n"); @@ -2080,7 +2211,7 @@ static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx) /* TODO: actually implement real values here */ bw_ctx[0] = 0; - memset(&bw_ctx[1], 80, MAXPORTS); /* 80% */ + memset(&bw_ctx[1], 80, xhci->numports); /* 80% */ pci_dma_write(&xhci->pci_dev, ctx, bw_ctx, sizeof(bw_ctx)); return CC_SUCCESS; @@ -2147,12 +2278,12 @@ static void xhci_process_commands(XHCIState *xhci) event.ptr = addr; switch (type) { case CR_ENABLE_SLOT: - for (i = 0; i < MAXSLOTS; i++) { + for (i = 0; i < xhci->numslots; i++) { if (!xhci->slots[i].enabled) { break; } } - if (i >= MAXSLOTS) { + if (i >= xhci->numslots) { fprintf(stderr, "xhci: no device slots available\n"); event.ccode = CC_NO_SLOTS_ERROR; } else { @@ -2244,36 +2375,90 @@ static void xhci_process_commands(XHCIState *xhci) break; } event.slotid = slotid; - xhci_event(xhci, &event); + xhci_event(xhci, &event, 0); + } +} + +static bool xhci_port_have_device(XHCIPort *port) +{ + if (!port->uport->dev || !port->uport->dev->attached) { + return false; /* no device present */ } + if (!((1 << port->uport->dev->speed) & port->speedmask)) { + return false; /* speed mismatch */ + } + return true; } -static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach) +static void xhci_port_notify(XHCIPort *port, uint32_t bits) { - int nr = port->port.index + 1; + XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, + port->portnr << 24 }; + + if ((port->portsc & bits) == bits) { + return; + } + port->portsc |= bits; + if (!xhci_running(port->xhci)) { + return; + } + xhci_event(port->xhci, &ev, 0); +} + +static void xhci_port_update(XHCIPort *port, int is_detach) +{ + uint32_t pls = PLS_RX_DETECT; port->portsc = PORTSC_PP; - if (port->port.dev && port->port.dev->attached && !is_detach) { + if (!is_detach && xhci_port_have_device(port)) { port->portsc |= PORTSC_CCS; - switch (port->port.dev->speed) { + switch (port->uport->dev->speed) { case USB_SPEED_LOW: port->portsc |= PORTSC_SPEED_LOW; + pls = PLS_POLLING; break; case USB_SPEED_FULL: port->portsc |= PORTSC_SPEED_FULL; + pls = PLS_POLLING; break; case USB_SPEED_HIGH: port->portsc |= PORTSC_SPEED_HIGH; + pls = PLS_POLLING; + break; + case USB_SPEED_SUPER: + port->portsc |= PORTSC_SPEED_SUPER; + port->portsc |= PORTSC_PED; + pls = PLS_U0; break; } } + set_field(&port->portsc, pls, PORTSC_PLS); + trace_usb_xhci_port_link(port->portnr, pls); + xhci_port_notify(port, PORTSC_CSC); +} + +static void xhci_port_reset(XHCIPort *port) +{ + trace_usb_xhci_port_reset(port->portnr); + + if (!xhci_port_have_device(port)) { + return; + } - if (xhci_running(xhci)) { - port->portsc |= PORTSC_CSC; - XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24}; - xhci_event(xhci, &ev); - DPRINTF("xhci: port change event for port %d\n", nr); + usb_device_reset(port->uport->dev); + + switch (port->uport->dev->speed) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + set_field(&port->portsc, PLS_U0, PORTSC_PLS); + trace_usb_xhci_port_link(port->portnr, PLS_U0); + port->portsc |= PORTSC_PED; + break; } + + port->portsc &= ~PORTSC_PR; + xhci_port_notify(port, PORTSC_PRC); } static void xhci_reset(DeviceState *dev) @@ -2296,32 +2481,38 @@ static void xhci_reset(DeviceState *dev) xhci->config = 0; xhci->devaddr = 2; - for (i = 0; i < MAXSLOTS; i++) { + for (i = 0; i < xhci->numslots; i++) { xhci_disable_slot(xhci, i+1); } - for (i = 0; i < MAXPORTS; i++) { - xhci_update_port(xhci, xhci->ports + i, 0); + for (i = 0; i < xhci->numports; i++) { + xhci_port_update(xhci->ports + i, 0); } - xhci->mfindex = 0; - xhci->iman = 0; - xhci->imod = 0; - xhci->erstsz = 0; - xhci->erstba_low = 0; - xhci->erstba_high = 0; - xhci->erdp_low = 0; - xhci->erdp_high = 0; + for (i = 0; i < xhci->numintrs; i++) { + xhci->intr[i].iman = 0; + xhci->intr[i].imod = 0; + xhci->intr[i].erstsz = 0; + xhci->intr[i].erstba_low = 0; + xhci->intr[i].erstba_high = 0; + xhci->intr[i].erdp_low = 0; + xhci->intr[i].erdp_high = 0; + xhci->intr[i].msix_used = 0; + + xhci->intr[i].er_ep_idx = 0; + xhci->intr[i].er_pcs = 1; + xhci->intr[i].er_full = 0; + xhci->intr[i].ev_buffer_put = 0; + xhci->intr[i].ev_buffer_get = 0; + } - xhci->er_ep_idx = 0; - xhci->er_pcs = 1; - xhci->er_full = 0; - xhci->ev_buffer_put = 0; - xhci->ev_buffer_get = 0; + xhci->mfindex_start = qemu_get_clock_ns(vm_clock); + xhci_mfwrap_update(xhci); } -static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) +static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size) { + XHCIState *xhci = ptr; uint32_t ret; switch (reg) { @@ -2329,7 +2520,8 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) ret = 0x01000000 | LEN_CAP; break; case 0x04: /* HCSPARAMS 1 */ - ret = (MAXPORTS<<24) | (MAXINTRS<<8) | MAXSLOTS; + ret = ((xhci->numports_2+xhci->numports_3)<<24) + | (xhci->numintrs<<8) | xhci->numslots; break; case 0x08: /* HCSPARAMS 2 */ ret = 0x0000000f; @@ -2356,10 +2548,10 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) ret = 0x02000402; /* USB 2.0 */ break; case 0x24: /* Supported Protocol:04 */ - ret = 0x20425455; /* "USB " */ + ret = 0x20425355; /* "USB " */ break; case 0x28: /* Supported Protocol:08 */ - ret = 0x00000001 | (USB2_PORTS<<8); + ret = 0x00000001 | (xhci->numports_2<<8); break; case 0x2c: /* Supported Protocol:0c */ ret = 0x00000000; /* reserved */ @@ -2368,16 +2560,16 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) ret = 0x03000002; /* USB 3.0 */ break; case 0x34: /* Supported Protocol:04 */ - ret = 0x20425455; /* "USB " */ + ret = 0x20425355; /* "USB " */ break; case 0x38: /* Supported Protocol:08 */ - ret = 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8); + ret = 0x00000000 | (xhci->numports_2+1) | (xhci->numports_3<<8); break; case 0x3c: /* Supported Protocol:0c */ ret = 0x00000000; /* reserved */ break; default: - fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", reg); + fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", (int)reg); ret = 0; } @@ -2385,20 +2577,14 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) return ret; } -static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg) +static uint64_t xhci_port_read(void *ptr, hwaddr reg, unsigned size) { - uint32_t port = reg >> 4; + XHCIPort *port = ptr; uint32_t ret; - if (port >= MAXPORTS) { - fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port); - ret = 0; - goto out; - } - - switch (reg & 0xf) { + switch (reg) { case 0x00: /* PORTSC */ - ret = xhci->ports[port].portsc; + ret = port->portsc; break; case 0x04: /* PORTPMSC */ case 0x08: /* PORTLI */ @@ -2407,65 +2593,56 @@ static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg) case 0x0c: /* reserved */ default: fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n", - port, reg); + port->portnr, (uint32_t)reg); ret = 0; } -out: - trace_usb_xhci_port_read(port, reg & 0x0f, ret); + trace_usb_xhci_port_read(port->portnr, reg, ret); return ret; } -static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) +static void xhci_port_write(void *ptr, hwaddr reg, + uint64_t val, unsigned size) { - uint32_t port = reg >> 4; + XHCIPort *port = ptr; uint32_t portsc; - trace_usb_xhci_port_write(port, reg & 0x0f, val); + trace_usb_xhci_port_write(port->portnr, reg, val); - if (port >= MAXPORTS) { - fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port); - return; - } - - switch (reg & 0xf) { + switch (reg) { case 0x00: /* PORTSC */ - portsc = xhci->ports[port].portsc; + portsc = port->portsc; /* write-1-to-clear bits*/ portsc &= ~(val & (PORTSC_CSC|PORTSC_PEC|PORTSC_WRC|PORTSC_OCC| PORTSC_PRC|PORTSC_PLC|PORTSC_CEC)); if (val & PORTSC_LWS) { /* overwrite PLS only when LWS=1 */ - portsc &= ~(PORTSC_PLS_MASK << PORTSC_PLS_SHIFT); - portsc |= val & (PORTSC_PLS_MASK << PORTSC_PLS_SHIFT); + uint32_t pls = get_field(val, PORTSC_PLS); + set_field(&portsc, pls, PORTSC_PLS); + trace_usb_xhci_port_link(port->portnr, pls); } /* read/write bits */ portsc &= ~(PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE); portsc |= (val & (PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE)); + port->portsc = portsc; /* write-1-to-start bits */ if (val & PORTSC_PR) { - DPRINTF("xhci: port %d reset\n", port); - usb_device_reset(xhci->ports[port].port.dev); - portsc |= PORTSC_PRC | PORTSC_PED; + xhci_port_reset(port); } - xhci->ports[port].portsc = portsc; break; case 0x04: /* PORTPMSC */ case 0x08: /* PORTLI */ default: fprintf(stderr, "xhci_port_write (port %d): reg 0x%x unimplemented\n", - port, reg); + port->portnr, (uint32_t)reg); } } -static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg) +static uint64_t xhci_oper_read(void *ptr, hwaddr reg, unsigned size) { + XHCIState *xhci = ptr; uint32_t ret; - if (reg >= 0x400) { - return xhci_port_read(xhci, reg - 0x400); - } - switch (reg) { case 0x00: /* USBCMD */ ret = xhci->usbcmd; @@ -2495,7 +2672,7 @@ static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg) ret = xhci->config; break; default: - fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", reg); + fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", (int)reg); ret = 0; } @@ -2503,12 +2680,10 @@ static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg) return ret; } -static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) +static void xhci_oper_write(void *ptr, hwaddr reg, + uint64_t val, unsigned size) { - if (reg >= 0x400) { - xhci_port_write(xhci, reg - 0x400, val); - return; - } + XHCIState *xhci = ptr; trace_usb_xhci_oper_write(reg, val); @@ -2520,16 +2695,17 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) xhci_stop(xhci); } xhci->usbcmd = val & 0xc0f; + xhci_mfwrap_update(xhci); if (val & USBCMD_HCRST) { xhci_reset(&xhci->pci_dev.qdev); } - xhci_irq_update(xhci); + xhci_intx_update(xhci); break; case 0x04: /* USBSTS */ /* these bits are write-1-to-clear */ xhci->usbsts &= ~(val & (USBSTS_HSE|USBSTS_EINT|USBSTS_PCD|USBSTS_SRE)); - xhci_irq_update(xhci); + xhci_intx_update(xhci); break; case 0x14: /* DNCTRL */ @@ -2543,7 +2719,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) if (xhci->crcr_low & (CRCR_CA|CRCR_CS) && (xhci->crcr_low & CRCR_CRR)) { XHCIEvent event = {ER_COMMAND_COMPLETE, CC_COMMAND_RING_STOPPED}; xhci->crcr_low &= ~CRCR_CRR; - xhci_event(xhci, &event); + xhci_event(xhci, &event, 0); DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low); } else { dma_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val); @@ -2561,101 +2737,127 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) xhci->config = val & 0xff; break; default: - fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); + fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", (int)reg); } } -static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) +static uint64_t xhci_runtime_read(void *ptr, hwaddr reg, + unsigned size) { - uint32_t ret; + XHCIState *xhci = ptr; + uint32_t ret = 0; - switch (reg) { - case 0x00: /* MFINDEX */ - fprintf(stderr, "xhci_runtime_read: MFINDEX not yet implemented\n"); - ret = xhci->mfindex; - break; - case 0x20: /* IMAN */ - ret = xhci->iman; - break; - case 0x24: /* IMOD */ - ret = xhci->imod; - break; - case 0x28: /* ERSTSZ */ - ret = xhci->erstsz; - break; - case 0x30: /* ERSTBA low */ - ret = xhci->erstba_low; - break; - case 0x34: /* ERSTBA high */ - ret = xhci->erstba_high; - break; - case 0x38: /* ERDP low */ - ret = xhci->erdp_low; - break; - case 0x3c: /* ERDP high */ - ret = xhci->erdp_high; - break; - default: - fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg); - ret = 0; + if (reg < 0x20) { + switch (reg) { + case 0x00: /* MFINDEX */ + ret = xhci_mfindex_get(xhci) & 0x3fff; + break; + default: + fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", + (int)reg); + break; + } + } else { + int v = (reg - 0x20) / 0x20; + XHCIInterrupter *intr = &xhci->intr[v]; + switch (reg & 0x1f) { + case 0x00: /* IMAN */ + ret = intr->iman; + break; + case 0x04: /* IMOD */ + ret = intr->imod; + break; + case 0x08: /* ERSTSZ */ + ret = intr->erstsz; + break; + case 0x10: /* ERSTBA low */ + ret = intr->erstba_low; + break; + case 0x14: /* ERSTBA high */ + ret = intr->erstba_high; + break; + case 0x18: /* ERDP low */ + ret = intr->erdp_low; + break; + case 0x1c: /* ERDP high */ + ret = intr->erdp_high; + break; + } } trace_usb_xhci_runtime_read(reg, ret); return ret; } -static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) +static void xhci_runtime_write(void *ptr, hwaddr reg, + uint64_t val, unsigned size) { - trace_usb_xhci_runtime_read(reg, val); + XHCIState *xhci = ptr; + int v = (reg - 0x20) / 0x20; + XHCIInterrupter *intr = &xhci->intr[v]; + trace_usb_xhci_runtime_write(reg, val); - switch (reg) { - case 0x20: /* IMAN */ + if (reg < 0x20) { + fprintf(stderr, "%s: reg 0x%x unimplemented\n", __func__, (int)reg); + return; + } + + switch (reg & 0x1f) { + case 0x00: /* IMAN */ if (val & IMAN_IP) { - xhci->iman &= ~IMAN_IP; + intr->iman &= ~IMAN_IP; + } + intr->iman &= ~IMAN_IE; + intr->iman |= val & IMAN_IE; + if (v == 0) { + xhci_intx_update(xhci); } - xhci->iman &= ~IMAN_IE; - xhci->iman |= val & IMAN_IE; - xhci_irq_update(xhci); + xhci_msix_update(xhci, v); break; - case 0x24: /* IMOD */ - xhci->imod = val; + case 0x04: /* IMOD */ + intr->imod = val; break; - case 0x28: /* ERSTSZ */ - xhci->erstsz = val & 0xffff; + case 0x08: /* ERSTSZ */ + intr->erstsz = val & 0xffff; break; - case 0x30: /* ERSTBA low */ + case 0x10: /* ERSTBA low */ /* XXX NEC driver bug: it doesn't align this to 64 bytes - xhci->erstba_low = val & 0xffffffc0; */ - xhci->erstba_low = val & 0xfffffff0; + intr->erstba_low = val & 0xffffffc0; */ + intr->erstba_low = val & 0xfffffff0; break; - case 0x34: /* ERSTBA high */ - xhci->erstba_high = val; - xhci_er_reset(xhci); + case 0x14: /* ERSTBA high */ + intr->erstba_high = val; + xhci_er_reset(xhci, v); break; - case 0x38: /* ERDP low */ + case 0x18: /* ERDP low */ if (val & ERDP_EHB) { - xhci->erdp_low &= ~ERDP_EHB; + intr->erdp_low &= ~ERDP_EHB; } - xhci->erdp_low = (val & ~ERDP_EHB) | (xhci->erdp_low & ERDP_EHB); + intr->erdp_low = (val & ~ERDP_EHB) | (intr->erdp_low & ERDP_EHB); break; - case 0x3c: /* ERDP high */ - xhci->erdp_high = val; - xhci_events_update(xhci); + case 0x1c: /* ERDP high */ + intr->erdp_high = val; + xhci_events_update(xhci, v); break; default: - fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); + fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", + (int)reg); } } -static uint32_t xhci_doorbell_read(XHCIState *xhci, uint32_t reg) +static uint64_t xhci_doorbell_read(void *ptr, hwaddr reg, + unsigned size) { /* doorbells always read as 0 */ trace_usb_xhci_doorbell_read(reg, 0); return 0; } -static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val) +static void xhci_doorbell_write(void *ptr, hwaddr reg, + uint64_t val, unsigned size) { + XHCIState *xhci = ptr; + trace_usb_xhci_doorbell_write(reg, val); if (!xhci_running(xhci)) { @@ -2669,69 +2871,57 @@ static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val) if (val == 0) { xhci_process_commands(xhci); } else { - fprintf(stderr, "xhci: bad doorbell 0 write: 0x%x\n", val); + fprintf(stderr, "xhci: bad doorbell 0 write: 0x%x\n", + (uint32_t)val); } } else { - if (reg > MAXSLOTS) { - fprintf(stderr, "xhci: bad doorbell %d\n", reg); + if (reg > xhci->numslots) { + fprintf(stderr, "xhci: bad doorbell %d\n", (int)reg); } else if (val > 31) { - fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n", reg, val); + fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n", + (int)reg, (uint32_t)val); } else { xhci_kick_ep(xhci, reg, val); } } } -static uint64_t xhci_mem_read(void *ptr, target_phys_addr_t addr, - unsigned size) -{ - XHCIState *xhci = ptr; - - /* Only aligned reads are allowed on xHCI */ - if (addr & 3) { - fprintf(stderr, "xhci_mem_read: Mis-aligned read\n"); - return 0; - } - - if (addr < LEN_CAP) { - return xhci_cap_read(xhci, addr); - } else if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) { - return xhci_oper_read(xhci, addr - OFF_OPER); - } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) { - return xhci_runtime_read(xhci, addr - OFF_RUNTIME); - } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) { - return xhci_doorbell_read(xhci, addr - OFF_DOORBELL); - } else { - fprintf(stderr, "xhci_mem_read: Bad offset %x\n", (int)addr); - return 0; - } -} +static const MemoryRegionOps xhci_cap_ops = { + .read = xhci_cap_read, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 4, + .impl.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; -static void xhci_mem_write(void *ptr, target_phys_addr_t addr, - uint64_t val, unsigned size) -{ - XHCIState *xhci = ptr; +static const MemoryRegionOps xhci_oper_ops = { + .read = xhci_oper_read, + .write = xhci_oper_write, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; - /* Only aligned writes are allowed on xHCI */ - if (addr & 3) { - fprintf(stderr, "xhci_mem_write: Mis-aligned write\n"); - return; - } +static const MemoryRegionOps xhci_port_ops = { + .read = xhci_port_read, + .write = xhci_port_write, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; - if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) { - xhci_oper_write(xhci, addr - OFF_OPER, val); - } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) { - xhci_runtime_write(xhci, addr - OFF_RUNTIME, val); - } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) { - xhci_doorbell_write(xhci, addr - OFF_DOORBELL, val); - } else { - fprintf(stderr, "xhci_mem_write: Bad offset %x\n", (int)addr); - } -} +static const MemoryRegionOps xhci_runtime_ops = { + .read = xhci_runtime_read, + .write = xhci_runtime_write, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; -static const MemoryRegionOps xhci_mem_ops = { - .read = xhci_mem_read, - .write = xhci_mem_write, +static const MemoryRegionOps xhci_doorbell_ops = { + .read = xhci_doorbell_read, + .write = xhci_doorbell_write, .valid.min_access_size = 4, .valid.max_access_size = 4, .endianness = DEVICE_LITTLE_ENDIAN, @@ -2740,53 +2930,57 @@ static const MemoryRegionOps xhci_mem_ops = { static void xhci_attach(USBPort *usbport) { XHCIState *xhci = usbport->opaque; - XHCIPort *port = &xhci->ports[usbport->index]; + XHCIPort *port = xhci_lookup_port(xhci, usbport); - xhci_update_port(xhci, port, 0); + xhci_port_update(port, 0); } static void xhci_detach(USBPort *usbport) { XHCIState *xhci = usbport->opaque; - XHCIPort *port = &xhci->ports[usbport->index]; + XHCIPort *port = xhci_lookup_port(xhci, usbport); - xhci_update_port(xhci, port, 1); + xhci_port_update(port, 1); } static void xhci_wakeup(USBPort *usbport) { XHCIState *xhci = usbport->opaque; - XHCIPort *port = &xhci->ports[usbport->index]; - int nr = port->port.index + 1; - XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24}; - uint32_t pls; + XHCIPort *port = xhci_lookup_port(xhci, usbport); - pls = (port->portsc >> PORTSC_PLS_SHIFT) & PORTSC_PLS_MASK; - if (pls != 3) { + if (get_field(port->portsc, PORTSC_PLS) != PLS_U3) { return; } - port->portsc |= 0xf << PORTSC_PLS_SHIFT; - if (port->portsc & PORTSC_PLC) { - return; - } - port->portsc |= PORTSC_PLC; - xhci_event(xhci, &ev); + set_field(&port->portsc, PLS_RESUME, PORTSC_PLS); + xhci_port_notify(port, PORTSC_PLC); } static void xhci_complete(USBPort *port, USBPacket *packet) { XHCITransfer *xfer = container_of(packet, XHCITransfer, packet); - xhci_complete_packet(xfer, packet->result); + if (packet->status == USB_RET_REMOVE_FROM_QUEUE) { + xhci_ep_nuke_one_xfer(xfer); + return; + } + xhci_complete_packet(xfer); xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid); } -static void xhci_child_detach(USBPort *port, USBDevice *child) +static void xhci_child_detach(USBPort *uport, USBDevice *child) { - FIXME(); + USBBus *bus = usb_bus_from_device(child); + XHCIState *xhci = container_of(bus, XHCIState, bus); + int i; + + for (i = 0; i < xhci->numslots; i++) { + if (xhci->slots[i].uport == uport) { + xhci->slots[i].uport = NULL; + } + } } -static USBPortOps xhci_port_ops = { +static USBPortOps xhci_uport_ops = { .attach = xhci_attach, .detach = xhci_detach, .wakeup = xhci_wakeup, @@ -2799,7 +2993,7 @@ static int xhci_find_slotid(XHCIState *xhci, USBDevice *dev) XHCISlot *slot; int slotid; - for (slotid = 1; slotid <= MAXSLOTS; slotid++) { + for (slotid = 1; slotid <= xhci->numslots; slotid++) { slot = &xhci->slots[slotid-1]; if (slot->devaddr == dev->addr) { return slotid; @@ -2840,28 +3034,51 @@ static USBBusOps xhci_bus_ops = { static void usb_xhci_init(XHCIState *xhci, DeviceState *dev) { - int i; + XHCIPort *port; + int i, usbports, speedmask; xhci->usbsts = USBSTS_HCH; + if (xhci->numports_2 > MAXPORTS_2) { + xhci->numports_2 = MAXPORTS_2; + } + if (xhci->numports_3 > MAXPORTS_3) { + xhci->numports_3 = MAXPORTS_3; + } + usbports = MAX(xhci->numports_2, xhci->numports_3); + xhci->numports = xhci->numports_2 + xhci->numports_3; + usb_bus_new(&xhci->bus, &xhci_bus_ops, &xhci->pci_dev.qdev); - for (i = 0; i < MAXPORTS; i++) { - memset(&xhci->ports[i], 0, sizeof(xhci->ports[i])); - usb_register_port(&xhci->bus, &xhci->ports[i].port, xhci, i, - &xhci_port_ops, - USB_SPEED_MASK_LOW | - USB_SPEED_MASK_FULL | - USB_SPEED_MASK_HIGH); - } - for (i = 0; i < MAXSLOTS; i++) { - xhci->slots[i].enabled = 0; + for (i = 0; i < usbports; i++) { + speedmask = 0; + if (i < xhci->numports_2) { + port = &xhci->ports[i]; + port->portnr = i + 1; + port->uport = &xhci->uports[i]; + port->speedmask = + USB_SPEED_MASK_LOW | + USB_SPEED_MASK_FULL | + USB_SPEED_MASK_HIGH; + snprintf(port->name, sizeof(port->name), "usb2 port #%d", i+1); + speedmask |= port->speedmask; + } + if (i < xhci->numports_3) { + port = &xhci->ports[i + xhci->numports_2]; + port->portnr = i + 1 + xhci->numports_2; + port->uport = &xhci->uports[i]; + port->speedmask = USB_SPEED_MASK_SUPER; + snprintf(port->name, sizeof(port->name), "usb3 port #%d", i+1); + speedmask |= port->speedmask; + } + usb_register_port(&xhci->bus, &xhci->uports[i], xhci, i, + &xhci_uport_ops, speedmask); } } static int usb_xhci_initfn(struct PCIDevice *dev) { - int ret; + int i, ret; XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev); @@ -2872,10 +3089,47 @@ static int usb_xhci_initfn(struct PCIDevice *dev) usb_xhci_init(xhci, &dev->qdev); + if (xhci->numintrs > MAXINTRS) { + xhci->numintrs = MAXINTRS; + } + if (xhci->numintrs < 1) { + xhci->numintrs = 1; + } + if (xhci->numslots > MAXSLOTS) { + xhci->numslots = MAXSLOTS; + } + if (xhci->numslots < 1) { + xhci->numslots = 1; + } + + xhci->mfwrap_timer = qemu_new_timer_ns(vm_clock, xhci_mfwrap_timer, xhci); + xhci->irq = xhci->pci_dev.irq[0]; - memory_region_init_io(&xhci->mem, &xhci_mem_ops, xhci, - "xhci", LEN_REGS); + memory_region_init(&xhci->mem, "xhci", LEN_REGS); + memory_region_init_io(&xhci->mem_cap, &xhci_cap_ops, xhci, + "capabilities", LEN_CAP); + memory_region_init_io(&xhci->mem_oper, &xhci_oper_ops, xhci, + "operational", 0x400); + memory_region_init_io(&xhci->mem_runtime, &xhci_runtime_ops, xhci, + "runtime", LEN_RUNTIME); + memory_region_init_io(&xhci->mem_doorbell, &xhci_doorbell_ops, xhci, + "doorbell", LEN_DOORBELL); + + memory_region_add_subregion(&xhci->mem, 0, &xhci->mem_cap); + memory_region_add_subregion(&xhci->mem, OFF_OPER, &xhci->mem_oper); + memory_region_add_subregion(&xhci->mem, OFF_RUNTIME, &xhci->mem_runtime); + memory_region_add_subregion(&xhci->mem, OFF_DOORBELL, &xhci->mem_doorbell); + + for (i = 0; i < xhci->numports; i++) { + XHCIPort *port = &xhci->ports[i]; + uint32_t offset = OFF_OPER + 0x400 + 0x10 * i; + port->xhci = xhci; + memory_region_init_io(&port->mem, &xhci_port_ops, port, + port->name, 0x10); + memory_region_add_subregion(&xhci->mem, offset, &port->mem); + } + pci_register_bar(&xhci->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64, &xhci->mem); @@ -2883,32 +3137,31 @@ static int usb_xhci_initfn(struct PCIDevice *dev) ret = pcie_cap_init(&xhci->pci_dev, 0xa0, PCI_EXP_TYPE_ENDPOINT, 0); assert(ret >= 0); - if (xhci->msi) { - ret = msi_init(&xhci->pci_dev, 0x70, 1, true, false); - assert(ret >= 0); + if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) { + msi_init(&xhci->pci_dev, 0x70, xhci->numintrs, true, false); + } + if (xhci->flags & (1 << XHCI_FLAG_USE_MSI_X)) { + msix_init(&xhci->pci_dev, xhci->numintrs, + &xhci->mem, 0, OFF_MSIX_TABLE, + &xhci->mem, 0, OFF_MSIX_PBA, + 0x90); } return 0; } -static void xhci_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, - int len) -{ - XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev); - - pci_default_write_config(dev, addr, val, len); - if (xhci->msi) { - msi_write_config(dev, addr, val, len); - } -} - static const VMStateDescription vmstate_xhci = { .name = "xhci", .unmigratable = 1, }; static Property xhci_properties[] = { - DEFINE_PROP_UINT32("msi", XHCIState, msi, 0), + DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true), + DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true), + DEFINE_PROP_UINT32("intrs", XHCIState, numintrs, MAXINTRS), + DEFINE_PROP_UINT32("slots", XHCIState, numslots, MAXSLOTS), + DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4), + DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4), DEFINE_PROP_END_OF_LIST(), }; @@ -2926,7 +3179,7 @@ static void xhci_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_SERIAL_USB; k->revision = 0x03; k->is_express = 1; - k->config_write = xhci_write_config; + k->no_hotplug = 1; } static TypeInfo xhci_info = { diff --git a/hw/usb/host-bsd.c b/hw/usb/host-bsd.c index ec26266620..340c21aeb4 100644 --- a/hw/usb/host-bsd.c +++ b/hw/usb/host-bsd.c @@ -25,7 +25,7 @@ */ #include "qemu-common.h" -#include "monitor.h" +#include "monitor/monitor.h" #include "hw/usb.h" /* usb.h declares these */ @@ -121,7 +121,7 @@ static void usb_host_handle_reset(USBDevice *dev) * -check device states against transfer requests * and return appropriate response */ -static int usb_host_handle_control(USBDevice *dev, +static void usb_host_handle_control(USBDevice *dev, USBPacket *p, int request, int value, @@ -139,7 +139,6 @@ static int usb_host_handle_control(USBDevice *dev, /* specific SET_ADDRESS support */ dev->addr = value; - return 0; } else if ((request >> 8) == UT_WRITE_DEVICE && (request & 0xff) == UR_SET_CONFIG) { @@ -151,10 +150,8 @@ static int usb_host_handle_control(USBDevice *dev, printf("handle_control: failed to set configuration - %s\n", strerror(errno)); #endif - return USB_RET_STALL; + p->status = USB_RET_STALL; } - - return 0; } else if ((request >> 8) == UT_WRITE_INTERFACE && (request & 0xff) == UR_SET_INTERFACE) { @@ -168,10 +165,8 @@ static int usb_host_handle_control(USBDevice *dev, printf("handle_control: failed to set alternate interface - %s\n", strerror(errno)); #endif - return USB_RET_STALL; + p->status = USB_RET_STALL; } - - return 0; } else { req.ucr_request.bmRequestType = request >> 8; req.ucr_request.bRequest = request & 0xff; @@ -201,14 +196,14 @@ static int usb_host_handle_control(USBDevice *dev, printf("handle_control: error after request - %s\n", strerror(errno)); #endif - return USB_RET_NAK; // STALL + p->status = USB_RET_NAK; /* STALL */ } else { - return req.ucr_actlen; + p->actual_length = req.ucr_actlen; } } } -static int usb_host_handle_data(USBDevice *dev, USBPacket *p) +static void usb_host_handle_data(USBDevice *dev, USBPacket *p) { USBHostDevice *s = (USBHostDevice *)dev; int ret, fd, mode; @@ -232,7 +227,8 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) fd = ensure_ep_open(s, devep, mode); if (fd < 0) { sigprocmask(SIG_SETMASK, &old_mask, NULL); - return USB_RET_NODEV; + p->status = USB_RET_NODEV; + return; } if (ioctl(fd, USB_SET_TIMEOUT, &timeout) < 0) { @@ -267,12 +263,13 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) switch(errno) { case ETIMEDOUT: case EINTR: - return USB_RET_NAK; + p->status = USB_RET_NAK; + break; default: - return USB_RET_STALL; + p->status = USB_RET_STALL; } } else { - return ret; + p->actual_length = ret; } } @@ -295,6 +292,7 @@ static void usb_host_handle_destroy(USBDevice *opaque) static int usb_host_initfn(USBDevice *dev) { + dev->flags |= (1 << USB_DEV_FLAG_IS_HOST); return 0; } diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index d55be878ad..669fbd245c 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -31,9 +31,9 @@ */ #include "qemu-common.h" -#include "qemu-timer.h" -#include "monitor.h" -#include "sysemu.h" +#include "qemu/timer.h" +#include "monitor/monitor.h" +#include "sysemu/sysemu.h" #include "trace.h" #include <dirent.h> @@ -135,7 +135,7 @@ static int parse_filter(const char *spec, struct USBAutoFilter *f); static void usb_host_auto_check(void *unused); static int usb_host_read_file(char *line, size_t line_size, const char *device_file, const char *device_name); -static int usb_linux_update_endp_table(USBHostDevice *s); +static void usb_linux_update_endp_table(USBHostDevice *s); static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p) { @@ -366,28 +366,34 @@ static void async_complete(void *opaque) if (p) { switch (aurb->urb.status) { case 0: - p->result += aurb->urb.actual_length; + p->actual_length += aurb->urb.actual_length; + if (!aurb->more) { + /* Clear previous ASYNC status */ + p->status = USB_RET_SUCCESS; + } break; case -EPIPE: set_halt(s, p->pid, p->ep->nr); - p->result = USB_RET_STALL; + p->status = USB_RET_STALL; break; case -EOVERFLOW: - p->result = USB_RET_BABBLE; + p->status = USB_RET_BABBLE; break; default: - p->result = USB_RET_IOERROR; + p->status = USB_RET_IOERROR; break; } if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) { - trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result); + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, aurb->urb.actual_length); usb_generic_async_ctrl_complete(&s->dev, p); } else if (!aurb->more) { - trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result); + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, aurb->urb.actual_length); usb_packet_complete(&s->dev, p); } } @@ -733,27 +739,31 @@ static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep) clear_iso_started(s, pid, ep); } -static int urb_status_to_usb_ret(int status) +static void urb_status_to_usb_ret(int status, USBPacket *p) { switch (status) { case -EPIPE: - return USB_RET_STALL; + p->status = USB_RET_STALL; + break; case -EOVERFLOW: - return USB_RET_BABBLE; + p->status = USB_RET_BABBLE; + break; default: - return USB_RET_IOERROR; + p->status = USB_RET_IOERROR; } } -static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) +static void usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) { AsyncURB *aurb; - int i, j, ret, max_packet_size, offset, len = 0; + int i, j, max_packet_size, offset, len; uint8_t *buf; max_packet_size = p->ep->max_packet_size; - if (max_packet_size == 0) - return USB_RET_NAK; + if (max_packet_size == 0) { + p->status = USB_RET_NAK; + return; + } aurb = get_iso_urb(s, p->pid, p->ep->nr); if (!aurb) { @@ -766,18 +776,17 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) if (in) { /* Check urb status */ if (aurb[i].urb.status) { - len = urb_status_to_usb_ret(aurb[i].urb.status); + urb_status_to_usb_ret(aurb[i].urb.status, p); /* Move to the next urb */ aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1; /* Check frame status */ } else if (aurb[i].urb.iso_frame_desc[j].status) { - len = urb_status_to_usb_ret( - aurb[i].urb.iso_frame_desc[j].status); + urb_status_to_usb_ret(aurb[i].urb.iso_frame_desc[j].status, p); /* Check the frame fits */ } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->iov.size) { printf("husb: received iso data is larger then packet\n"); - len = USB_RET_BABBLE; + p->status = USB_RET_BABBLE; /* All good copy data over */ } else { len = aurb[i].urb.iso_frame_desc[j].actual_length; @@ -792,7 +801,8 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) /* Check the frame fits */ if (len > max_packet_size) { printf("husb: send iso data is larger then max packet size\n"); - return USB_RET_NAK; + p->status = USB_RET_NAK; + return; } /* All good copy data over */ @@ -823,17 +833,16 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) /* (Re)-submit all fully consumed / filled urbs */ for (i = 0; i < s->iso_urb_count; i++) { if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) { - ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]); - if (ret < 0) { + if (ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]) < 0) { perror("USBDEVFS_SUBMITURB"); - if (!in || len == 0) { + if (!in || p->status == USB_RET_SUCCESS) { switch(errno) { case ETIMEDOUT: - len = USB_RET_NAK; + p->status = USB_RET_NAK; break; case EPIPE: default: - len = USB_RET_STALL; + p->status = USB_RET_STALL; } } break; @@ -843,11 +852,9 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) } } } - - return len; } -static int usb_host_handle_data(USBDevice *dev, USBPacket *p) +static void usb_host_handle_data(USBDevice *dev, USBPacket *p) { USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); struct usbdevfs_urb *urb; @@ -861,8 +868,10 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) p->ep->nr, p->iov.size); if (!is_valid(s, p->pid, p->ep->nr)) { - trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK); - return USB_RET_NAK; + p->status = USB_RET_NAK; + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, p->actual_length); + return; } if (p->pid == USB_TOKEN_IN) { @@ -876,14 +885,17 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg); if (ret < 0) { perror("USBDEVFS_CLEAR_HALT"); - trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK); - return USB_RET_NAK; + p->status = USB_RET_NAK; + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, p->actual_length); + return; } clear_halt(s, p->pid, p->ep->nr); } if (is_isoc(s, p->pid, p->ep->nr)) { - return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN); + usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN); + return; } v = 0; @@ -931,19 +943,21 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) switch(errno) { case ETIMEDOUT: + p->status = USB_RET_NAK; trace_usb_host_req_complete(s->bus_num, s->addr, p, - USB_RET_NAK); - return USB_RET_NAK; + p->status, p->actual_length); + break; case EPIPE: default: + p->status = USB_RET_STALL; trace_usb_host_req_complete(s->bus_num, s->addr, p, - USB_RET_STALL); - return USB_RET_STALL; + p->status, p->actual_length); } + return; } } while (rem > 0); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } static int ctrl_error(void) @@ -955,14 +969,13 @@ static int ctrl_error(void) } } -static int usb_host_set_address(USBHostDevice *s, int addr) +static void usb_host_set_address(USBHostDevice *s, int addr) { trace_usb_host_set_address(s->bus_num, s->addr, addr); s->dev.addr = addr; - return 0; } -static int usb_host_set_config(USBHostDevice *s, int config) +static void usb_host_set_config(USBHostDevice *s, int config, USBPacket *p) { int ret, first = 1; @@ -987,14 +1000,15 @@ again: } if (ret < 0) { - return ctrl_error(); + p->status = ctrl_error(); + return; } usb_host_claim_interfaces(s, config); usb_linux_update_endp_table(s); - return 0; } -static int usb_host_set_interface(USBHostDevice *s, int iface, int alt) +static void usb_host_set_interface(USBHostDevice *s, int iface, int alt, + USBPacket *p) { struct usbdevfs_setinterface si; int i, ret; @@ -1011,7 +1025,8 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt) } if (iface >= USB_MAX_INTERFACES) { - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } si.interface = iface; @@ -1022,15 +1037,15 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt) iface, alt, ret, errno); if (ret < 0) { - return ctrl_error(); + p->status = ctrl_error(); + return; } s->dev.altsetting[iface] = alt; usb_linux_update_endp_table(s); - return 0; } -static int usb_host_handle_control(USBDevice *dev, USBPacket *p, +static void usb_host_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); @@ -1048,19 +1063,19 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, switch (request) { case DeviceOutRequest | USB_REQ_SET_ADDRESS: - ret = usb_host_set_address(s, value); - trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret); - return ret; + usb_host_set_address(s, value); + trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); + return; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - ret = usb_host_set_config(s, value & 0xff); - trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret); - return ret; + usb_host_set_config(s, value & 0xff, p); + trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); + return; case InterfaceOutRequest | USB_REQ_SET_INTERFACE: - ret = usb_host_set_interface(s, index, value); - trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret); - return ret; + usb_host_set_interface(s, index, value, p); + trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); + return; case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: if (value == 0) { /* clear halt */ @@ -1068,16 +1083,16 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, ioctl(s->fd, USBDEVFS_CLEAR_HALT, &index); clear_halt(s, pid, index & 0x0f); trace_usb_host_req_emulated(s->bus_num, s->addr, p, 0); - return 0; + return; } } /* The rest are asynchronous */ - if (length > sizeof(dev->data_buf)) { fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n", length, sizeof(dev->data_buf)); - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } aurb = async_alloc(s); @@ -1111,18 +1126,20 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, switch(errno) { case ETIMEDOUT: - return USB_RET_NAK; + p->status = USB_RET_NAK; + break; case EPIPE: default: - return USB_RET_STALL; + p->status = USB_RET_STALL; + break; } + return; } - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } -/* returns 1 on problem encountered or 0 for success */ -static int usb_linux_update_endp_table(USBHostDevice *s) +static void usb_linux_update_endp_table(USBHostDevice *s) { static const char *tname[] = { [USB_ENDPOINT_XFER_CONTROL] = "control", @@ -1148,23 +1165,23 @@ static int usb_linux_update_endp_table(USBHostDevice *s) if (d->bLength < 2) { trace_usb_host_parse_error(s->bus_num, s->addr, "descriptor too short"); - goto error; + return; } if (i + d->bLength > s->descr_len) { trace_usb_host_parse_error(s->bus_num, s->addr, "descriptor too long"); - goto error; + return; } switch (d->bDescriptorType) { case 0: trace_usb_host_parse_error(s->bus_num, s->addr, "invalid descriptor type"); - goto error; + return; case USB_DT_DEVICE: if (d->bLength < 0x12) { trace_usb_host_parse_error(s->bus_num, s->addr, "device descriptor too short"); - goto error; + return; } v = (d->u.device.idVendor_hi << 8) | d->u.device.idVendor_lo; p = (d->u.device.idProduct_hi << 8) | d->u.device.idProduct_lo; @@ -1174,7 +1191,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s) if (d->bLength < 0x09) { trace_usb_host_parse_error(s->bus_num, s->addr, "config descriptor too short"); - goto error; + return; } configuration = d->u.config.bConfigurationValue; active = (configuration == s->dev.configuration); @@ -1185,7 +1202,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s) if (d->bLength < 0x09) { trace_usb_host_parse_error(s->bus_num, s->addr, "interface descriptor too short"); - goto error; + return; } interface = d->u.interface.bInterfaceNumber; altsetting = d->u.interface.bAlternateSetting; @@ -1198,7 +1215,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s) if (d->bLength < 0x07) { trace_usb_host_parse_error(s->bus_num, s->addr, "endpoint descriptor too short"); - goto error; + return; } devep = d->u.endpoint.bEndpointAddress; pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT; @@ -1206,7 +1223,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s) if (ep == 0) { trace_usb_host_parse_error(s->bus_num, s->addr, "invalid endpoint address"); - goto error; + return; } type = d->u.endpoint.bmAttributes & 0x3; @@ -1223,7 +1240,8 @@ static int usb_linux_update_endp_table(USBHostDevice *s) usb_ep_set_type(&s->dev, pid, ep, type); usb_ep_set_ifnum(&s->dev, pid, ep, interface); if ((s->options & (1 << USB_HOST_OPT_PIPELINE)) && - (type == USB_ENDPOINT_XFER_BULK)) { + (type == USB_ENDPOINT_XFER_BULK) && + (pid == USB_TOKEN_OUT)) { usb_ep_set_pipeline(&s->dev, pid, ep, true); } @@ -1238,11 +1256,6 @@ static int usb_linux_update_endp_table(USBHostDevice *s) break; } } - return 0; - -error: - usb_ep_reset(&s->dev); - return 1; } /* @@ -1329,10 +1342,7 @@ static int usb_host_open(USBHostDevice *dev, int bus_num, } usb_ep_init(&dev->dev); - ret = usb_linux_update_endp_table(dev); - if (ret) { - goto fail; - } + usb_linux_update_endp_table(dev); if (speed == -1) { struct usbdevfs_connectinfo ci; @@ -1466,6 +1476,7 @@ static int usb_host_initfn(USBDevice *dev) { USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); + dev->flags |= (1 << USB_DEV_FLAG_IS_HOST); dev->auto_attach = 0; s->fd = -1; s->hub_fd = -1; @@ -1726,6 +1737,7 @@ static int usb_host_scan(void *opaque, USBScanFunc *func) } static QEMUTimer *usb_auto_timer; +static VMChangeStateEntry *usb_vmstate; static int usb_host_auto_scan(void *opaque, int bus_num, int addr, const char *port, @@ -1780,6 +1792,13 @@ static int usb_host_auto_scan(void *opaque, int bus_num, return 0; } +static void usb_host_vm_state(void *unused, int running, RunState state) +{ + if (running) { + usb_host_auto_check(unused); + } +} + static void usb_host_auto_check(void *unused) { struct USBHostDevice *s; @@ -1808,6 +1827,9 @@ static void usb_host_auto_check(void *unused) } } + if (!usb_vmstate) { + usb_vmstate = qemu_add_vm_change_state_handler(usb_host_vm_state, NULL); + } if (!usb_auto_timer) { usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL); if (!usb_auto_timer) { diff --git a/hw/usb/host-stub.c b/hw/usb/host-stub.c index b4e10c12ca..58423a0f5c 100644 --- a/hw/usb/host-stub.c +++ b/hw/usb/host-stub.c @@ -31,9 +31,9 @@ */ #include "qemu-common.h" -#include "console.h" +#include "ui/console.h" #include "hw/usb.h" -#include "monitor.h" +#include "monitor/monitor.h" void usb_host_info(Monitor *mon) { diff --git a/hw/usb/libhw.c b/hw/usb/libhw.c index c0de30ea88..75f022f4ec 100644 --- a/hw/usb/libhw.c +++ b/hw/usb/libhw.c @@ -20,27 +20,33 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "cpu-common.h" +#include "exec/cpu-common.h" #include "hw/usb.h" -#include "dma.h" +#include "sysemu/dma.h" int usb_packet_map(USBPacket *p, QEMUSGList *sgl) { DMADirection dir = (p->pid == USB_TOKEN_IN) ? DMA_DIRECTION_FROM_DEVICE : DMA_DIRECTION_TO_DEVICE; - dma_addr_t len; void *mem; int i; for (i = 0; i < sgl->nsg; i++) { - len = sgl->sg[i].len; - mem = dma_memory_map(sgl->dma, sgl->sg[i].base, &len, dir); - if (!mem) { - goto err; - } - qemu_iovec_add(&p->iov, mem, len); - if (len != sgl->sg[i].len) { - goto err; + dma_addr_t base = sgl->sg[i].base; + dma_addr_t len = sgl->sg[i].len; + + while (len) { + dma_addr_t xlen = len; + mem = dma_memory_map(sgl->dma, base, &xlen, dir); + if (!mem) { + goto err; + } + if (xlen > len) { + xlen = len; + } + qemu_iovec_add(&p->iov, mem, xlen); + len -= xlen; + base += xlen; } } return 0; diff --git a/hw/usb/quirks-ftdi-ids.h b/hw/usb/quirks-ftdi-ids.h new file mode 100644 index 0000000000..57c12ef662 --- /dev/null +++ b/hw/usb/quirks-ftdi-ids.h @@ -0,0 +1,1255 @@ +/* + * vendor/product IDs (VID/PID) of devices using FTDI USB serial converters. + * Please keep numerically sorted within individual areas, thanks! + * + * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais + * from Rudolf Gugler + * + */ + + +/**********************************/ +/***** devices using FTDI VID *****/ +/**********************************/ + + +#define FTDI_VID 0x0403 /* Vendor Id */ + + +/*** "original" FTDI device PIDs ***/ + +#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */ +#define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */ +#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */ +#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */ +#define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */ +#define FTDI_FTX_PID 0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */ +#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ +#define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */ + + +/*** third-party PIDs (using FTDI_VID) ***/ + +#define FTDI_LUMEL_PD12_PID 0x6002 + +/* + * Marvell OpenRD Base, Client + * http://www.open-rd.org + * OpenRD Base, Client use VID 0x0403 + */ +#define MARVELL_OPENRD_PID 0x9e90 + +/* www.candapter.com Ewert Energy Systems CANdapter device */ +#define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */ + +/* + * Texas Instruments XDS100v2 JTAG / BeagleBone A3 + * http://processors.wiki.ti.com/index.php/XDS100 + * http://beagleboard.org/bone + */ +#define TI_XDS100V2_PID 0xa6d0 + +#define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */ + +/* US Interface Navigator (http://www.usinterface.com/) */ +#define FTDI_USINT_CAT_PID 0xb810 /* Navigator CAT and 2nd PTT lines */ +#define FTDI_USINT_WKEY_PID 0xb811 /* Navigator WKEY and FSK lines */ +#define FTDI_USINT_RS232_PID 0xb812 /* Navigator RS232 and CONFIG lines */ + +/* OOCDlink by Joern Kaipf <joernk@web.de> + * (http://www.joernonline.de/) */ +#define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */ + +/* Luminary Micro Stellaris Boards, VID = FTDI_VID */ +/* FTDI 2332C Dual channel device, side A=245 FIFO (JTAG), Side B=RS232 UART */ +#define LMI_LM3S_DEVEL_BOARD_PID 0xbcd8 +#define LMI_LM3S_EVAL_BOARD_PID 0xbcd9 +#define LMI_LM3S_ICDI_BOARD_PID 0xbcda + +#define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmbH */ + +/* OpenDCC (www.opendcc.de) product id */ +#define FTDI_OPENDCC_PID 0xBFD8 +#define FTDI_OPENDCC_SNIFFER_PID 0xBFD9 +#define FTDI_OPENDCC_THROTTLE_PID 0xBFDA +#define FTDI_OPENDCC_GATEWAY_PID 0xBFDB +#define FTDI_OPENDCC_GBM_PID 0xBFDC + +/* NZR SEM 16+ USB (http://www.nzr.de) */ +#define FTDI_NZR_SEM_USB_PID 0xC1E0 /* NZR SEM-LOG16+ */ + +/* + * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com) + */ +#define FTDI_RRCIRKITS_LOCOBUFFER_PID 0xc7d0 /* LocoBuffer USB */ + +/* DMX4ALL DMX Interfaces */ +#define FTDI_DMX4ALL 0xC850 + +/* + * ASK.fr devices + */ +#define FTDI_ASK_RDR400_PID 0xC991 /* ASK RDR 400 series card reader */ + +/* www.starting-point-systems.com µChameleon device */ +#define FTDI_MICRO_CHAMELEON_PID 0xCAA0 /* Product Id */ + +/* + * Tactrix OpenPort (ECU) devices. + * OpenPort 1.3M submitted by Donour Sizemore. + * OpenPort 1.3S and 1.3U submitted by Ian Abbott. + */ +#define FTDI_TACTRIX_OPENPORT_13M_PID 0xCC48 /* OpenPort 1.3 Mitsubishi */ +#define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */ +#define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */ + +#define FTDI_DISTORTEC_JTAG_LOCK_PICK_PID 0xCFF8 + +/* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */ +/* the VID is the standard ftdi vid (FTDI_VID) */ +#define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */ +#define FTDI_SCS_DEVICE_1_PID 0xD011 /* SCS Tracker / DSP TNC */ +#define FTDI_SCS_DEVICE_2_PID 0xD012 +#define FTDI_SCS_DEVICE_3_PID 0xD013 +#define FTDI_SCS_DEVICE_4_PID 0xD014 +#define FTDI_SCS_DEVICE_5_PID 0xD015 +#define FTDI_SCS_DEVICE_6_PID 0xD016 +#define FTDI_SCS_DEVICE_7_PID 0xD017 + +/* iPlus device */ +#define FTDI_IPLUS_PID 0xD070 /* Product Id */ +#define FTDI_IPLUS2_PID 0xD071 /* Product Id */ + +/* + * Gamma Scout (http://gamma-scout.com/). Submitted by rsc@runtux.com. + */ +#define FTDI_GAMMA_SCOUT_PID 0xD678 /* Gamma Scout online */ + +/* Propox devices */ +#define FTDI_PROPOX_JTAGCABLEII_PID 0xD738 +#define FTDI_PROPOX_ISPCABLEIII_PID 0xD739 + +/* Lenz LI-USB Computer Interface. */ +#define FTDI_LENZ_LIUSB_PID 0xD780 + +/* Vardaan Enterprises Serial Interface VEUSB422R3 */ +#define FTDI_VARDAAN_PID 0xF070 + +/* + * Xsens Technologies BV products (http://www.xsens.com). + */ +#define XSENS_CONVERTER_0_PID 0xD388 +#define XSENS_CONVERTER_1_PID 0xD389 +#define XSENS_CONVERTER_2_PID 0xD38A +#define XSENS_CONVERTER_3_PID 0xD38B +#define XSENS_CONVERTER_4_PID 0xD38C +#define XSENS_CONVERTER_5_PID 0xD38D +#define XSENS_CONVERTER_6_PID 0xD38E +#define XSENS_CONVERTER_7_PID 0xD38F + +/* + * NDI (www.ndigital.com) product ids + */ +#define FTDI_NDI_HUC_PID 0xDA70 /* NDI Host USB Converter */ +#define FTDI_NDI_SPECTRA_SCU_PID 0xDA71 /* NDI Spectra SCU */ +#define FTDI_NDI_FUTURE_2_PID 0xDA72 /* NDI future device #2 */ +#define FTDI_NDI_FUTURE_3_PID 0xDA73 /* NDI future device #3 */ +#define FTDI_NDI_AURORA_SCU_PID 0xDA74 /* NDI Aurora SCU */ + +/* + * ChamSys Limited (www.chamsys.co.uk) USB wing/interface product IDs + */ +#define FTDI_CHAMSYS_24_MASTER_WING_PID 0xDAF8 +#define FTDI_CHAMSYS_PC_WING_PID 0xDAF9 +#define FTDI_CHAMSYS_USB_DMX_PID 0xDAFA +#define FTDI_CHAMSYS_MIDI_TIMECODE_PID 0xDAFB +#define FTDI_CHAMSYS_MINI_WING_PID 0xDAFC +#define FTDI_CHAMSYS_MAXI_WING_PID 0xDAFD +#define FTDI_CHAMSYS_MEDIA_WING_PID 0xDAFE +#define FTDI_CHAMSYS_WING_PID 0xDAFF + +/* + * Westrex International devices submitted by Cory Lee + */ +#define FTDI_WESTREX_MODEL_777_PID 0xDC00 /* Model 777 */ +#define FTDI_WESTREX_MODEL_8900F_PID 0xDC01 /* Model 8900F */ + +/* + * ACG Identification Technologies GmbH products (http://www.acg.de/). + * Submitted by anton -at- goto10 -dot- org. + */ +#define FTDI_ACG_HFDUAL_PID 0xDD20 /* HF Dual ISO Reader (RFID) */ + +/* + * Definitions for Artemis astronomical USB based cameras + * Check it at http://www.artemisccd.co.uk/ + */ +#define FTDI_ARTEMIS_PID 0xDF28 /* All Artemis Cameras */ + +/* + * Definitions for ATIK Instruments astronomical USB based cameras + * Check it at http://www.atik-instruments.com/ + */ +#define FTDI_ATIK_ATK16_PID 0xDF30 /* ATIK ATK-16 Grayscale Camera */ +#define FTDI_ATIK_ATK16C_PID 0xDF32 /* ATIK ATK-16C Colour Camera */ +#define FTDI_ATIK_ATK16HR_PID 0xDF31 /* ATIK ATK-16HR Grayscale Camera */ +#define FTDI_ATIK_ATK16HRC_PID 0xDF33 /* ATIK ATK-16HRC Colour Camera */ +#define FTDI_ATIK_ATK16IC_PID 0xDF35 /* ATIK ATK-16IC Grayscale Camera */ + +/* + * Yost Engineering, Inc. products (www.yostengineering.com). + * PID 0xE050 submitted by Aaron Prose. + */ +#define FTDI_YEI_SERVOCENTER31_PID 0xE050 /* YEI ServoCenter3.1 USB */ + +/* + * ELV USB devices submitted by Christian Abt of ELV (www.elv.de). + * All of these devices use FTDI's vendor ID (0x0403). + * Further IDs taken from ELV Windows .inf file. + * + * The previously included PID for the UO 100 module was incorrect. + * In fact, that PID was for ELV's UR 100 USB-RS232 converter (0xFB58). + * + * Armin Laeuger originally sent the PID for the UM 100 module. + */ +#define FTDI_ELV_USR_PID 0xE000 /* ELV Universal-Sound-Recorder */ +#define FTDI_ELV_MSM1_PID 0xE001 /* ELV Mini-Sound-Modul */ +#define FTDI_ELV_KL100_PID 0xE002 /* ELV Kfz-Leistungsmesser KL 100 */ +#define FTDI_ELV_WS550_PID 0xE004 /* WS 550 */ +#define FTDI_ELV_EC3000_PID 0xE006 /* ENERGY CONTROL 3000 USB */ +#define FTDI_ELV_WS888_PID 0xE008 /* WS 888 */ +#define FTDI_ELV_TWS550_PID 0xE009 /* Technoline WS 550 */ +#define FTDI_ELV_FEM_PID 0xE00A /* Funk Energie Monitor */ +#define FTDI_ELV_FHZ1300PC_PID 0xE0E8 /* FHZ 1300 PC */ +#define FTDI_ELV_WS500_PID 0xE0E9 /* PC-Wetterstation (WS 500) */ +#define FTDI_ELV_HS485_PID 0xE0EA /* USB to RS-485 adapter */ +#define FTDI_ELV_UMS100_PID 0xE0EB /* ELV USB Master-Slave Schaltsteckdose UMS 100 */ +#define FTDI_ELV_TFD128_PID 0xE0EC /* ELV Temperatur-Feuchte-Datenlogger TFD 128 */ +#define FTDI_ELV_FM3RX_PID 0xE0ED /* ELV Messwertuebertragung FM3 RX */ +#define FTDI_ELV_WS777_PID 0xE0EE /* Conrad WS 777 */ +#define FTDI_ELV_EM1010PC_PID 0xE0EF /* Energy monitor EM 1010 PC */ +#define FTDI_ELV_CSI8_PID 0xE0F0 /* Computer-Schalt-Interface (CSI 8) */ +#define FTDI_ELV_EM1000DL_PID 0xE0F1 /* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */ +#define FTDI_ELV_PCK100_PID 0xE0F2 /* PC-Kabeltester (PCK 100) */ +#define FTDI_ELV_RFP500_PID 0xE0F3 /* HF-Leistungsmesser (RFP 500) */ +#define FTDI_ELV_FS20SIG_PID 0xE0F4 /* Signalgeber (FS 20 SIG) */ +#define FTDI_ELV_UTP8_PID 0xE0F5 /* ELV UTP 8 */ +#define FTDI_ELV_WS300PC_PID 0xE0F6 /* PC-Wetterstation (WS 300 PC) */ +#define FTDI_ELV_WS444PC_PID 0xE0F7 /* Conrad WS 444 PC */ +#define FTDI_PHI_FISCO_PID 0xE40B /* PHI Fisco USB to Serial cable */ +#define FTDI_ELV_UAD8_PID 0xF068 /* USB-AD-Wandler (UAD 8) */ +#define FTDI_ELV_UDA7_PID 0xF069 /* USB-DA-Wandler (UDA 7) */ +#define FTDI_ELV_USI2_PID 0xF06A /* USB-Schrittmotoren-Interface (USI 2) */ +#define FTDI_ELV_T1100_PID 0xF06B /* Thermometer (T 1100) */ +#define FTDI_ELV_PCD200_PID 0xF06C /* PC-Datenlogger (PCD 200) */ +#define FTDI_ELV_ULA200_PID 0xF06D /* USB-LCD-Ansteuerung (ULA 200) */ +#define FTDI_ELV_ALC8500_PID 0xF06E /* ALC 8500 Expert */ +#define FTDI_ELV_FHZ1000PC_PID 0xF06F /* FHZ 1000 PC */ +#define FTDI_ELV_UR100_PID 0xFB58 /* USB-RS232-Umsetzer (UR 100) */ +#define FTDI_ELV_UM100_PID 0xFB5A /* USB-Modul UM 100 */ +#define FTDI_ELV_UO100_PID 0xFB5B /* USB-Modul UO 100 */ +/* Additional ELV PIDs that default to using the FTDI D2XX drivers on + * MS Windows, rather than the FTDI Virtual Com Port drivers. + * Maybe these will be easier to use with the libftdi/libusb user-space + * drivers, or possibly the Comedi drivers in some cases. */ +#define FTDI_ELV_CLI7000_PID 0xFB59 /* Computer-Light-Interface (CLI 7000) */ +#define FTDI_ELV_PPS7330_PID 0xFB5C /* Processor-Power-Supply (PPS 7330) */ +#define FTDI_ELV_TFM100_PID 0xFB5D /* Temperatur-Feuchte-Messgeraet (TFM 100) */ +#define FTDI_ELV_UDF77_PID 0xFB5E /* USB DCF Funkuhr (UDF 77) */ +#define FTDI_ELV_UIO88_PID 0xFB5F /* USB-I/O Interface (UIO 88) */ + +/* + * EVER Eco Pro UPS (http://www.ever.com.pl/) + */ + +#define EVER_ECO_PRO_CDS 0xe520 /* RS-232 converter */ + +/* + * Active Robots product ids. + */ +#define FTDI_ACTIVE_ROBOTS_PID 0xE548 /* USB comms board */ + +/* Pyramid Computer GmbH */ +#define FTDI_PYRAMID_PID 0xE6C8 /* Pyramid Appliance Display */ + +/* www.elsterelectricity.com Elster Unicom III Optical Probe */ +#define FTDI_ELSTER_UNICOM_PID 0xE700 /* Product Id */ + +/* + * Gude Analog- und Digitalsysteme GmbH + */ +#define FTDI_GUDEADS_E808_PID 0xE808 +#define FTDI_GUDEADS_E809_PID 0xE809 +#define FTDI_GUDEADS_E80A_PID 0xE80A +#define FTDI_GUDEADS_E80B_PID 0xE80B +#define FTDI_GUDEADS_E80C_PID 0xE80C +#define FTDI_GUDEADS_E80D_PID 0xE80D +#define FTDI_GUDEADS_E80E_PID 0xE80E +#define FTDI_GUDEADS_E80F_PID 0xE80F +#define FTDI_GUDEADS_E888_PID 0xE888 /* Expert ISDN Control USB */ +#define FTDI_GUDEADS_E889_PID 0xE889 /* USB RS-232 OptoBridge */ +#define FTDI_GUDEADS_E88A_PID 0xE88A +#define FTDI_GUDEADS_E88B_PID 0xE88B +#define FTDI_GUDEADS_E88C_PID 0xE88C +#define FTDI_GUDEADS_E88D_PID 0xE88D +#define FTDI_GUDEADS_E88E_PID 0xE88E +#define FTDI_GUDEADS_E88F_PID 0xE88F + +/* + * Eclo (http://www.eclo.pt/) product IDs. + * PID 0xEA90 submitted by Martin Grill. + */ +#define FTDI_ECLO_COM_1WIRE_PID 0xEA90 /* COM to 1-Wire USB adaptor */ + +/* TNC-X USB-to-packet-radio adapter, versions prior to 3.0 (DLP module) */ +#define FTDI_TNC_X_PID 0xEBE0 + +/* + * Teratronik product ids. + * Submitted by O. Wölfelschneider. + */ +#define FTDI_TERATRONIK_VCP_PID 0xEC88 /* Teratronik device (preferring VCP driver on windows) */ +#define FTDI_TERATRONIK_D2XX_PID 0xEC89 /* Teratronik device (preferring D2XX driver on windows) */ + +/* Rig Expert Ukraine devices */ +#define FTDI_REU_TINY_PID 0xED22 /* RigExpert Tiny */ + +/* + * Hameg HO820 and HO870 interface (using VID 0x0403) + */ +#define HAMEG_HO820_PID 0xed74 +#define HAMEG_HO730_PID 0xed73 +#define HAMEG_HO720_PID 0xed72 +#define HAMEG_HO870_PID 0xed71 + +/* + * MaxStream devices www.maxstream.net + */ +#define FTDI_MAXSTREAM_PID 0xEE18 /* Xbee PKG-U Module */ + +/* + * microHAM product IDs (http://www.microham.com). + * Submitted by Justin Burket (KL1RL) <zorton@jtan.com> + * and Mike Studer (K6EEP) <k6eep@hamsoftware.org>. + * Ian Abbott <abbotti@mev.co.uk> added a few more from the driver INF file. + */ +#define FTDI_MHAM_KW_PID 0xEEE8 /* USB-KW interface */ +#define FTDI_MHAM_YS_PID 0xEEE9 /* USB-YS interface */ +#define FTDI_MHAM_Y6_PID 0xEEEA /* USB-Y6 interface */ +#define FTDI_MHAM_Y8_PID 0xEEEB /* USB-Y8 interface */ +#define FTDI_MHAM_IC_PID 0xEEEC /* USB-IC interface */ +#define FTDI_MHAM_DB9_PID 0xEEED /* USB-DB9 interface */ +#define FTDI_MHAM_RS232_PID 0xEEEE /* USB-RS232 interface */ +#define FTDI_MHAM_Y9_PID 0xEEEF /* USB-Y9 interface */ + +/* Domintell products http://www.domintell.com */ +#define FTDI_DOMINTELL_DGQG_PID 0xEF50 /* Master */ +#define FTDI_DOMINTELL_DUSB_PID 0xEF51 /* DUSB01 module */ + +/* + * The following are the values for the Perle Systems + * UltraPort USB serial converters + */ +#define FTDI_PERLE_ULTRAPORT_PID 0xF0C0 /* Perle UltraPort Product Id */ + +/* Sprog II (Andrew Crosland's SprogII DCC interface) */ +#define FTDI_SPROG_II 0xF0C8 + +/* an infrared receiver for user access control with IR tags */ +#define FTDI_PIEGROUP_PID 0xF208 /* Product Id */ + +/* ACT Solutions HomePro ZWave interface + (http://www.act-solutions.com/HomePro-Product-Matrix.html) */ +#define FTDI_ACTZWAVE_PID 0xF2D0 + +/* + * 4N-GALAXY.DE PIDs for CAN-USB, USB-RS232, USB-RS422, USB-RS485, + * USB-TTY aktiv, USB-TTY passiv. Some PIDs are used by several devices + * and I'm not entirely sure which are used by which. + */ +#define FTDI_4N_GALAXY_DE_1_PID 0xF3C0 +#define FTDI_4N_GALAXY_DE_2_PID 0xF3C1 +#define FTDI_4N_GALAXY_DE_3_PID 0xF3C2 + +/* + * Linx Technologies product ids + */ +#define LINX_SDMUSBQSS_PID 0xF448 /* Linx SDM-USB-QS-S */ +#define LINX_MASTERDEVEL2_PID 0xF449 /* Linx Master Development 2.0 */ +#define LINX_FUTURE_0_PID 0xF44A /* Linx future device */ +#define LINX_FUTURE_1_PID 0xF44B /* Linx future device */ +#define LINX_FUTURE_2_PID 0xF44C /* Linx future device */ + +/* + * Oceanic product ids + */ +#define FTDI_OCEANIC_PID 0xF460 /* Oceanic dive instrument */ + +/* + * SUUNTO product ids + */ +#define FTDI_SUUNTO_SPORTS_PID 0xF680 /* Suunto Sports instrument */ + +/* USB-UIRT - An infrared receiver and transmitter using the 8U232AM chip */ +/* http://www.usbuirt.com/ */ +#define FTDI_USB_UIRT_PID 0xF850 /* Product Id */ + +/* CCS Inc. ICDU/ICDU40 product ID - + * the FT232BM is used in an in-circuit-debugger unit for PIC16's/PIC18's */ +#define FTDI_CCSICDU20_0_PID 0xF9D0 +#define FTDI_CCSICDU40_1_PID 0xF9D1 +#define FTDI_CCSMACHX_2_PID 0xF9D2 +#define FTDI_CCSLOAD_N_GO_3_PID 0xF9D3 +#define FTDI_CCSICDU64_4_PID 0xF9D4 +#define FTDI_CCSPRIME8_5_PID 0xF9D5 + +/* + * The following are the values for the Matrix Orbital LCD displays, + * which are the FT232BM ( similar to the 8U232AM ) + */ +#define FTDI_MTXORB_0_PID 0xFA00 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_1_PID 0xFA01 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_2_PID 0xFA02 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_3_PID 0xFA03 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_4_PID 0xFA04 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */ + +/* + * Home Electronics (www.home-electro.com) USB gadgets + */ +#define FTDI_HE_TIRA1_PID 0xFA78 /* Tira-1 IR transceiver */ + +/* Inside Accesso contactless reader (http://www.insidecontactless.com/) */ +#define INSIDE_ACCESSO 0xFAD0 + +/* + * ThorLabs USB motor drivers + */ +#define FTDI_THORLABS_PID 0xfaf0 /* ThorLabs USB motor drivers */ + +/* + * Protego product ids + */ +#define PROTEGO_SPECIAL_1 0xFC70 /* special/unknown device */ +#define PROTEGO_R2X0 0xFC71 /* R200-USB TRNG unit (R210, R220, and R230) */ +#define PROTEGO_SPECIAL_3 0xFC72 /* special/unknown device */ +#define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */ + +/* + * Sony Ericsson product ids + */ +#define FTDI_DSS20_PID 0xFC82 /* DSS-20 Sync Station for Sony Ericsson P800 */ +#define FTDI_URBAN_0_PID 0xFC8A /* Sony Ericsson Urban, uart #0 */ +#define FTDI_URBAN_1_PID 0xFC8B /* Sony Ericsson Urban, uart #1 */ + +/* www.irtrans.de device */ +#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */ + +/* + * RM Michaelides CANview USB (http://www.rmcan.com) (FTDI_VID) + * CAN fieldbus interface adapter, added by port GmbH www.port.de) + * Ian Abbott changed the macro names for consistency. + */ +#define FTDI_RM_CANVIEW_PID 0xfd60 /* Product Id */ +/* www.thoughttechnology.com/ TT-USB provide with procomp use ftdi_sio */ +#define FTDI_TTUSB_PID 0xFF20 /* Product Id */ + +#define FTDI_USBX_707_PID 0xF857 /* ADSTech IR Blaster USBX-707 (FTDI_VID) */ + +#define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */ + +/* + * PCDJ use ftdi based dj-controllers. The following PID is + * for their DAC-2 device http://www.pcdjhardware.com/DAC2.asp + * (the VID is the standard ftdi vid (FTDI_VID), PID sent by Wouter Paesen) + */ +#define FTDI_PCDJ_DAC2_PID 0xFA88 + +#define FTDI_R2000KU_TRUE_RNG 0xFB80 /* R2000KU TRUE RNG (FTDI_VID) */ + +/* + * DIEBOLD BCS SE923 (FTDI_VID) + */ +#define DIEBOLD_BCS_SE923_PID 0xfb99 + +/* www.crystalfontz.com devices + * - thanx for providing free devices for evaluation ! + * they use the ftdi chipset for the USB interface + * and the vendor id is the same + */ +#define FTDI_XF_632_PID 0xFC08 /* 632: 16x2 Character Display */ +#define FTDI_XF_634_PID 0xFC09 /* 634: 20x4 Character Display */ +#define FTDI_XF_547_PID 0xFC0A /* 547: Two line Display */ +#define FTDI_XF_633_PID 0xFC0B /* 633: 16x2 Character Display with Keys */ +#define FTDI_XF_631_PID 0xFC0C /* 631: 20x2 Character Display */ +#define FTDI_XF_635_PID 0xFC0D /* 635: 20x4 Character Display */ +#define FTDI_XF_640_PID 0xFC0E /* 640: Two line Display */ +#define FTDI_XF_642_PID 0xFC0F /* 642: Two line Display */ + +/* + * Video Networks Limited / Homechoice in the UK use an ftdi-based device + * for their 1Mb broadband internet service. The following PID is exhibited + * by the usb device supplied (the VID is the standard ftdi vid (FTDI_VID) + */ +#define FTDI_VNHCPCUSB_D_PID 0xfe38 /* Product Id */ + +/* AlphaMicro Components AMC-232USB01 device (FTDI_VID) */ +#define FTDI_AMC232_PID 0xFF00 /* Product Id */ + +/* + * IBS elektronik product ids (FTDI_VID) + * Submitted by Thomas Schleusener + */ +#define FTDI_IBS_US485_PID 0xff38 /* IBS US485 (USB<-->RS422/485 interface) */ +#define FTDI_IBS_PICPRO_PID 0xff39 /* IBS PIC-Programmer */ +#define FTDI_IBS_PCMCIA_PID 0xff3a /* IBS Card reader for PCMCIA SRAM-cards */ +#define FTDI_IBS_PK1_PID 0xff3b /* IBS PK1 - Particel counter */ +#define FTDI_IBS_RS232MON_PID 0xff3c /* IBS RS232 - Monitor */ +#define FTDI_IBS_APP70_PID 0xff3d /* APP 70 (dust monitoring system) */ +#define FTDI_IBS_PEDO_PID 0xff3e /* IBS PEDO-Modem (RF modem 868.35 MHz) */ +#define FTDI_IBS_PROD_PID 0xff3f /* future device */ +/* www.canusb.com Lawicel CANUSB device (FTDI_VID) */ +#define FTDI_CANUSB_PID 0xFFA8 /* Product Id */ + +/* + * TavIR AVR product ids (FTDI_VID) + */ +#define FTDI_TAVIR_STK500_PID 0xFA33 /* STK500 AVR programmer */ + +/* + * TIAO product ids (FTDI_VID) + * http://www.tiaowiki.com/w/Main_Page + */ +#define FTDI_TIAO_UMPA_PID 0x8a98 /* TIAO/DIYGADGET USB Multi-Protocol Adapter */ + + +/********************************/ +/** third-party VID/PID combos **/ +/********************************/ + + + +/* + * Atmel STK541 + */ +#define ATMEL_VID 0x03eb /* Vendor ID */ +#define STK541_PID 0x2109 /* Zigbee Controller */ + +/* + * Blackfin gnICE JTAG + * http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:gnice + */ +#define ADI_VID 0x0456 +#define ADI_GNICE_PID 0xF000 +#define ADI_GNICEPLUS_PID 0xF001 + +/* + * Microchip Technology, Inc. + * + * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are + * used by single function CDC ACM class based firmware demo + * applications. The VID/PID has also been used in firmware + * emulating FTDI serial chips by: + * Hornby Elite - Digital Command Control Console + * http://www.hornby.com/hornby-dcc/controllers/ + */ +#define MICROCHIP_VID 0x04D8 +#define MICROCHIP_USB_BOARD_PID 0x000A /* CDC RS-232 Emulation Demo */ + +/* + * RATOC REX-USB60F + */ +#define RATOC_VENDOR_ID 0x0584 +#define RATOC_PRODUCT_ID_USB60F 0xb020 + +/* + * Acton Research Corp. + */ +#define ACTON_VID 0x0647 /* Vendor ID */ +#define ACTON_SPECTRAPRO_PID 0x0100 + +/* + * Contec products (http://www.contec.com) + * Submitted by Daniel Sangorrin + */ +#define CONTEC_VID 0x06CE /* Vendor ID */ +#define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */ + +/* + * Definitions for B&B Electronics products. + */ +#define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */ +#define BANDB_USOTL4_PID 0xAC01 /* USOTL4 Isolated RS-485 Converter */ +#define BANDB_USTL4_PID 0xAC02 /* USTL4 RS-485 Converter */ +#define BANDB_USO9ML2_PID 0xAC03 /* USO9ML2 Isolated RS-232 Converter */ +#define BANDB_USOPTL4_PID 0xAC11 +#define BANDB_USPTL4_PID 0xAC12 +#define BANDB_USO9ML2DR_2_PID 0xAC16 +#define BANDB_USO9ML2DR_PID 0xAC17 +#define BANDB_USOPTL4DR2_PID 0xAC18 /* USOPTL4R-2 2-port Isolated RS-232 Converter */ +#define BANDB_USOPTL4DR_PID 0xAC19 +#define BANDB_485USB9F_2W_PID 0xAC25 +#define BANDB_485USB9F_4W_PID 0xAC26 +#define BANDB_232USB9M_PID 0xAC27 +#define BANDB_485USBTB_2W_PID 0xAC33 +#define BANDB_485USBTB_4W_PID 0xAC34 +#define BANDB_TTL5USB9M_PID 0xAC49 +#define BANDB_TTL3USB9M_PID 0xAC50 +#define BANDB_ZZ_PROG1_USB_PID 0xBA02 + +/* + * Intrepid Control Systems (http://www.intrepidcs.com/) ValueCAN and NeoVI + */ +#define INTREPID_VID 0x093C +#define INTREPID_VALUECAN_PID 0x0601 +#define INTREPID_NEOVI_PID 0x0701 + +/* + * Definitions for ID TECH (www.idt-net.com) devices + */ +#define IDTECH_VID 0x0ACD /* ID TECH Vendor ID */ +#define IDTECH_IDT1221U_PID 0x0300 /* IDT1221U USB to RS-232 adapter */ + +/* + * Definitions for Omnidirectional Control Technology, Inc. devices + */ +#define OCT_VID 0x0B39 /* OCT vendor ID */ +/* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */ +/* Also rebadged as Dick Smith Electronics (Aus) XH6451 */ +/* Also rebadged as SIIG Inc. model US2308 hardware version 1 */ +#define OCT_DK201_PID 0x0103 /* OCT DK201 USB docking station */ +#define OCT_US101_PID 0x0421 /* OCT US101 USB to RS-232 */ + +/* + * Definitions for Icom Inc. devices + */ +#define ICOM_VID 0x0C26 /* Icom vendor ID */ +/* Note: ID-1 is a communications tranceiver for HAM-radio operators */ +#define ICOM_ID_1_PID 0x0004 /* ID-1 USB to RS-232 */ +/* Note: OPC is an Optional cable to connect an Icom Tranceiver */ +#define ICOM_OPC_U_UC_PID 0x0018 /* OPC-478UC, OPC-1122U cloning cable */ +/* Note: ID-RP* devices are Icom Repeater Devices for HAM-radio */ +#define ICOM_ID_RP2C1_PID 0x0009 /* ID-RP2C Asset 1 to RS-232 */ +#define ICOM_ID_RP2C2_PID 0x000A /* ID-RP2C Asset 2 to RS-232 */ +#define ICOM_ID_RP2D_PID 0x000B /* ID-RP2D configuration port*/ +#define ICOM_ID_RP2VT_PID 0x000C /* ID-RP2V Transmit config port */ +#define ICOM_ID_RP2VR_PID 0x000D /* ID-RP2V Receive config port */ +#define ICOM_ID_RP4KVT_PID 0x0010 /* ID-RP4000V Transmit config port */ +#define ICOM_ID_RP4KVR_PID 0x0011 /* ID-RP4000V Receive config port */ +#define ICOM_ID_RP2KVT_PID 0x0012 /* ID-RP2000V Transmit config port */ +#define ICOM_ID_RP2KVR_PID 0x0013 /* ID-RP2000V Receive config port */ + +/* + * GN Otometrics (http://www.otometrics.com) + * Submitted by Ville Sundberg. + */ +#define GN_OTOMETRICS_VID 0x0c33 /* Vendor ID */ +#define AURICAL_USB_PID 0x0010 /* Aurical USB Audiometer */ + +/* + * The following are the values for the Sealevel SeaLINK+ adapters. + * (Original list sent by Tuan Hoang. Ian Abbott renamed the macros and + * removed some PIDs that don't seem to match any existing products.) + */ +#define SEALEVEL_VID 0x0c52 /* Sealevel Vendor ID */ +#define SEALEVEL_2101_PID 0x2101 /* SeaLINK+232 (2101/2105) */ +#define SEALEVEL_2102_PID 0x2102 /* SeaLINK+485 (2102) */ +#define SEALEVEL_2103_PID 0x2103 /* SeaLINK+232I (2103) */ +#define SEALEVEL_2104_PID 0x2104 /* SeaLINK+485I (2104) */ +#define SEALEVEL_2106_PID 0x9020 /* SeaLINK+422 (2106) */ +#define SEALEVEL_2201_1_PID 0x2211 /* SeaPORT+2/232 (2201) Port 1 */ +#define SEALEVEL_2201_2_PID 0x2221 /* SeaPORT+2/232 (2201) Port 2 */ +#define SEALEVEL_2202_1_PID 0x2212 /* SeaPORT+2/485 (2202) Port 1 */ +#define SEALEVEL_2202_2_PID 0x2222 /* SeaPORT+2/485 (2202) Port 2 */ +#define SEALEVEL_2203_1_PID 0x2213 /* SeaPORT+2 (2203) Port 1 */ +#define SEALEVEL_2203_2_PID 0x2223 /* SeaPORT+2 (2203) Port 2 */ +#define SEALEVEL_2401_1_PID 0x2411 /* SeaPORT+4/232 (2401) Port 1 */ +#define SEALEVEL_2401_2_PID 0x2421 /* SeaPORT+4/232 (2401) Port 2 */ +#define SEALEVEL_2401_3_PID 0x2431 /* SeaPORT+4/232 (2401) Port 3 */ +#define SEALEVEL_2401_4_PID 0x2441 /* SeaPORT+4/232 (2401) Port 4 */ +#define SEALEVEL_2402_1_PID 0x2412 /* SeaPORT+4/485 (2402) Port 1 */ +#define SEALEVEL_2402_2_PID 0x2422 /* SeaPORT+4/485 (2402) Port 2 */ +#define SEALEVEL_2402_3_PID 0x2432 /* SeaPORT+4/485 (2402) Port 3 */ +#define SEALEVEL_2402_4_PID 0x2442 /* SeaPORT+4/485 (2402) Port 4 */ +#define SEALEVEL_2403_1_PID 0x2413 /* SeaPORT+4 (2403) Port 1 */ +#define SEALEVEL_2403_2_PID 0x2423 /* SeaPORT+4 (2403) Port 2 */ +#define SEALEVEL_2403_3_PID 0x2433 /* SeaPORT+4 (2403) Port 3 */ +#define SEALEVEL_2403_4_PID 0x2443 /* SeaPORT+4 (2403) Port 4 */ +#define SEALEVEL_2801_1_PID 0X2811 /* SeaLINK+8/232 (2801) Port 1 */ +#define SEALEVEL_2801_2_PID 0X2821 /* SeaLINK+8/232 (2801) Port 2 */ +#define SEALEVEL_2801_3_PID 0X2831 /* SeaLINK+8/232 (2801) Port 3 */ +#define SEALEVEL_2801_4_PID 0X2841 /* SeaLINK+8/232 (2801) Port 4 */ +#define SEALEVEL_2801_5_PID 0X2851 /* SeaLINK+8/232 (2801) Port 5 */ +#define SEALEVEL_2801_6_PID 0X2861 /* SeaLINK+8/232 (2801) Port 6 */ +#define SEALEVEL_2801_7_PID 0X2871 /* SeaLINK+8/232 (2801) Port 7 */ +#define SEALEVEL_2801_8_PID 0X2881 /* SeaLINK+8/232 (2801) Port 8 */ +#define SEALEVEL_2802_1_PID 0X2812 /* SeaLINK+8/485 (2802) Port 1 */ +#define SEALEVEL_2802_2_PID 0X2822 /* SeaLINK+8/485 (2802) Port 2 */ +#define SEALEVEL_2802_3_PID 0X2832 /* SeaLINK+8/485 (2802) Port 3 */ +#define SEALEVEL_2802_4_PID 0X2842 /* SeaLINK+8/485 (2802) Port 4 */ +#define SEALEVEL_2802_5_PID 0X2852 /* SeaLINK+8/485 (2802) Port 5 */ +#define SEALEVEL_2802_6_PID 0X2862 /* SeaLINK+8/485 (2802) Port 6 */ +#define SEALEVEL_2802_7_PID 0X2872 /* SeaLINK+8/485 (2802) Port 7 */ +#define SEALEVEL_2802_8_PID 0X2882 /* SeaLINK+8/485 (2802) Port 8 */ +#define SEALEVEL_2803_1_PID 0X2813 /* SeaLINK+8 (2803) Port 1 */ +#define SEALEVEL_2803_2_PID 0X2823 /* SeaLINK+8 (2803) Port 2 */ +#define SEALEVEL_2803_3_PID 0X2833 /* SeaLINK+8 (2803) Port 3 */ +#define SEALEVEL_2803_4_PID 0X2843 /* SeaLINK+8 (2803) Port 4 */ +#define SEALEVEL_2803_5_PID 0X2853 /* SeaLINK+8 (2803) Port 5 */ +#define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */ +#define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */ +#define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */ +#define SEALEVEL_2803R_1_PID 0Xa02a /* SeaLINK+8 (2803-ROHS) Port 1+2 */ +#define SEALEVEL_2803R_2_PID 0Xa02b /* SeaLINK+8 (2803-ROHS) Port 3+4 */ +#define SEALEVEL_2803R_3_PID 0Xa02c /* SeaLINK+8 (2803-ROHS) Port 5+6 */ +#define SEALEVEL_2803R_4_PID 0Xa02d /* SeaLINK+8 (2803-ROHS) Port 7+8 */ + +/* + * JETI SPECTROMETER SPECBOS 1201 + * http://www.jeti.com/cms/index.php/instruments/other-instruments/specbos-2101 + */ +#define JETI_VID 0x0c6c +#define JETI_SPC1201_PID 0x04b2 + +/* + * FTDI USB UART chips used in construction projects from the + * Elektor Electronics magazine (http://www.elektor.com/) + */ +#define ELEKTOR_VID 0x0C7D +#define ELEKTOR_FT323R_PID 0x0005 /* RFID-Reader, issue 09-2006 */ + +/* + * Posiflex inc retail equipment (http://www.posiflex.com.tw) + */ +#define POSIFLEX_VID 0x0d3a /* Vendor ID */ +#define POSIFLEX_PP7000_PID 0x0300 /* PP-7000II thermal printer */ + +/* + * The following are the values for two KOBIL chipcard terminals. + */ +#define KOBIL_VID 0x0d46 /* KOBIL Vendor ID */ +#define KOBIL_CONV_B1_PID 0x2020 /* KOBIL Konverter for B1 */ +#define KOBIL_CONV_KAAN_PID 0x2021 /* KOBIL_Konverter for KAAN */ + +#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ +#define FTDI_NF_RIC_PID 0x0001 /* Product Id */ + +/* + * Falcom Wireless Communications GmbH + */ +#define FALCOM_VID 0x0F94 /* Vendor Id */ +#define FALCOM_TWIST_PID 0x0001 /* Falcom Twist USB GPRS modem */ +#define FALCOM_SAMBA_PID 0x0005 /* Falcom Samba USB GPRS modem */ + +/* Larsen and Brusgaard AltiTrack/USBtrack */ +#define LARSENBRUSGAARD_VID 0x0FD8 +#define LB_ALTITRACK_PID 0x0001 + +/* + * TTi (Thurlby Thandar Instruments) + */ +#define TTI_VID 0x103E /* Vendor Id */ +#define TTI_QL355P_PID 0x03E8 /* TTi QL355P power supply */ + +/* Interbiometrics USB I/O Board */ +/* Developed for Interbiometrics by Rudolf Gugler */ +#define INTERBIOMETRICS_VID 0x1209 +#define INTERBIOMETRICS_IOBOARD_PID 0x1002 +#define INTERBIOMETRICS_MINI_IOBOARD_PID 0x1006 + +/* + * Testo products (http://www.testo.com/) + * Submitted by Colin Leroy + */ +#define TESTO_VID 0x128D +#define TESTO_USB_INTERFACE_PID 0x0001 + +/* + * Mobility Electronics products. + */ +#define MOBILITY_VID 0x1342 +#define MOBILITY_USB_SERIAL_PID 0x0202 /* EasiDock USB 200 serial */ + +/* + * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3 + * Submitted by Harald Welte <laforge@openmoko.org> + */ +#define FIC_VID 0x1457 +#define FIC_NEO1973_DEBUG_PID 0x5118 + +/* Olimex */ +#define OLIMEX_VID 0x15BA +#define OLIMEX_ARM_USB_OCD_PID 0x0003 +#define OLIMEX_ARM_USB_OCD_H_PID 0x002b + +/* + * Telldus Technologies + */ +#define TELLDUS_VID 0x1781 /* Vendor ID */ +#define TELLDUS_TELLSTICK_PID 0x0C30 /* RF control dongle 433 MHz using FT232RL */ + +/* + * RT Systems programming cables for various ham radios + */ +#define RTSYSTEMS_VID 0x2100 /* Vendor ID */ +#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */ +#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */ +#define RTSYSTEMS_RTS01_PID 0x9e57 /* USB-RTS01 Radio Cable */ + + +/* + * Physik Instrumente + * http://www.physikinstrumente.com/en/products/ + */ +/* These two devices use the VID of FTDI */ +#define PI_C865_PID 0xe0a0 /* PI C-865 Piezomotor Controller */ +#define PI_C857_PID 0xe0a1 /* PI Encoder Trigger Box */ + +#define PI_VID 0x1a72 /* Vendor ID */ +#define PI_C866_PID 0x1000 /* PI C-866 Piezomotor Controller */ +#define PI_C663_PID 0x1001 /* PI C-663 Mercury-Step */ +#define PI_C725_PID 0x1002 /* PI C-725 Piezomotor Controller */ +#define PI_E517_PID 0x1005 /* PI E-517 Digital Piezo Controller Operation Module */ +#define PI_C863_PID 0x1007 /* PI C-863 */ +#define PI_E861_PID 0x1008 /* PI E-861 Piezomotor Controller */ +#define PI_C867_PID 0x1009 /* PI C-867 Piezomotor Controller */ +#define PI_E609_PID 0x100D /* PI E-609 Digital Piezo Controller */ +#define PI_E709_PID 0x100E /* PI E-709 Digital Piezo Controller */ +#define PI_100F_PID 0x100F /* PI Digital Piezo Controller */ +#define PI_1011_PID 0x1011 /* PI Digital Piezo Controller */ +#define PI_1012_PID 0x1012 /* PI Motion Controller */ +#define PI_1013_PID 0x1013 /* PI Motion Controller */ +#define PI_1014_PID 0x1014 /* PI Device */ +#define PI_1015_PID 0x1015 /* PI Device */ +#define PI_1016_PID 0x1016 /* PI Digital Servo Module */ + +/* + * Kondo Kagaku Co.Ltd. + * http://www.kondo-robot.com/EN + */ +#define KONDO_VID 0x165c +#define KONDO_USB_SERIAL_PID 0x0002 + +/* + * Bayer Ascensia Contour blood glucose meter USB-converter cable. + * http://winglucofacts.com/cables/ + */ +#define BAYER_VID 0x1A79 +#define BAYER_CONTOUR_CABLE_PID 0x6001 + +/* + * The following are the values for the Matrix Orbital FTDI Range + * Anything in this range will use an FT232RL. + */ +#define MTXORB_VID 0x1B3D +#define MTXORB_FTDI_RANGE_0100_PID 0x0100 +#define MTXORB_FTDI_RANGE_0101_PID 0x0101 +#define MTXORB_FTDI_RANGE_0102_PID 0x0102 +#define MTXORB_FTDI_RANGE_0103_PID 0x0103 +#define MTXORB_FTDI_RANGE_0104_PID 0x0104 +#define MTXORB_FTDI_RANGE_0105_PID 0x0105 +#define MTXORB_FTDI_RANGE_0106_PID 0x0106 +#define MTXORB_FTDI_RANGE_0107_PID 0x0107 +#define MTXORB_FTDI_RANGE_0108_PID 0x0108 +#define MTXORB_FTDI_RANGE_0109_PID 0x0109 +#define MTXORB_FTDI_RANGE_010A_PID 0x010A +#define MTXORB_FTDI_RANGE_010B_PID 0x010B +#define MTXORB_FTDI_RANGE_010C_PID 0x010C +#define MTXORB_FTDI_RANGE_010D_PID 0x010D +#define MTXORB_FTDI_RANGE_010E_PID 0x010E +#define MTXORB_FTDI_RANGE_010F_PID 0x010F +#define MTXORB_FTDI_RANGE_0110_PID 0x0110 +#define MTXORB_FTDI_RANGE_0111_PID 0x0111 +#define MTXORB_FTDI_RANGE_0112_PID 0x0112 +#define MTXORB_FTDI_RANGE_0113_PID 0x0113 +#define MTXORB_FTDI_RANGE_0114_PID 0x0114 +#define MTXORB_FTDI_RANGE_0115_PID 0x0115 +#define MTXORB_FTDI_RANGE_0116_PID 0x0116 +#define MTXORB_FTDI_RANGE_0117_PID 0x0117 +#define MTXORB_FTDI_RANGE_0118_PID 0x0118 +#define MTXORB_FTDI_RANGE_0119_PID 0x0119 +#define MTXORB_FTDI_RANGE_011A_PID 0x011A +#define MTXORB_FTDI_RANGE_011B_PID 0x011B +#define MTXORB_FTDI_RANGE_011C_PID 0x011C +#define MTXORB_FTDI_RANGE_011D_PID 0x011D +#define MTXORB_FTDI_RANGE_011E_PID 0x011E +#define MTXORB_FTDI_RANGE_011F_PID 0x011F +#define MTXORB_FTDI_RANGE_0120_PID 0x0120 +#define MTXORB_FTDI_RANGE_0121_PID 0x0121 +#define MTXORB_FTDI_RANGE_0122_PID 0x0122 +#define MTXORB_FTDI_RANGE_0123_PID 0x0123 +#define MTXORB_FTDI_RANGE_0124_PID 0x0124 +#define MTXORB_FTDI_RANGE_0125_PID 0x0125 +#define MTXORB_FTDI_RANGE_0126_PID 0x0126 +#define MTXORB_FTDI_RANGE_0127_PID 0x0127 +#define MTXORB_FTDI_RANGE_0128_PID 0x0128 +#define MTXORB_FTDI_RANGE_0129_PID 0x0129 +#define MTXORB_FTDI_RANGE_012A_PID 0x012A +#define MTXORB_FTDI_RANGE_012B_PID 0x012B +#define MTXORB_FTDI_RANGE_012C_PID 0x012C +#define MTXORB_FTDI_RANGE_012D_PID 0x012D +#define MTXORB_FTDI_RANGE_012E_PID 0x012E +#define MTXORB_FTDI_RANGE_012F_PID 0x012F +#define MTXORB_FTDI_RANGE_0130_PID 0x0130 +#define MTXORB_FTDI_RANGE_0131_PID 0x0131 +#define MTXORB_FTDI_RANGE_0132_PID 0x0132 +#define MTXORB_FTDI_RANGE_0133_PID 0x0133 +#define MTXORB_FTDI_RANGE_0134_PID 0x0134 +#define MTXORB_FTDI_RANGE_0135_PID 0x0135 +#define MTXORB_FTDI_RANGE_0136_PID 0x0136 +#define MTXORB_FTDI_RANGE_0137_PID 0x0137 +#define MTXORB_FTDI_RANGE_0138_PID 0x0138 +#define MTXORB_FTDI_RANGE_0139_PID 0x0139 +#define MTXORB_FTDI_RANGE_013A_PID 0x013A +#define MTXORB_FTDI_RANGE_013B_PID 0x013B +#define MTXORB_FTDI_RANGE_013C_PID 0x013C +#define MTXORB_FTDI_RANGE_013D_PID 0x013D +#define MTXORB_FTDI_RANGE_013E_PID 0x013E +#define MTXORB_FTDI_RANGE_013F_PID 0x013F +#define MTXORB_FTDI_RANGE_0140_PID 0x0140 +#define MTXORB_FTDI_RANGE_0141_PID 0x0141 +#define MTXORB_FTDI_RANGE_0142_PID 0x0142 +#define MTXORB_FTDI_RANGE_0143_PID 0x0143 +#define MTXORB_FTDI_RANGE_0144_PID 0x0144 +#define MTXORB_FTDI_RANGE_0145_PID 0x0145 +#define MTXORB_FTDI_RANGE_0146_PID 0x0146 +#define MTXORB_FTDI_RANGE_0147_PID 0x0147 +#define MTXORB_FTDI_RANGE_0148_PID 0x0148 +#define MTXORB_FTDI_RANGE_0149_PID 0x0149 +#define MTXORB_FTDI_RANGE_014A_PID 0x014A +#define MTXORB_FTDI_RANGE_014B_PID 0x014B +#define MTXORB_FTDI_RANGE_014C_PID 0x014C +#define MTXORB_FTDI_RANGE_014D_PID 0x014D +#define MTXORB_FTDI_RANGE_014E_PID 0x014E +#define MTXORB_FTDI_RANGE_014F_PID 0x014F +#define MTXORB_FTDI_RANGE_0150_PID 0x0150 +#define MTXORB_FTDI_RANGE_0151_PID 0x0151 +#define MTXORB_FTDI_RANGE_0152_PID 0x0152 +#define MTXORB_FTDI_RANGE_0153_PID 0x0153 +#define MTXORB_FTDI_RANGE_0154_PID 0x0154 +#define MTXORB_FTDI_RANGE_0155_PID 0x0155 +#define MTXORB_FTDI_RANGE_0156_PID 0x0156 +#define MTXORB_FTDI_RANGE_0157_PID 0x0157 +#define MTXORB_FTDI_RANGE_0158_PID 0x0158 +#define MTXORB_FTDI_RANGE_0159_PID 0x0159 +#define MTXORB_FTDI_RANGE_015A_PID 0x015A +#define MTXORB_FTDI_RANGE_015B_PID 0x015B +#define MTXORB_FTDI_RANGE_015C_PID 0x015C +#define MTXORB_FTDI_RANGE_015D_PID 0x015D +#define MTXORB_FTDI_RANGE_015E_PID 0x015E +#define MTXORB_FTDI_RANGE_015F_PID 0x015F +#define MTXORB_FTDI_RANGE_0160_PID 0x0160 +#define MTXORB_FTDI_RANGE_0161_PID 0x0161 +#define MTXORB_FTDI_RANGE_0162_PID 0x0162 +#define MTXORB_FTDI_RANGE_0163_PID 0x0163 +#define MTXORB_FTDI_RANGE_0164_PID 0x0164 +#define MTXORB_FTDI_RANGE_0165_PID 0x0165 +#define MTXORB_FTDI_RANGE_0166_PID 0x0166 +#define MTXORB_FTDI_RANGE_0167_PID 0x0167 +#define MTXORB_FTDI_RANGE_0168_PID 0x0168 +#define MTXORB_FTDI_RANGE_0169_PID 0x0169 +#define MTXORB_FTDI_RANGE_016A_PID 0x016A +#define MTXORB_FTDI_RANGE_016B_PID 0x016B +#define MTXORB_FTDI_RANGE_016C_PID 0x016C +#define MTXORB_FTDI_RANGE_016D_PID 0x016D +#define MTXORB_FTDI_RANGE_016E_PID 0x016E +#define MTXORB_FTDI_RANGE_016F_PID 0x016F +#define MTXORB_FTDI_RANGE_0170_PID 0x0170 +#define MTXORB_FTDI_RANGE_0171_PID 0x0171 +#define MTXORB_FTDI_RANGE_0172_PID 0x0172 +#define MTXORB_FTDI_RANGE_0173_PID 0x0173 +#define MTXORB_FTDI_RANGE_0174_PID 0x0174 +#define MTXORB_FTDI_RANGE_0175_PID 0x0175 +#define MTXORB_FTDI_RANGE_0176_PID 0x0176 +#define MTXORB_FTDI_RANGE_0177_PID 0x0177 +#define MTXORB_FTDI_RANGE_0178_PID 0x0178 +#define MTXORB_FTDI_RANGE_0179_PID 0x0179 +#define MTXORB_FTDI_RANGE_017A_PID 0x017A +#define MTXORB_FTDI_RANGE_017B_PID 0x017B +#define MTXORB_FTDI_RANGE_017C_PID 0x017C +#define MTXORB_FTDI_RANGE_017D_PID 0x017D +#define MTXORB_FTDI_RANGE_017E_PID 0x017E +#define MTXORB_FTDI_RANGE_017F_PID 0x017F +#define MTXORB_FTDI_RANGE_0180_PID 0x0180 +#define MTXORB_FTDI_RANGE_0181_PID 0x0181 +#define MTXORB_FTDI_RANGE_0182_PID 0x0182 +#define MTXORB_FTDI_RANGE_0183_PID 0x0183 +#define MTXORB_FTDI_RANGE_0184_PID 0x0184 +#define MTXORB_FTDI_RANGE_0185_PID 0x0185 +#define MTXORB_FTDI_RANGE_0186_PID 0x0186 +#define MTXORB_FTDI_RANGE_0187_PID 0x0187 +#define MTXORB_FTDI_RANGE_0188_PID 0x0188 +#define MTXORB_FTDI_RANGE_0189_PID 0x0189 +#define MTXORB_FTDI_RANGE_018A_PID 0x018A +#define MTXORB_FTDI_RANGE_018B_PID 0x018B +#define MTXORB_FTDI_RANGE_018C_PID 0x018C +#define MTXORB_FTDI_RANGE_018D_PID 0x018D +#define MTXORB_FTDI_RANGE_018E_PID 0x018E +#define MTXORB_FTDI_RANGE_018F_PID 0x018F +#define MTXORB_FTDI_RANGE_0190_PID 0x0190 +#define MTXORB_FTDI_RANGE_0191_PID 0x0191 +#define MTXORB_FTDI_RANGE_0192_PID 0x0192 +#define MTXORB_FTDI_RANGE_0193_PID 0x0193 +#define MTXORB_FTDI_RANGE_0194_PID 0x0194 +#define MTXORB_FTDI_RANGE_0195_PID 0x0195 +#define MTXORB_FTDI_RANGE_0196_PID 0x0196 +#define MTXORB_FTDI_RANGE_0197_PID 0x0197 +#define MTXORB_FTDI_RANGE_0198_PID 0x0198 +#define MTXORB_FTDI_RANGE_0199_PID 0x0199 +#define MTXORB_FTDI_RANGE_019A_PID 0x019A +#define MTXORB_FTDI_RANGE_019B_PID 0x019B +#define MTXORB_FTDI_RANGE_019C_PID 0x019C +#define MTXORB_FTDI_RANGE_019D_PID 0x019D +#define MTXORB_FTDI_RANGE_019E_PID 0x019E +#define MTXORB_FTDI_RANGE_019F_PID 0x019F +#define MTXORB_FTDI_RANGE_01A0_PID 0x01A0 +#define MTXORB_FTDI_RANGE_01A1_PID 0x01A1 +#define MTXORB_FTDI_RANGE_01A2_PID 0x01A2 +#define MTXORB_FTDI_RANGE_01A3_PID 0x01A3 +#define MTXORB_FTDI_RANGE_01A4_PID 0x01A4 +#define MTXORB_FTDI_RANGE_01A5_PID 0x01A5 +#define MTXORB_FTDI_RANGE_01A6_PID 0x01A6 +#define MTXORB_FTDI_RANGE_01A7_PID 0x01A7 +#define MTXORB_FTDI_RANGE_01A8_PID 0x01A8 +#define MTXORB_FTDI_RANGE_01A9_PID 0x01A9 +#define MTXORB_FTDI_RANGE_01AA_PID 0x01AA +#define MTXORB_FTDI_RANGE_01AB_PID 0x01AB +#define MTXORB_FTDI_RANGE_01AC_PID 0x01AC +#define MTXORB_FTDI_RANGE_01AD_PID 0x01AD +#define MTXORB_FTDI_RANGE_01AE_PID 0x01AE +#define MTXORB_FTDI_RANGE_01AF_PID 0x01AF +#define MTXORB_FTDI_RANGE_01B0_PID 0x01B0 +#define MTXORB_FTDI_RANGE_01B1_PID 0x01B1 +#define MTXORB_FTDI_RANGE_01B2_PID 0x01B2 +#define MTXORB_FTDI_RANGE_01B3_PID 0x01B3 +#define MTXORB_FTDI_RANGE_01B4_PID 0x01B4 +#define MTXORB_FTDI_RANGE_01B5_PID 0x01B5 +#define MTXORB_FTDI_RANGE_01B6_PID 0x01B6 +#define MTXORB_FTDI_RANGE_01B7_PID 0x01B7 +#define MTXORB_FTDI_RANGE_01B8_PID 0x01B8 +#define MTXORB_FTDI_RANGE_01B9_PID 0x01B9 +#define MTXORB_FTDI_RANGE_01BA_PID 0x01BA +#define MTXORB_FTDI_RANGE_01BB_PID 0x01BB +#define MTXORB_FTDI_RANGE_01BC_PID 0x01BC +#define MTXORB_FTDI_RANGE_01BD_PID 0x01BD +#define MTXORB_FTDI_RANGE_01BE_PID 0x01BE +#define MTXORB_FTDI_RANGE_01BF_PID 0x01BF +#define MTXORB_FTDI_RANGE_01C0_PID 0x01C0 +#define MTXORB_FTDI_RANGE_01C1_PID 0x01C1 +#define MTXORB_FTDI_RANGE_01C2_PID 0x01C2 +#define MTXORB_FTDI_RANGE_01C3_PID 0x01C3 +#define MTXORB_FTDI_RANGE_01C4_PID 0x01C4 +#define MTXORB_FTDI_RANGE_01C5_PID 0x01C5 +#define MTXORB_FTDI_RANGE_01C6_PID 0x01C6 +#define MTXORB_FTDI_RANGE_01C7_PID 0x01C7 +#define MTXORB_FTDI_RANGE_01C8_PID 0x01C8 +#define MTXORB_FTDI_RANGE_01C9_PID 0x01C9 +#define MTXORB_FTDI_RANGE_01CA_PID 0x01CA +#define MTXORB_FTDI_RANGE_01CB_PID 0x01CB +#define MTXORB_FTDI_RANGE_01CC_PID 0x01CC +#define MTXORB_FTDI_RANGE_01CD_PID 0x01CD +#define MTXORB_FTDI_RANGE_01CE_PID 0x01CE +#define MTXORB_FTDI_RANGE_01CF_PID 0x01CF +#define MTXORB_FTDI_RANGE_01D0_PID 0x01D0 +#define MTXORB_FTDI_RANGE_01D1_PID 0x01D1 +#define MTXORB_FTDI_RANGE_01D2_PID 0x01D2 +#define MTXORB_FTDI_RANGE_01D3_PID 0x01D3 +#define MTXORB_FTDI_RANGE_01D4_PID 0x01D4 +#define MTXORB_FTDI_RANGE_01D5_PID 0x01D5 +#define MTXORB_FTDI_RANGE_01D6_PID 0x01D6 +#define MTXORB_FTDI_RANGE_01D7_PID 0x01D7 +#define MTXORB_FTDI_RANGE_01D8_PID 0x01D8 +#define MTXORB_FTDI_RANGE_01D9_PID 0x01D9 +#define MTXORB_FTDI_RANGE_01DA_PID 0x01DA +#define MTXORB_FTDI_RANGE_01DB_PID 0x01DB +#define MTXORB_FTDI_RANGE_01DC_PID 0x01DC +#define MTXORB_FTDI_RANGE_01DD_PID 0x01DD +#define MTXORB_FTDI_RANGE_01DE_PID 0x01DE +#define MTXORB_FTDI_RANGE_01DF_PID 0x01DF +#define MTXORB_FTDI_RANGE_01E0_PID 0x01E0 +#define MTXORB_FTDI_RANGE_01E1_PID 0x01E1 +#define MTXORB_FTDI_RANGE_01E2_PID 0x01E2 +#define MTXORB_FTDI_RANGE_01E3_PID 0x01E3 +#define MTXORB_FTDI_RANGE_01E4_PID 0x01E4 +#define MTXORB_FTDI_RANGE_01E5_PID 0x01E5 +#define MTXORB_FTDI_RANGE_01E6_PID 0x01E6 +#define MTXORB_FTDI_RANGE_01E7_PID 0x01E7 +#define MTXORB_FTDI_RANGE_01E8_PID 0x01E8 +#define MTXORB_FTDI_RANGE_01E9_PID 0x01E9 +#define MTXORB_FTDI_RANGE_01EA_PID 0x01EA +#define MTXORB_FTDI_RANGE_01EB_PID 0x01EB +#define MTXORB_FTDI_RANGE_01EC_PID 0x01EC +#define MTXORB_FTDI_RANGE_01ED_PID 0x01ED +#define MTXORB_FTDI_RANGE_01EE_PID 0x01EE +#define MTXORB_FTDI_RANGE_01EF_PID 0x01EF +#define MTXORB_FTDI_RANGE_01F0_PID 0x01F0 +#define MTXORB_FTDI_RANGE_01F1_PID 0x01F1 +#define MTXORB_FTDI_RANGE_01F2_PID 0x01F2 +#define MTXORB_FTDI_RANGE_01F3_PID 0x01F3 +#define MTXORB_FTDI_RANGE_01F4_PID 0x01F4 +#define MTXORB_FTDI_RANGE_01F5_PID 0x01F5 +#define MTXORB_FTDI_RANGE_01F6_PID 0x01F6 +#define MTXORB_FTDI_RANGE_01F7_PID 0x01F7 +#define MTXORB_FTDI_RANGE_01F8_PID 0x01F8 +#define MTXORB_FTDI_RANGE_01F9_PID 0x01F9 +#define MTXORB_FTDI_RANGE_01FA_PID 0x01FA +#define MTXORB_FTDI_RANGE_01FB_PID 0x01FB +#define MTXORB_FTDI_RANGE_01FC_PID 0x01FC +#define MTXORB_FTDI_RANGE_01FD_PID 0x01FD +#define MTXORB_FTDI_RANGE_01FE_PID 0x01FE +#define MTXORB_FTDI_RANGE_01FF_PID 0x01FF + + + +/* + * The Mobility Lab (TML) + * Submitted by Pierre Castella + */ +#define TML_VID 0x1B91 /* Vendor ID */ +#define TML_USB_SERIAL_PID 0x0064 /* USB - Serial Converter */ + +/* Alti-2 products http://www.alti-2.com */ +#define ALTI2_VID 0x1BC9 +#define ALTI2_N3_PID 0x6001 /* Neptune 3 */ + +/* + * Ionics PlugComputer + */ +#define IONICS_VID 0x1c0c +#define IONICS_PLUGCOMPUTER_PID 0x0102 + +/* + * Dresden Elektronik Sensor Terminal Board + */ +#define DE_VID 0x1cf1 /* Vendor ID */ +#define STB_PID 0x0001 /* Sensor Terminal Board */ +#define WHT_PID 0x0004 /* Wireless Handheld Terminal */ + +/* + * STMicroelectonics + */ +#define ST_VID 0x0483 +#define ST_STMCLT1030_PID 0x3747 /* ST Micro Connect Lite STMCLT1030 */ + +/* + * Papouch products (http://www.papouch.com/) + * Submitted by Folkert van Heusden + */ + +#define PAPOUCH_VID 0x5050 /* Vendor ID */ +#define PAPOUCH_SB485_PID 0x0100 /* Papouch SB485 USB-485/422 Converter */ +#define PAPOUCH_AP485_PID 0x0101 /* AP485 USB-RS485 Converter */ +#define PAPOUCH_SB422_PID 0x0102 /* Papouch SB422 USB-RS422 Converter */ +#define PAPOUCH_SB485_2_PID 0x0103 /* Papouch SB485 USB-485/422 Converter */ +#define PAPOUCH_AP485_2_PID 0x0104 /* AP485 USB-RS485 Converter */ +#define PAPOUCH_SB422_2_PID 0x0105 /* Papouch SB422 USB-RS422 Converter */ +#define PAPOUCH_SB485S_PID 0x0106 /* Papouch SB485S USB-485/422 Converter */ +#define PAPOUCH_SB485C_PID 0x0107 /* Papouch SB485C USB-485/422 Converter */ +#define PAPOUCH_LEC_PID 0x0300 /* LEC USB Converter */ +#define PAPOUCH_SB232_PID 0x0301 /* Papouch SB232 USB-RS232 Converter */ +#define PAPOUCH_TMU_PID 0x0400 /* TMU USB Thermometer */ +#define PAPOUCH_IRAMP_PID 0x0500 /* Papouch IRAmp Duplex */ +#define PAPOUCH_DRAK5_PID 0x0700 /* Papouch DRAK5 */ +#define PAPOUCH_QUIDO8x8_PID 0x0800 /* Papouch Quido 8/8 Module */ +#define PAPOUCH_QUIDO4x4_PID 0x0900 /* Papouch Quido 4/4 Module */ +#define PAPOUCH_QUIDO2x2_PID 0x0a00 /* Papouch Quido 2/2 Module */ +#define PAPOUCH_QUIDO10x1_PID 0x0b00 /* Papouch Quido 10/1 Module */ +#define PAPOUCH_QUIDO30x3_PID 0x0c00 /* Papouch Quido 30/3 Module */ +#define PAPOUCH_QUIDO60x3_PID 0x0d00 /* Papouch Quido 60(100)/3 Module */ +#define PAPOUCH_QUIDO2x16_PID 0x0e00 /* Papouch Quido 2/16 Module */ +#define PAPOUCH_QUIDO3x32_PID 0x0f00 /* Papouch Quido 3/32 Module */ +#define PAPOUCH_DRAK6_PID 0x1000 /* Papouch DRAK6 */ +#define PAPOUCH_UPSUSB_PID 0x8000 /* Papouch UPS-USB adapter */ +#define PAPOUCH_MU_PID 0x8001 /* MU controller */ +#define PAPOUCH_SIMUKEY_PID 0x8002 /* Papouch SimuKey */ +#define PAPOUCH_AD4USB_PID 0x8003 /* AD4USB Measurement Module */ +#define PAPOUCH_GMUX_PID 0x8004 /* Papouch GOLIATH MUX */ +#define PAPOUCH_GMSR_PID 0x8005 /* Papouch GOLIATH MSR */ + +/* + * Marvell SheevaPlug + */ +#define MARVELL_VID 0x9e88 +#define MARVELL_SHEEVAPLUG_PID 0x9e8f + +/* + * Evolution Robotics products (http://www.evolution.com/). + * Submitted by Shawn M. Lavelle. + */ +#define EVOLUTION_VID 0xDEEE /* Vendor ID */ +#define EVOLUTION_ER1_PID 0x0300 /* ER1 Control Module */ +#define EVO_8U232AM_PID 0x02FF /* Evolution robotics RCM2 (FT232AM)*/ +#define EVO_HYBRID_PID 0x0302 /* Evolution robotics RCM4 PID (FT232BM)*/ +#define EVO_RCM4_PID 0x0303 /* Evolution robotics RCM4 PID */ + +/* + * MJS Gadgets HD Radio / XM Radio / Sirius Radio interfaces (using VID 0x0403) + */ +#define MJSG_GENERIC_PID 0x9378 +#define MJSG_SR_RADIO_PID 0x9379 +#define MJSG_XM_RADIO_PID 0x937A +#define MJSG_HD_RADIO_PID 0x937C + +/* + * D.O.Tec products (http://www.directout.eu) + */ +#define FTDI_DOTEC_PID 0x9868 + +/* + * Xverve Signalyzer tools (http://www.signalyzer.com/) + */ +#define XVERVE_SIGNALYZER_ST_PID 0xBCA0 +#define XVERVE_SIGNALYZER_SLITE_PID 0xBCA1 +#define XVERVE_SIGNALYZER_SH2_PID 0xBCA2 +#define XVERVE_SIGNALYZER_SH4_PID 0xBCA4 + +/* + * Segway Robotic Mobility Platform USB interface (using VID 0x0403) + * Submitted by John G. Rogers + */ +#define SEGWAY_RMP200_PID 0xe729 + + +/* + * Accesio USB Data Acquisition products (http://www.accesio.com/) + */ +#define ACCESIO_COM4SM_PID 0xD578 + +/* www.sciencescope.co.uk educational dataloggers */ +#define FTDI_SCIENCESCOPE_LOGBOOKML_PID 0xFF18 +#define FTDI_SCIENCESCOPE_LS_LOGBOOK_PID 0xFF1C +#define FTDI_SCIENCESCOPE_HS_LOGBOOK_PID 0xFF1D + +/* + * Milkymist One JTAG/Serial + */ +#define QIHARDWARE_VID 0x20B7 +#define MILKYMISTONE_JTAGSERIAL_PID 0x0713 + +/* + * CTI GmbH RS485 Converter http://www.cti-lean.com/ + */ +/* USB-485-Mini*/ +#define FTDI_CTI_MINI_PID 0xF608 +/* USB-Nano-485*/ +#define FTDI_CTI_NANO_PID 0xF60B + +/* + * ZeitControl cardsystems GmbH rfid-readers http://zeitconrol.de + */ +/* TagTracer MIFARE*/ +#define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID 0xF7C0 + +/* + * Rainforest Automation + */ +/* ZigBee controller */ +#define FTDI_RF_R106 0x8A28 + +/* + * Product: HCP HIT GPRS modem + * Manufacturer: HCP d.o.o. + * ATI command output: Cinterion MC55i + */ +#define FTDI_CINTERION_MC55I_PID 0xA951 diff --git a/hw/usb/quirks-pl2303-ids.h b/hw/usb/quirks-pl2303-ids.h new file mode 100644 index 0000000000..8dbdb46ffe --- /dev/null +++ b/hw/usb/quirks-pl2303-ids.h @@ -0,0 +1,150 @@ +/* + * Prolific PL2303 USB to serial adaptor driver header file + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#define BENQ_VENDOR_ID 0x04a5 +#define BENQ_PRODUCT_ID_S81 0x4027 + +#define PL2303_VENDOR_ID 0x067b +#define PL2303_PRODUCT_ID 0x2303 +#define PL2303_PRODUCT_ID_RSAQ2 0x04bb +#define PL2303_PRODUCT_ID_DCU11 0x1234 +#define PL2303_PRODUCT_ID_PHAROS 0xaaa0 +#define PL2303_PRODUCT_ID_RSAQ3 0xaaa2 +#define PL2303_PRODUCT_ID_ALDIGA 0x0611 +#define PL2303_PRODUCT_ID_MMX 0x0612 +#define PL2303_PRODUCT_ID_GPRS 0x0609 +#define PL2303_PRODUCT_ID_HCR331 0x331a +#define PL2303_PRODUCT_ID_MOTOROLA 0x0307 + +#define ATEN_VENDOR_ID 0x0557 +#define ATEN_VENDOR_ID2 0x0547 +#define ATEN_PRODUCT_ID 0x2008 + +#define IODATA_VENDOR_ID 0x04bb +#define IODATA_PRODUCT_ID 0x0a03 +#define IODATA_PRODUCT_ID_RSAQ5 0x0a0e + +#define ELCOM_VENDOR_ID 0x056e +#define ELCOM_PRODUCT_ID 0x5003 +#define ELCOM_PRODUCT_ID_UCSGT 0x5004 + +#define ITEGNO_VENDOR_ID 0x0eba +#define ITEGNO_PRODUCT_ID 0x1080 +#define ITEGNO_PRODUCT_ID_2080 0x2080 + +#define MA620_VENDOR_ID 0x0df7 +#define MA620_PRODUCT_ID 0x0620 + +#define RATOC_VENDOR_ID 0x0584 +#define RATOC_PRODUCT_ID 0xb000 + +#define TRIPP_VENDOR_ID 0x2478 +#define TRIPP_PRODUCT_ID 0x2008 + +#define RADIOSHACK_VENDOR_ID 0x1453 +#define RADIOSHACK_PRODUCT_ID 0x4026 + +#define DCU10_VENDOR_ID 0x0731 +#define DCU10_PRODUCT_ID 0x0528 + +#define SITECOM_VENDOR_ID 0x6189 +#define SITECOM_PRODUCT_ID 0x2068 + +/* Alcatel OT535/735 USB cable */ +#define ALCATEL_VENDOR_ID 0x11f7 +#define ALCATEL_PRODUCT_ID 0x02df + +/* Samsung I330 phone cradle */ +#define SAMSUNG_VENDOR_ID 0x04e8 +#define SAMSUNG_PRODUCT_ID 0x8001 + +#define SIEMENS_VENDOR_ID 0x11f5 +#define SIEMENS_PRODUCT_ID_SX1 0x0001 +#define SIEMENS_PRODUCT_ID_X65 0x0003 +#define SIEMENS_PRODUCT_ID_X75 0x0004 +#define SIEMENS_PRODUCT_ID_EF81 0x0005 + +#define SYNTECH_VENDOR_ID 0x0745 +#define SYNTECH_PRODUCT_ID 0x0001 + +/* Nokia CA-42 Cable */ +#define NOKIA_CA42_VENDOR_ID 0x078b +#define NOKIA_CA42_PRODUCT_ID 0x1234 + +/* CA-42 CLONE Cable www.ca-42.com chipset: Prolific Technology Inc */ +#define CA_42_CA42_VENDOR_ID 0x10b5 +#define CA_42_CA42_PRODUCT_ID 0xac70 + +#define SAGEM_VENDOR_ID 0x079b +#define SAGEM_PRODUCT_ID 0x0027 + +/* Leadtek GPS 9531 (ID 0413:2101) */ +#define LEADTEK_VENDOR_ID 0x0413 +#define LEADTEK_9531_PRODUCT_ID 0x2101 + +/* USB GSM cable from Speed Dragon Multimedia, Ltd */ +#define SPEEDDRAGON_VENDOR_ID 0x0e55 +#define SPEEDDRAGON_PRODUCT_ID 0x110b + +/* DATAPILOT Universal-2 Phone Cable */ +#define DATAPILOT_U2_VENDOR_ID 0x0731 +#define DATAPILOT_U2_PRODUCT_ID 0x2003 + +/* Belkin "F5U257" Serial Adapter */ +#define BELKIN_VENDOR_ID 0x050d +#define BELKIN_PRODUCT_ID 0x0257 + +/* Alcor Micro Corp. USB 2.0 TO RS-232 */ +#define ALCOR_VENDOR_ID 0x058F +#define ALCOR_PRODUCT_ID 0x9720 + +/* Willcom WS002IN Data Driver (by NetIndex Inc.) */ +#define WS002IN_VENDOR_ID 0x11f6 +#define WS002IN_PRODUCT_ID 0x2001 + +/* Corega CG-USBRS232R Serial Adapter */ +#define COREGA_VENDOR_ID 0x07aa +#define COREGA_PRODUCT_ID 0x002a + +/* Y.C. Cable U.S.A., Inc - USB to RS-232 */ +#define YCCABLE_VENDOR_ID 0x05ad +#define YCCABLE_PRODUCT_ID 0x0fba + +/* "Superial" USB - Serial */ +#define SUPERIAL_VENDOR_ID 0x5372 +#define SUPERIAL_PRODUCT_ID 0x2303 + +/* Hewlett-Packard LD220-HP POS Pole Display */ +#define HP_VENDOR_ID 0x03f0 +#define HP_LD220_PRODUCT_ID 0x3524 + +/* Cressi Edy (diving computer) PC interface */ +#define CRESSI_VENDOR_ID 0x04b8 +#define CRESSI_EDY_PRODUCT_ID 0x0521 + +/* Zeagle dive computer interface */ +#define ZEAGLE_VENDOR_ID 0x04b8 +#define ZEAGLE_N2ITION3_PRODUCT_ID 0x0522 + +/* Sony, USB data cable for CMD-Jxx mobile phones */ +#define SONY_VENDOR_ID 0x054c +#define SONY_QN3USB_PRODUCT_ID 0x0437 + +/* Sanwa KB-USB2 multimeter cable (ID: 11ad:0001) */ +#define SANWA_VENDOR_ID 0x11ad +#define SANWA_PRODUCT_ID 0x0001 + +/* ADLINK ND-6530 RS232,RS485 and RS422 adapter */ +#define ADLINK_VENDOR_ID 0x0b63 +#define ADLINK_ND6530_PRODUCT_ID 0x6530 + +/* SMART USB Serial Adapter */ +#define SMART_VENDOR_ID 0x0b8c +#define SMART_PRODUCT_ID 0x2303 diff --git a/hw/usb/quirks.c b/hw/usb/quirks.c new file mode 100644 index 0000000000..a761a96032 --- /dev/null +++ b/hw/usb/quirks.c @@ -0,0 +1,53 @@ +/* + * USB quirk handling + * + * Copyright (c) 2012 Red Hat, Inc. + * + * Red Hat Authors: + * Hans de Goede <hdegoede@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "quirks.h" +#include "hw/usb.h" + +static bool usb_id_match(const struct usb_device_id *ids, + uint16_t vendor_id, uint16_t product_id, + uint8_t interface_class, uint8_t interface_subclass, + uint8_t interface_protocol) { + int i; + + for (i = 0; ids[i].vendor_id != -1; i++) { + if (ids[i].vendor_id == vendor_id && + ids[i].product_id == product_id && + (ids[i].interface_class == -1 || + (ids[i].interface_class == interface_class && + ids[i].interface_subclass == interface_subclass && + ids[i].interface_protocol == interface_protocol))) { + return true; + } + } + return false; +} + +int usb_get_quirks(uint16_t vendor_id, uint16_t product_id, + uint8_t interface_class, uint8_t interface_subclass, + uint8_t interface_protocol) +{ + int quirks = 0; + + if (usb_id_match(usbredir_raw_serial_ids, vendor_id, product_id, + interface_class, interface_subclass, interface_protocol)) { + quirks |= USB_QUIRK_BUFFER_BULK_IN; + } + if (usb_id_match(usbredir_ftdi_serial_ids, vendor_id, product_id, + interface_class, interface_subclass, interface_protocol)) { + quirks |= USB_QUIRK_BUFFER_BULK_IN | USB_QUIRK_IS_FTDI; + } + + return quirks; +} diff --git a/hw/usb/quirks.h b/hw/usb/quirks.h new file mode 100644 index 0000000000..8dc6065527 --- /dev/null +++ b/hw/usb/quirks.h @@ -0,0 +1,910 @@ +/* + * USB quirk handling + * + * Copyright (c) 2012 Red Hat, Inc. + * + * Red Hat Authors: + * Hans de Goede <hdegoede@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/* 1 on 1 copy of linux/drivers/usb/serial/ftdi_sio_ids.h */ +#include "quirks-ftdi-ids.h" +/* 1 on 1 copy of linux/drivers/usb/serial/pl2303.h */ +#include "quirks-pl2303-ids.h" + +struct usb_device_id { + int vendor_id; + int product_id; + int interface_class; + int interface_subclass; + int interface_protocol; +}; + +#define USB_DEVICE(vendor, product) \ + .vendor_id = vendor, .product_id = product, .interface_class = -1, + +#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, iclass, isubclass, iproto) \ + .vendor_id = vend, .product_id = prod, .interface_class = iclass, \ + .interface_subclass = isubclass, .interface_protocol = iproto + +static const struct usb_device_id usbredir_raw_serial_ids[] = { + /* + * Silicon Laboratories CP210x USB to RS232 serial adapter ids + * copied from linux/drivers/usb/serial/cp210x.c + * + * Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk) + */ + { USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */ + { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */ + { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */ + { USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */ + { USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */ + { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ + { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */ + { USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */ + { USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */ + { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ + { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */ + { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */ + { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ + { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ + { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ + { USB_DEVICE(0x10C4, 0x0F91) }, /* Vstabi */ + { USB_DEVICE(0x10C4, 0x1101) }, /* Arkham Technology DS101 Bus Monitor */ + { USB_DEVICE(0x10C4, 0x1601) }, /* Arkham Technology DS101 Adapter */ + { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */ + { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ + { USB_DEVICE(0x10C4, 0x8044) }, /* Cygnal Debug Adapter */ + { USB_DEVICE(0x10C4, 0x804E) }, /* Software Bisque Paramount ME build-in converter */ + { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */ + { USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */ + { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */ + { USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */ + { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ + { USB_DEVICE(0x10C4, 0x80C4) }, /* Cygnal Integrated Products, Inc., Optris infrared thermometer */ + { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ + { USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */ + { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ + { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */ + { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ + { USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */ + { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */ + { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */ + { USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */ + { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ + { USB_DEVICE(0x10C4, 0x815F) }, /* Timewave HamLinkUSB */ + { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */ + { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */ + { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ + { USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */ + { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */ + { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */ + { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ + { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */ + { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */ + { USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */ + { USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */ + { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ + { USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */ + { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */ + { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */ + { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */ + { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ + { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */ + { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ + { USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */ + { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */ + { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */ + { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ + { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ + { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */ + { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */ + { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */ + { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */ + { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */ + { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ + { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ + { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */ + { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */ + { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */ + { USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */ + { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ + { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */ + { USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */ + { USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */ + { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ + { USB_DEVICE(0x166A, 0x0304) }, /* Clipsal 5000CT2 C-Bus Black and White Touchscreen */ + { USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */ + { USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */ + { USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */ + { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ + { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */ + { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */ + { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */ + { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */ + { USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */ + { USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */ + { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ + { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ + { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ + { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ + { USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */ + { USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */ + { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */ + { USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */ + { USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */ + { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ + + /* + * Prolific pl2303 USB to RS232 serial adapter ids + * copied from linux/drivers/usb/serial/pl2303.c + * + * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2003 IBM Corp. + */ + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) }, + { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, + { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, + { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, + { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, + { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, + { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) }, + { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, + { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) }, + { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, + { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, + { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, + { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) }, + { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, + { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, + { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, + { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, + { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */ + { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, + { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, + { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, + { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) }, + { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, + { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, + { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, + { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, + { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, + { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, + { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) }, + { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, + { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, + { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, + { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) }, + { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, + { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, + { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, + { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, + + { USB_DEVICE(-1, -1) } /* Terminating Entry */ +}; + +static const struct usb_device_id usbredir_ftdi_serial_ids[] = { + /* + * FTDI USB to RS232 serial adapter ids + * copied from linux/drivers/usb/serial/ftdi_sio.c + * + * Copyright (C) 2009 - 2010 + * Johan Hovold (jhovold@gmail.com) + * Copyright (C) 1999 - 2001 + * Greg Kroah-Hartman (greg@kroah.com) + * Bill Ryder (bryder@sgi.com) + * Copyright (C) 2002 + * Kuba Ober (kuba@mareimbrium.org) + */ + { USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_USINT_CAT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_USINT_WKEY_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_USINT_RS232_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IPLUS2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DMX4ALL) }, + { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_232RL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_232H_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FTX_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_SNIFFER_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) }, + { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, + { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, + { USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_633_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_631_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_635_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_URBAN_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_URBAN_1_PID) }, + { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) }, + { USB_DEVICE(FTDI_VID, FTDI_VARDAAN_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0103_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0104_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0105_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0106_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0107_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0108_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0109_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0110_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0111_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0112_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0113_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0114_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0115_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0116_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0117_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0118_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0119_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0120_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0121_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0122_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0123_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0124_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0125_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0126_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0127_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0128_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0129_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0130_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0131_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0132_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0133_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0134_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0135_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0136_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0137_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0138_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0139_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0140_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0141_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0142_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0143_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0144_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0145_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0146_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0147_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0148_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0149_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0150_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0151_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0152_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0153_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0154_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0155_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0156_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0157_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0158_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0159_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0160_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0161_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0162_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0163_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0164_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0165_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0166_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0167_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0168_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0169_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0170_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0171_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0172_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0173_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0174_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0175_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0176_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0177_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0178_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0179_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0180_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0181_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0182_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0183_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0184_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0185_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0186_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0187_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0188_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0189_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0190_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0191_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0192_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0193_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0194_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0195_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0196_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0197_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0198_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0199_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AD_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BD_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CD_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DD_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01ED_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FD_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FF_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_USBX_707_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2104_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2106_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_5_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_6_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_7_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_8_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_5_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_6_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_7_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_8_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_5_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_4_PID) }, + { USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) }, + { USB_DEVICE(OCT_VID, OCT_US101_PID) }, + { USB_DEVICE(OCT_VID, OCT_DK201_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) }, + { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_1) }, + { USB_DEVICE(FTDI_VID, PROTEGO_R2X0) }, + { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) }, + { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E808_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E809_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80A_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80B_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80D_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80E_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80F_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E888_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E889_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88A_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88B_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88D_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88E_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UR100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PYRAMID_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_US485_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PICPRO_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PCMCIA_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PK1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_RS232MON_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_APP70_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID) }, + /* + * ELV devices: + */ + { USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS550_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_EC3000_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS888_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_TWS550_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FEM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UTP8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS444PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1010PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_HS485_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UMS100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_TFD128_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FM3RX_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS777_PID) }, + { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, + { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSLOAD_N_GO_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU64_4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSPRIME8_5_PID) }, + { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, + { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) }, + { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) }, + { USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) }, + { USB_DEVICE(FALCOM_VID, FALCOM_SAMBA_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) }, + { USB_DEVICE(TTI_VID, TTI_QL355P_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) }, + { USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) }, + { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USOPTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USPTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_2_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR2_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_485USB9F_2W_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_485USB9F_4W_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_232USB9M_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_485USBTB_2W_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_485USBTB_4W_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_TTL5USB9M_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_TTL3USB9M_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_ZZ_PROG1_USB_PID) }, + { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) }, + { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_3_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_1_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_2_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_3_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_4_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) }, + { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_KW_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_YS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_IC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_DB9_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_RS232_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y9_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_VCP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_D2XX_PID) }, + { USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) }, + { USB_DEVICE(EVOLUTION_VID, EVO_HYBRID_PID) }, + { USB_DEVICE(EVOLUTION_VID, EVO_RCM4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16IC_PID) }, + { USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) }, + { USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) }, + { USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TTUSB_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ECLO_COM_1WIRE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NZR_SEM_USB_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C2_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2D_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VT_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VR_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVT_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVR_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVT_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVR_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) }, + { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) }, + { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_SPECTRA_SCU_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID) }, + { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) }, + { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) }, + { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID) }, + { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID) }, + { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID) }, + { USB_DEVICE(FTDI_VID, LMI_LM3S_DEVEL_BOARD_PID) }, + { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID) }, + { USB_DEVICE(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID) }, + { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, + { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) }, + + /* Papouch devices based on FTDI chip */ + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_2_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_2_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_2_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485S_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485C_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_LEC_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB232_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_IRAMP_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK5_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO8x8_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x2_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO10x1_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO30x3_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO60x3_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x16_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO3x32_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK6_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_UPSUSB_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_MU_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SIMUKEY_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AD4USB_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMUX_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMSR_PID) }, + + { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DGQG_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) }, + { USB_DEVICE(ALTI2_VID, ALTI2_N3_PID) }, + { USB_DEVICE(FTDI_VID, DIEBOLD_BCS_SE923_PID) }, + { USB_DEVICE(ATMEL_VID, STK541_PID) }, + { USB_DEVICE(DE_VID, STB_PID) }, + { USB_DEVICE(DE_VID, WHT_PID) }, + { USB_DEVICE(ADI_VID, ADI_GNICE_PID) }, + { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID) }, + { USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID, + 0xff, 0xff, 0x00) }, + { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, + { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID) }, + { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, + { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, + { USB_DEVICE(FTDI_VID, PI_C865_PID) }, + { USB_DEVICE(FTDI_VID, PI_C857_PID) }, + { USB_DEVICE(PI_VID, PI_C866_PID) }, + { USB_DEVICE(PI_VID, PI_C663_PID) }, + { USB_DEVICE(PI_VID, PI_C725_PID) }, + { USB_DEVICE(PI_VID, PI_E517_PID) }, + { USB_DEVICE(PI_VID, PI_C863_PID) }, + { USB_DEVICE(PI_VID, PI_E861_PID) }, + { USB_DEVICE(PI_VID, PI_C867_PID) }, + { USB_DEVICE(PI_VID, PI_E609_PID) }, + { USB_DEVICE(PI_VID, PI_E709_PID) }, + { USB_DEVICE(PI_VID, PI_100F_PID) }, + { USB_DEVICE(PI_VID, PI_1011_PID) }, + { USB_DEVICE(PI_VID, PI_1012_PID) }, + { USB_DEVICE(PI_VID, PI_1013_PID) }, + { USB_DEVICE(PI_VID, PI_1014_PID) }, + { USB_DEVICE(PI_VID, PI_1015_PID) }, + { USB_DEVICE(PI_VID, PI_1016_PID) }, + { USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) }, + { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, + { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID) }, + { USB_DEVICE(FTDI_VID, TI_XDS100V2_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) }, + { USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) }, + { USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) }, + { USB_DEVICE(FTDI_VID, MJSG_HD_RADIO_PID) }, + { USB_DEVICE(FTDI_VID, MJSG_XM_RADIO_PID) }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_ST_PID) }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SLITE_PID) }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH2_PID) }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID) }, + { USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) }, + { USB_DEVICE(FTDI_VID, ACCESIO_COM4SM_PID) }, + { USB_DEVICE(IONICS_VID, IONICS_PLUGCOMPUTER_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_24_MASTER_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_PC_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_USB_DMX_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MIDI_TIMECODE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MINI_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MAXI_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MEDIA_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, + { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID) }, + { USB_DEVICE(ST_VID, ST_STMCLT1030_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_RF_R106) }, + { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) }, + + { USB_DEVICE(-1, -1) } /* Terminating Entry */ +}; + +#undef USB_DEVICE +#undef USB_DEVICE_AND_INTERFACE_INFO diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 10b4fbb3a7..f1bf84c987 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -1,7 +1,7 @@ /* * USB redirector usb-guest * - * Copyright (c) 2011 Red Hat, Inc. + * Copyright (c) 2011-2012 Red Hat, Inc. * * Red Hat Authors: * Hans de Goede <hdegoede@redhat.com> @@ -26,9 +26,11 @@ */ #include "qemu-common.h" -#include "qemu-timer.h" -#include "monitor.h" -#include "sysemu.h" +#include "qemu/timer.h" +#include "monitor/monitor.h" +#include "sysemu/sysemu.h" +#include "qemu/iov.h" +#include "char/char.h" #include <dirent.h> #include <sys/ioctl.h> @@ -42,31 +44,54 @@ #define NO_INTERFACE_INFO 255 /* Valid interface_count always <= 32 */ #define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f)) #define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f)) +#define USBEP2I(usb_ep) (((usb_ep)->pid == USB_TOKEN_IN) ? \ + ((usb_ep)->nr | 0x10) : ((usb_ep)->nr)) +#define I2USBEP(d, i) (usb_ep_get(&(d)->dev, \ + ((i) & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, \ + (i) & 0x0f)) -typedef struct AsyncURB AsyncURB; typedef struct USBRedirDevice USBRedirDevice; -/* Struct to hold buffered packets (iso or int input packets) */ +/* Struct to hold buffered packets */ struct buf_packet { uint8_t *data; - int len; - int status; + void *free_on_destroy; + uint16_t len; + uint16_t offset; + uint8_t status; QTAILQ_ENTRY(buf_packet)next; }; struct endp_data { + USBRedirDevice *dev; uint8_t type; uint8_t interval; uint8_t interface; /* bInterfaceNumber this ep belongs to */ + uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */ uint8_t iso_started; uint8_t iso_error; /* For reporting iso errors to the HC */ uint8_t interrupt_started; uint8_t interrupt_error; + uint8_t bulk_receiving_enabled; + uint8_t bulk_receiving_started; uint8_t bufpq_prefilled; uint8_t bufpq_dropping_packets; QTAILQ_HEAD(, buf_packet) bufpq; - int bufpq_size; - int bufpq_target_size; + int32_t bufpq_size; + int32_t bufpq_target_size; + USBPacket *pending_async_packet; +}; + +struct PacketIdQueueEntry { + uint64_t id; + QTAILQ_ENTRY(PacketIdQueueEntry)next; +}; + +struct PacketIdQueue { + USBRedirDevice *dev; + const char *name; + QTAILQ_HEAD(, PacketIdQueueEntry) head; + int size; }; struct USBRedirDevice { @@ -79,33 +104,22 @@ struct USBRedirDevice { /* Data passed from chardev the fd_read cb to the usbredirparser read cb */ const uint8_t *read_buf; int read_buf_size; - /* For async handling of open/close */ - QEMUBH *open_close_bh; + /* For async handling of close */ + QEMUBH *chardev_close_bh; /* To delay the usb attach in case of quick chardev close + open */ QEMUTimer *attach_timer; int64_t next_attach_time; struct usbredirparser *parser; struct endp_data endpoint[MAX_ENDPOINTS]; - uint32_t packet_id; - QTAILQ_HEAD(, AsyncURB) asyncq; + struct PacketIdQueue cancelled; + struct PacketIdQueue already_in_flight; + void (*buffered_bulk_in_complete)(USBRedirDevice *, USBPacket *, uint8_t); /* Data for device filtering */ struct usb_redir_device_connect_header device_info; struct usb_redir_interface_info_header interface_info; struct usbredirfilter_rule *filter_rules; int filter_rules_count; -}; - -struct AsyncURB { - USBRedirDevice *dev; - USBPacket *packet; - uint32_t packet_id; - int get; - union { - struct usb_redir_control_packet_header control_packet; - struct usb_redir_bulk_packet_header bulk_packet; - struct usb_redir_interrupt_packet_header interrupt_packet; - }; - QTAILQ_ENTRY(AsyncURB)next; + int compatible_speedmask; }; static void usbredir_hello(void *priv, struct usb_redir_hello_header *h); @@ -116,32 +130,39 @@ static void usbredir_interface_info(void *priv, struct usb_redir_interface_info_header *interface_info); static void usbredir_ep_info(void *priv, struct usb_redir_ep_info_header *ep_info); -static void usbredir_configuration_status(void *priv, uint32_t id, +static void usbredir_configuration_status(void *priv, uint64_t id, struct usb_redir_configuration_status_header *configuration_status); -static void usbredir_alt_setting_status(void *priv, uint32_t id, +static void usbredir_alt_setting_status(void *priv, uint64_t id, struct usb_redir_alt_setting_status_header *alt_setting_status); -static void usbredir_iso_stream_status(void *priv, uint32_t id, +static void usbredir_iso_stream_status(void *priv, uint64_t id, struct usb_redir_iso_stream_status_header *iso_stream_status); -static void usbredir_interrupt_receiving_status(void *priv, uint32_t id, +static void usbredir_interrupt_receiving_status(void *priv, uint64_t id, struct usb_redir_interrupt_receiving_status_header *interrupt_receiving_status); -static void usbredir_bulk_streams_status(void *priv, uint32_t id, +static void usbredir_bulk_streams_status(void *priv, uint64_t id, struct usb_redir_bulk_streams_status_header *bulk_streams_status); -static void usbredir_control_packet(void *priv, uint32_t id, +static void usbredir_bulk_receiving_status(void *priv, uint64_t id, + struct usb_redir_bulk_receiving_status_header *bulk_receiving_status); +static void usbredir_control_packet(void *priv, uint64_t id, struct usb_redir_control_packet_header *control_packet, uint8_t *data, int data_len); -static void usbredir_bulk_packet(void *priv, uint32_t id, +static void usbredir_bulk_packet(void *priv, uint64_t id, struct usb_redir_bulk_packet_header *bulk_packet, uint8_t *data, int data_len); -static void usbredir_iso_packet(void *priv, uint32_t id, +static void usbredir_iso_packet(void *priv, uint64_t id, struct usb_redir_iso_packet_header *iso_packet, uint8_t *data, int data_len); -static void usbredir_interrupt_packet(void *priv, uint32_t id, +static void usbredir_interrupt_packet(void *priv, uint64_t id, struct usb_redir_interrupt_packet_header *interrupt_header, uint8_t *data, int data_len); +static void usbredir_buffered_bulk_packet(void *priv, uint64_t id, + struct usb_redir_buffered_bulk_packet_header *buffered_bulk_packet, + uint8_t *data, int data_len); -static int usbredir_handle_status(USBRedirDevice *dev, - int status, int actual_len); +static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p, + int status); + +#define VERSION "qemu usb-redir guest " QEMU_VERSION /* * Logging stuff @@ -241,66 +262,160 @@ static int usbredir_write(void *priv, uint8_t *data, int count) return 0; } + /* Don't send new data to the chardev until our state is fully synced */ + if (!runstate_check(RUN_STATE_RUNNING)) { + return 0; + } + return qemu_chr_fe_write(dev->cs, data, count); } /* - * Async and buffered packets helpers + * Cancelled and buffered packets helpers */ -static AsyncURB *async_alloc(USBRedirDevice *dev, USBPacket *p) +static void packet_id_queue_init(struct PacketIdQueue *q, + USBRedirDevice *dev, const char *name) +{ + q->dev = dev; + q->name = name; + QTAILQ_INIT(&q->head); + q->size = 0; +} + +static void packet_id_queue_add(struct PacketIdQueue *q, uint64_t id) { - AsyncURB *aurb = (AsyncURB *) g_malloc0(sizeof(AsyncURB)); - aurb->dev = dev; - aurb->packet = p; - aurb->packet_id = dev->packet_id; - QTAILQ_INSERT_TAIL(&dev->asyncq, aurb, next); - dev->packet_id++; + USBRedirDevice *dev = q->dev; + struct PacketIdQueueEntry *e; - return aurb; + DPRINTF("adding packet id %"PRIu64" to %s queue\n", id, q->name); + + e = g_malloc0(sizeof(struct PacketIdQueueEntry)); + e->id = id; + QTAILQ_INSERT_TAIL(&q->head, e, next); + q->size++; } -static void async_free(USBRedirDevice *dev, AsyncURB *aurb) +static int packet_id_queue_remove(struct PacketIdQueue *q, uint64_t id) { - QTAILQ_REMOVE(&dev->asyncq, aurb, next); - g_free(aurb); + USBRedirDevice *dev = q->dev; + struct PacketIdQueueEntry *e; + + QTAILQ_FOREACH(e, &q->head, next) { + if (e->id == id) { + DPRINTF("removing packet id %"PRIu64" from %s queue\n", + id, q->name); + QTAILQ_REMOVE(&q->head, e, next); + q->size--; + g_free(e); + return 1; + } + } + return 0; } -static AsyncURB *async_find(USBRedirDevice *dev, uint32_t packet_id) +static void packet_id_queue_empty(struct PacketIdQueue *q) { - AsyncURB *aurb; + USBRedirDevice *dev = q->dev; + struct PacketIdQueueEntry *e, *next_e; - QTAILQ_FOREACH(aurb, &dev->asyncq, next) { - if (aurb->packet_id == packet_id) { - return aurb; - } + DPRINTF("removing %d packet-ids from %s queue\n", q->size, q->name); + + QTAILQ_FOREACH_SAFE(e, &q->head, next, next_e) { + QTAILQ_REMOVE(&q->head, e, next); + g_free(e); } - DPRINTF("could not find async urb for packet_id %u\n", packet_id); - return NULL; + q->size = 0; } static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) { USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); - AsyncURB *aurb; + int i = USBEP2I(p->ep); + + if (p->combined) { + usb_combined_packet_cancel(udev, p); + return; + } + + if (dev->endpoint[i].pending_async_packet) { + assert(dev->endpoint[i].pending_async_packet == p); + dev->endpoint[i].pending_async_packet = NULL; + return; + } + + packet_id_queue_add(&dev->cancelled, p->id); + usbredirparser_send_cancel_data_packet(dev->parser, p->id); + usbredirparser_do_write(dev->parser); +} + +static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) +{ + if (!dev->dev.attached) { + return 1; /* Treat everything as cancelled after a disconnect */ + } + return packet_id_queue_remove(&dev->cancelled, id); +} - QTAILQ_FOREACH(aurb, &dev->asyncq, next) { - if (p != aurb->packet) { +static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev, + struct USBEndpoint *ep) +{ + static USBPacket *p; + + /* async handled packets for bulk receiving eps do not count as inflight */ + if (dev->endpoint[USBEP2I(ep)].bulk_receiving_started) { + return; + } + + QTAILQ_FOREACH(p, &ep->queue, queue) { + /* Skip combined packets, except for the first */ + if (p->combined && p != p->combined->first) { continue; } + if (p->state == USB_PACKET_ASYNC) { + packet_id_queue_add(&dev->already_in_flight, p->id); + } + } +} - DPRINTF("async cancel id %u\n", aurb->packet_id); - usbredirparser_send_cancel_data_packet(dev->parser, aurb->packet_id); - usbredirparser_do_write(dev->parser); +static void usbredir_fill_already_in_flight(USBRedirDevice *dev) +{ + int ep; + struct USBDevice *udev = &dev->dev; - /* Mark it as dead */ - aurb->packet = NULL; - break; + usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_ctl); + + for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { + usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_in[ep]); + usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_out[ep]); + } +} + +static int usbredir_already_in_flight(USBRedirDevice *dev, uint64_t id) +{ + return packet_id_queue_remove(&dev->already_in_flight, id); +} + +static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, + uint8_t ep, uint64_t id) +{ + USBPacket *p; + + if (usbredir_is_cancelled(dev, id)) { + return NULL; + } + + p = usb_ep_find_packet_by_id(&dev->dev, + (ep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT, + ep & 0x0f, id); + if (p == NULL) { + ERROR("could not find packet with id %"PRIu64"\n", id); } + return p; } -static void bufp_alloc(USBRedirDevice *dev, - uint8_t *data, int len, int status, uint8_t ep) +static void bufp_alloc(USBRedirDevice *dev, uint8_t *data, uint16_t len, + uint8_t status, uint8_t ep, void *free_on_destroy) { struct buf_packet *bufp; @@ -324,7 +439,9 @@ static void bufp_alloc(USBRedirDevice *dev, bufp = g_malloc(sizeof(struct buf_packet)); bufp->data = data; bufp->len = len; + bufp->offset = 0; bufp->status = status; + bufp->free_on_destroy = free_on_destroy; QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next); dev->endpoint[EP2I(ep)].bufpq_size++; } @@ -334,7 +451,7 @@ static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp, { QTAILQ_REMOVE(&dev->endpoint[EP2I(ep)].bufpq, bufp, next); dev->endpoint[EP2I(ep)].bufpq_size--; - free(bufp->data); + free(bufp->free_on_destroy); g_free(bufp); } @@ -360,7 +477,7 @@ static void usbredir_handle_reset(USBDevice *udev) usbredirparser_do_write(dev->parser); } -static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, +static void usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, uint8_t ep) { int status, len; @@ -417,7 +534,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, !dev->endpoint[EP2I(ep)].bufpq_prefilled) { if (dev->endpoint[EP2I(ep)].bufpq_size < dev->endpoint[EP2I(ep)].bufpq_target_size) { - return usbredir_handle_status(dev, 0, 0); + return; } dev->endpoint[EP2I(ep)].bufpq_prefilled = 1; } @@ -431,27 +548,23 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, /* Check iso_error for stream errors, otherwise its an underrun */ status = dev->endpoint[EP2I(ep)].iso_error; dev->endpoint[EP2I(ep)].iso_error = 0; - return status ? USB_RET_IOERROR : 0; + p->status = status ? USB_RET_IOERROR : USB_RET_SUCCESS; + return; } DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep, isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size); status = isop->status; - if (status != usb_redir_success) { - bufp_free(dev, isop, ep); - return USB_RET_IOERROR; - } - len = isop->len; if (len > p->iov.size) { ERROR("received iso data is larger then packet ep %02X (%d > %d)\n", ep, len, (int)p->iov.size); - bufp_free(dev, isop, ep); - return USB_RET_BABBLE; + len = p->iov.size; + status = usb_redir_babble; } usb_packet_copy(p, isop->data, len); bufp_free(dev, isop, ep); - return len; + usbredir_handle_status(dev, p, status); } else { /* If the stream was not started because of a pending error don't send the packet to the usb-host */ @@ -471,7 +584,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, dev->endpoint[EP2I(ep)].iso_error = 0; DPRINTF2("iso-token-out ep %02X status %d len %zd\n", ep, status, p->iov.size); - return usbredir_handle_status(dev, status, p->iov.size); + usbredir_handle_status(dev, p, status); } } @@ -489,108 +602,265 @@ static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep) usbredir_free_bufpq(dev, ep); } -static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, +/* + * The usb-host may poll the endpoint faster then our guest, resulting in lots + * of smaller bulkp-s. The below buffered_bulk_in_complete* functions combine + * data from multiple bulkp-s into a single packet, avoiding bufpq overflows. + */ +static void usbredir_buffered_bulk_add_data_to_packet(USBRedirDevice *dev, + struct buf_packet *bulkp, int count, USBPacket *p, uint8_t ep) +{ + usb_packet_copy(p, bulkp->data + bulkp->offset, count); + bulkp->offset += count; + if (bulkp->offset == bulkp->len) { + /* Store status in the last packet with data from this bulkp */ + usbredir_handle_status(dev, p, bulkp->status); + bufp_free(dev, bulkp, ep); + } +} + +static void usbredir_buffered_bulk_in_complete_raw(USBRedirDevice *dev, + USBPacket *p, uint8_t ep) +{ + struct buf_packet *bulkp; + int count; + + while ((bulkp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq)) && + p->actual_length < p->iov.size && p->status == USB_RET_SUCCESS) { + count = bulkp->len - bulkp->offset; + if (count > (p->iov.size - p->actual_length)) { + count = p->iov.size - p->actual_length; + } + usbredir_buffered_bulk_add_data_to_packet(dev, bulkp, count, p, ep); + } +} + +static void usbredir_buffered_bulk_in_complete_ftdi(USBRedirDevice *dev, + USBPacket *p, uint8_t ep) +{ + const int maxp = dev->endpoint[EP2I(ep)].max_packet_size; + uint8_t header[2] = { 0, 0 }; + struct buf_packet *bulkp; + int count; + + while ((bulkp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq)) && + p->actual_length < p->iov.size && p->status == USB_RET_SUCCESS) { + if (bulkp->len < 2) { + WARNING("malformed ftdi bulk in packet\n"); + bufp_free(dev, bulkp, ep); + continue; + } + + if ((p->actual_length % maxp) == 0) { + usb_packet_copy(p, bulkp->data, 2); + memcpy(header, bulkp->data, 2); + } else { + if (bulkp->data[0] != header[0] || bulkp->data[1] != header[1]) { + break; /* Different header, add to next packet */ + } + } + + if (bulkp->offset == 0) { + bulkp->offset = 2; /* Skip header */ + } + count = bulkp->len - bulkp->offset; + /* Must repeat the header at maxp interval */ + if (count > (maxp - (p->actual_length % maxp))) { + count = maxp - (p->actual_length % maxp); + } + usbredir_buffered_bulk_add_data_to_packet(dev, bulkp, count, p, ep); + } +} + +static void usbredir_buffered_bulk_in_complete(USBRedirDevice *dev, + USBPacket *p, uint8_t ep) +{ + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ + dev->buffered_bulk_in_complete(dev, p, ep); + DPRINTF("bulk-token-in ep %02X status %d len %d id %"PRIu64"\n", + ep, p->status, p->actual_length, p->id); +} + +static void usbredir_handle_buffered_bulk_in_data(USBRedirDevice *dev, + USBPacket *p, uint8_t ep) +{ + /* Input bulk endpoint, buffered packet input */ + if (!dev->endpoint[EP2I(ep)].bulk_receiving_started) { + int bpt; + struct usb_redir_start_bulk_receiving_header start = { + .endpoint = ep, + .stream_id = 0, + .no_transfers = 5, + }; + /* Round bytes_per_transfer up to a multiple of max_packet_size */ + bpt = 512 + dev->endpoint[EP2I(ep)].max_packet_size - 1; + bpt /= dev->endpoint[EP2I(ep)].max_packet_size; + bpt *= dev->endpoint[EP2I(ep)].max_packet_size; + start.bytes_per_transfer = bpt; + /* No id, we look at the ep when receiving a status back */ + usbredirparser_send_start_bulk_receiving(dev->parser, 0, &start); + usbredirparser_do_write(dev->parser); + DPRINTF("bulk receiving started bytes/transfer %u count %d ep %02X\n", + start.bytes_per_transfer, start.no_transfers, ep); + dev->endpoint[EP2I(ep)].bulk_receiving_started = 1; + /* We don't really want to drop bulk packets ever, but + having some upper limit to how much we buffer is good. */ + dev->endpoint[EP2I(ep)].bufpq_target_size = 5000; + dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; + } + + if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) { + DPRINTF("bulk-token-in ep %02X, no bulkp\n", ep); + assert(dev->endpoint[EP2I(ep)].pending_async_packet == NULL); + dev->endpoint[EP2I(ep)].pending_async_packet = p; + p->status = USB_RET_ASYNC; + return; + } + usbredir_buffered_bulk_in_complete(dev, p, ep); +} + +static void usbredir_stop_bulk_receiving(USBRedirDevice *dev, uint8_t ep) +{ + struct usb_redir_stop_bulk_receiving_header stop_bulk = { + .endpoint = ep, + .stream_id = 0, + }; + if (dev->endpoint[EP2I(ep)].bulk_receiving_started) { + usbredirparser_send_stop_bulk_receiving(dev->parser, 0, &stop_bulk); + DPRINTF("bulk receiving stopped ep %02X\n", ep); + dev->endpoint[EP2I(ep)].bulk_receiving_started = 0; + } + usbredir_free_bufpq(dev, ep); +} + +static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, uint8_t ep) { - AsyncURB *aurb = async_alloc(dev, p); struct usb_redir_bulk_packet_header bulk_packet; + size_t size = (p->combined) ? p->combined->iov.size : p->iov.size; + const int maxp = dev->endpoint[EP2I(ep)].max_packet_size; + + if (usbredir_already_in_flight(dev, p->id)) { + p->status = USB_RET_ASYNC; + return; + } + + if (dev->endpoint[EP2I(ep)].bulk_receiving_enabled) { + if (size != 0 && (size % maxp) == 0) { + usbredir_handle_buffered_bulk_in_data(dev, p, ep); + return; + } + WARNING("bulk recv invalid size %zd ep %02x, disabling\n", size, ep); + assert(dev->endpoint[EP2I(ep)].pending_async_packet == NULL); + usbredir_stop_bulk_receiving(dev, ep); + dev->endpoint[EP2I(ep)].bulk_receiving_enabled = 0; + } - DPRINTF("bulk-out ep %02X len %zd id %u\n", ep, - p->iov.size, aurb->packet_id); + DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, size, p->id); bulk_packet.endpoint = ep; - bulk_packet.length = p->iov.size; + bulk_packet.length = size; bulk_packet.stream_id = 0; - aurb->bulk_packet = bulk_packet; + bulk_packet.length_high = size >> 16; + assert(bulk_packet.length_high == 0 || + usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_32bits_bulk_length)); if (ep & USB_DIR_IN) { - usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id, + usbredirparser_send_bulk_packet(dev->parser, p->id, &bulk_packet, NULL, 0); } else { - uint8_t buf[p->iov.size]; - usb_packet_copy(p, buf, p->iov.size); - usbredir_log_data(dev, "bulk data out:", buf, p->iov.size); - usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id, - &bulk_packet, buf, p->iov.size); + uint8_t buf[size]; + if (p->combined) { + iov_to_buf(p->combined->iov.iov, p->combined->iov.niov, + 0, buf, size); + } else { + usb_packet_copy(p, buf, size); + } + usbredir_log_data(dev, "bulk data out:", buf, size); + usbredirparser_send_bulk_packet(dev->parser, p->id, + &bulk_packet, buf, size); } usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } -static int usbredir_handle_interrupt_data(USBRedirDevice *dev, - USBPacket *p, uint8_t ep) +static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev, + USBPacket *p, uint8_t ep) { - if (ep & USB_DIR_IN) { - /* Input interrupt endpoint, buffered packet input */ - struct buf_packet *intp; - int status, len; - - if (!dev->endpoint[EP2I(ep)].interrupt_started && - !dev->endpoint[EP2I(ep)].interrupt_error) { - struct usb_redir_start_interrupt_receiving_header start_int = { - .endpoint = ep, - }; - /* No id, we look at the ep when receiving a status back */ - usbredirparser_send_start_interrupt_receiving(dev->parser, 0, - &start_int); - usbredirparser_do_write(dev->parser); - DPRINTF("interrupt recv started ep %02X\n", ep); - dev->endpoint[EP2I(ep)].interrupt_started = 1; - /* We don't really want to drop interrupt packets ever, but - having some upper limit to how much we buffer is good. */ - dev->endpoint[EP2I(ep)].bufpq_target_size = 1000; - dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; - } + /* Input interrupt endpoint, buffered packet input */ + struct buf_packet *intp; + int status, len; - intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq); - if (intp == NULL) { - DPRINTF2("interrupt-token-in ep %02X, no intp\n", ep); - /* Check interrupt_error for stream errors */ - status = dev->endpoint[EP2I(ep)].interrupt_error; - dev->endpoint[EP2I(ep)].interrupt_error = 0; - if (status) { - return usbredir_handle_status(dev, status, 0); - } - return USB_RET_NAK; - } - DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep, - intp->status, intp->len); + if (!dev->endpoint[EP2I(ep)].interrupt_started && + !dev->endpoint[EP2I(ep)].interrupt_error) { + struct usb_redir_start_interrupt_receiving_header start_int = { + .endpoint = ep, + }; + /* No id, we look at the ep when receiving a status back */ + usbredirparser_send_start_interrupt_receiving(dev->parser, 0, + &start_int); + usbredirparser_do_write(dev->parser); + DPRINTF("interrupt recv started ep %02X\n", ep); + dev->endpoint[EP2I(ep)].interrupt_started = 1; + /* We don't really want to drop interrupt packets ever, but + having some upper limit to how much we buffer is good. */ + dev->endpoint[EP2I(ep)].bufpq_target_size = 1000; + dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; + } - status = intp->status; - if (status != usb_redir_success) { - bufp_free(dev, intp, ep); - return usbredir_handle_status(dev, status, 0); + intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq); + if (intp == NULL) { + DPRINTF2("interrupt-token-in ep %02X, no intp\n", ep); + /* Check interrupt_error for stream errors */ + status = dev->endpoint[EP2I(ep)].interrupt_error; + dev->endpoint[EP2I(ep)].interrupt_error = 0; + if (status) { + usbredir_handle_status(dev, p, status); + } else { + p->status = USB_RET_NAK; } + return; + } + DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep, + intp->status, intp->len); - len = intp->len; - if (len > p->iov.size) { - ERROR("received int data is larger then packet ep %02X\n", ep); - bufp_free(dev, intp, ep); - return USB_RET_BABBLE; - } - usb_packet_copy(p, intp->data, len); - bufp_free(dev, intp, ep); - return len; - } else { - /* Output interrupt endpoint, normal async operation */ - AsyncURB *aurb = async_alloc(dev, p); - struct usb_redir_interrupt_packet_header interrupt_packet; - uint8_t buf[p->iov.size]; - - DPRINTF("interrupt-out ep %02X len %zd id %u\n", ep, p->iov.size, - aurb->packet_id); - - interrupt_packet.endpoint = ep; - interrupt_packet.length = p->iov.size; - aurb->interrupt_packet = interrupt_packet; - - usb_packet_copy(p, buf, p->iov.size); - usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size); - usbredirparser_send_interrupt_packet(dev->parser, aurb->packet_id, - &interrupt_packet, buf, p->iov.size); - usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; + status = intp->status; + len = intp->len; + if (len > p->iov.size) { + ERROR("received int data is larger then packet ep %02X\n", ep); + len = p->iov.size; + status = usb_redir_babble; } + usb_packet_copy(p, intp->data, len); + bufp_free(dev, intp, ep); + usbredir_handle_status(dev, p, status); +} + +/* + * Handle interrupt out data, the usbredir protocol expects us to do this + * async, so that it can report back a completion status. But guests will + * expect immediate completion for an interrupt endpoint, and handling this + * async causes migration issues. So we report success directly, counting + * on the fact that output interrupt packets normally always succeed. + */ +static void usbredir_handle_interrupt_out_data(USBRedirDevice *dev, + USBPacket *p, uint8_t ep) +{ + struct usb_redir_interrupt_packet_header interrupt_packet; + uint8_t buf[p->iov.size]; + + DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep, + p->iov.size, p->id); + + interrupt_packet.endpoint = ep; + interrupt_packet.length = p->iov.size; + + usb_packet_copy(p, buf, p->iov.size); + usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size); + usbredirparser_send_interrupt_packet(dev->parser, p->id, + &interrupt_packet, buf, p->iov.size); + usbredirparser_do_write(dev->parser); } static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev, @@ -609,7 +879,7 @@ static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev, usbredir_free_bufpq(dev, ep); } -static int usbredir_handle_data(USBDevice *udev, USBPacket *p) +static void usbredir_handle_data(USBDevice *udev, USBPacket *p) { USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); uint8_t ep; @@ -622,142 +892,166 @@ static int usbredir_handle_data(USBDevice *udev, USBPacket *p) switch (dev->endpoint[EP2I(ep)].type) { case USB_ENDPOINT_XFER_CONTROL: ERROR("handle_data called for control transfer on ep %02X\n", ep); - return USB_RET_NAK; - case USB_ENDPOINT_XFER_ISOC: - return usbredir_handle_iso_data(dev, p, ep); + p->status = USB_RET_NAK; + break; case USB_ENDPOINT_XFER_BULK: - return usbredir_handle_bulk_data(dev, p, ep); + if (p->state == USB_PACKET_SETUP && p->pid == USB_TOKEN_IN && + p->ep->pipeline) { + p->status = USB_RET_ADD_TO_QUEUE; + break; + } + usbredir_handle_bulk_data(dev, p, ep); + break; + case USB_ENDPOINT_XFER_ISOC: + usbredir_handle_iso_data(dev, p, ep); + break; case USB_ENDPOINT_XFER_INT: - return usbredir_handle_interrupt_data(dev, p, ep); + if (ep & USB_DIR_IN) { + usbredir_handle_interrupt_in_data(dev, p, ep); + } else { + usbredir_handle_interrupt_out_data(dev, p, ep); + } + break; default: ERROR("handle_data ep %02X has unknown type %d\n", ep, dev->endpoint[EP2I(ep)].type); - return USB_RET_NAK; + p->status = USB_RET_NAK; + } +} + +static void usbredir_flush_ep_queue(USBDevice *dev, USBEndpoint *ep) +{ + if (ep->pid == USB_TOKEN_IN && ep->pipeline) { + usb_ep_combine_input_packets(ep); + } +} + +static void usbredir_stop_ep(USBRedirDevice *dev, int i) +{ + uint8_t ep = I2EP(i); + + switch (dev->endpoint[i].type) { + case USB_ENDPOINT_XFER_BULK: + if (ep & USB_DIR_IN) { + usbredir_stop_bulk_receiving(dev, ep); + } + break; + case USB_ENDPOINT_XFER_ISOC: + usbredir_stop_iso_stream(dev, ep); + break; + case USB_ENDPOINT_XFER_INT: + if (ep & USB_DIR_IN) { + usbredir_stop_interrupt_receiving(dev, ep); + } + break; } + usbredir_free_bufpq(dev, ep); } -static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p, +static void usbredir_ep_stopped(USBDevice *udev, USBEndpoint *uep) +{ + USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); + + usbredir_stop_ep(dev, USBEP2I(uep)); + usbredirparser_do_write(dev->parser); +} + +static void usbredir_set_config(USBRedirDevice *dev, USBPacket *p, int config) { struct usb_redir_set_configuration_header set_config; - AsyncURB *aurb = async_alloc(dev, p); int i; - DPRINTF("set config %d id %u\n", config, aurb->packet_id); + DPRINTF("set config %d id %"PRIu64"\n", config, p->id); for (i = 0; i < MAX_ENDPOINTS; i++) { - switch (dev->endpoint[i].type) { - case USB_ENDPOINT_XFER_ISOC: - usbredir_stop_iso_stream(dev, I2EP(i)); - break; - case USB_ENDPOINT_XFER_INT: - if (i & 0x10) { - usbredir_stop_interrupt_receiving(dev, I2EP(i)); - } - break; - } - usbredir_free_bufpq(dev, I2EP(i)); + usbredir_stop_ep(dev, i); } set_config.configuration = config; - usbredirparser_send_set_configuration(dev->parser, aurb->packet_id, - &set_config); + usbredirparser_send_set_configuration(dev->parser, p->id, &set_config); usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } -static int usbredir_get_config(USBRedirDevice *dev, USBPacket *p) +static void usbredir_get_config(USBRedirDevice *dev, USBPacket *p) { - AsyncURB *aurb = async_alloc(dev, p); + DPRINTF("get config id %"PRIu64"\n", p->id); - DPRINTF("get config id %u\n", aurb->packet_id); - - aurb->get = 1; - usbredirparser_send_get_configuration(dev->parser, aurb->packet_id); + usbredirparser_send_get_configuration(dev->parser, p->id); usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } -static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p, +static void usbredir_set_interface(USBRedirDevice *dev, USBPacket *p, int interface, int alt) { struct usb_redir_set_alt_setting_header set_alt; - AsyncURB *aurb = async_alloc(dev, p); int i; - DPRINTF("set interface %d alt %d id %u\n", interface, alt, - aurb->packet_id); + DPRINTF("set interface %d alt %d id %"PRIu64"\n", interface, alt, p->id); for (i = 0; i < MAX_ENDPOINTS; i++) { if (dev->endpoint[i].interface == interface) { - switch (dev->endpoint[i].type) { - case USB_ENDPOINT_XFER_ISOC: - usbredir_stop_iso_stream(dev, I2EP(i)); - break; - case USB_ENDPOINT_XFER_INT: - if (i & 0x10) { - usbredir_stop_interrupt_receiving(dev, I2EP(i)); - } - break; - } - usbredir_free_bufpq(dev, I2EP(i)); + usbredir_stop_ep(dev, i); } } set_alt.interface = interface; set_alt.alt = alt; - usbredirparser_send_set_alt_setting(dev->parser, aurb->packet_id, - &set_alt); + usbredirparser_send_set_alt_setting(dev->parser, p->id, &set_alt); usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } -static int usbredir_get_interface(USBRedirDevice *dev, USBPacket *p, +static void usbredir_get_interface(USBRedirDevice *dev, USBPacket *p, int interface) { struct usb_redir_get_alt_setting_header get_alt; - AsyncURB *aurb = async_alloc(dev, p); - DPRINTF("get interface %d id %u\n", interface, aurb->packet_id); + DPRINTF("get interface %d id %"PRIu64"\n", interface, p->id); get_alt.interface = interface; - aurb->get = 1; - usbredirparser_send_get_alt_setting(dev->parser, aurb->packet_id, - &get_alt); + usbredirparser_send_get_alt_setting(dev->parser, p->id, &get_alt); usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } -static int usbredir_handle_control(USBDevice *udev, USBPacket *p, +static void usbredir_handle_control(USBDevice *udev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); struct usb_redir_control_packet_header control_packet; - AsyncURB *aurb; + + if (usbredir_already_in_flight(dev, p->id)) { + p->status = USB_RET_ASYNC; + return; + } /* Special cases for certain standard device requests */ switch (request) { case DeviceOutRequest | USB_REQ_SET_ADDRESS: DPRINTF("set address %d\n", value); dev->dev.addr = value; - return 0; + return; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - return usbredir_set_config(dev, p, value & 0xff); + usbredir_set_config(dev, p, value & 0xff); + return; case DeviceRequest | USB_REQ_GET_CONFIGURATION: - return usbredir_get_config(dev, p); + usbredir_get_config(dev, p); + return; case InterfaceOutRequest | USB_REQ_SET_INTERFACE: - return usbredir_set_interface(dev, p, index, value); + usbredir_set_interface(dev, p, index, value); + return; case InterfaceRequest | USB_REQ_GET_INTERFACE: - return usbredir_get_interface(dev, p, index); + usbredir_get_interface(dev, p, index); + return; } - /* "Normal" ctrl requests */ - aurb = async_alloc(dev, p); - - /* Note request is (bRequestType << 8) | bRequest */ - DPRINTF("ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %u\n", - request >> 8, request & 0xff, value, index, length, - aurb->packet_id); + /* Normal ctrl requests, note request is (bRequestType << 8) | bRequest */ + DPRINTF( + "ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %"PRIu64"\n", + request >> 8, request & 0xff, value, index, length, p->id); control_packet.request = request & 0xFF; control_packet.requesttype = request >> 8; @@ -765,18 +1059,17 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, control_packet.value = value; control_packet.index = index; control_packet.length = length; - aurb->control_packet = control_packet; if (control_packet.requesttype & USB_DIR_IN) { - usbredirparser_send_control_packet(dev->parser, aurb->packet_id, + usbredirparser_send_control_packet(dev->parser, p->id, &control_packet, NULL, 0); } else { usbredir_log_data(dev, "ctrl data out:", data, length); - usbredirparser_send_control_packet(dev->parser, aurb->packet_id, + usbredirparser_send_control_packet(dev->parser, p->id, &control_packet, data, length); } usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } /* @@ -784,53 +1077,73 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, * from within the USBDevice data / control packet callbacks and doing a * usb_detach from within these callbacks is not a good idea. * - * So we use a bh handler to take care of close events. We also handle - * open events from this callback to make sure that a close directly followed - * by an open gets handled in the right order. + * So we use a bh handler to take care of close events. */ -static void usbredir_open_close_bh(void *opaque) +static void usbredir_chardev_close_bh(void *opaque) { USBRedirDevice *dev = opaque; - uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; - char version[32]; - - strcpy(version, "qemu usb-redir guest "); - pstrcat(version, sizeof(version), qemu_get_version()); usbredir_device_disconnect(dev); if (dev->parser) { + DPRINTF("destroying usbredirparser\n"); usbredirparser_destroy(dev->parser); dev->parser = NULL; } +} - if (dev->cs->opened) { - dev->parser = qemu_oom_check(usbredirparser_create()); - dev->parser->priv = dev; - dev->parser->log_func = usbredir_log; - dev->parser->read_func = usbredir_read; - dev->parser->write_func = usbredir_write; - dev->parser->hello_func = usbredir_hello; - dev->parser->device_connect_func = usbredir_device_connect; - dev->parser->device_disconnect_func = usbredir_device_disconnect; - dev->parser->interface_info_func = usbredir_interface_info; - dev->parser->ep_info_func = usbredir_ep_info; - dev->parser->configuration_status_func = usbredir_configuration_status; - dev->parser->alt_setting_status_func = usbredir_alt_setting_status; - dev->parser->iso_stream_status_func = usbredir_iso_stream_status; - dev->parser->interrupt_receiving_status_func = - usbredir_interrupt_receiving_status; - dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status; - dev->parser->control_packet_func = usbredir_control_packet; - dev->parser->bulk_packet_func = usbredir_bulk_packet; - dev->parser->iso_packet_func = usbredir_iso_packet; - dev->parser->interrupt_packet_func = usbredir_interrupt_packet; - dev->read_buf = NULL; - dev->read_buf_size = 0; +static void usbredir_create_parser(USBRedirDevice *dev) +{ + uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; + int flags = 0; + + DPRINTF("creating usbredirparser\n"); + + dev->parser = qemu_oom_check(usbredirparser_create()); + dev->parser->priv = dev; + dev->parser->log_func = usbredir_log; + dev->parser->read_func = usbredir_read; + dev->parser->write_func = usbredir_write; + dev->parser->hello_func = usbredir_hello; + dev->parser->device_connect_func = usbredir_device_connect; + dev->parser->device_disconnect_func = usbredir_device_disconnect; + dev->parser->interface_info_func = usbredir_interface_info; + dev->parser->ep_info_func = usbredir_ep_info; + dev->parser->configuration_status_func = usbredir_configuration_status; + dev->parser->alt_setting_status_func = usbredir_alt_setting_status; + dev->parser->iso_stream_status_func = usbredir_iso_stream_status; + dev->parser->interrupt_receiving_status_func = + usbredir_interrupt_receiving_status; + dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status; + dev->parser->bulk_receiving_status_func = usbredir_bulk_receiving_status; + dev->parser->control_packet_func = usbredir_control_packet; + dev->parser->bulk_packet_func = usbredir_bulk_packet; + dev->parser->iso_packet_func = usbredir_iso_packet; + dev->parser->interrupt_packet_func = usbredir_interrupt_packet; + dev->parser->buffered_bulk_packet_func = usbredir_buffered_bulk_packet; + dev->read_buf = NULL; + dev->read_buf_size = 0; + + usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); + usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); + usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size); + usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); + usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length); + usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving); + + if (runstate_check(RUN_STATE_INMIGRATE)) { + flags |= usbredirparser_fl_no_hello; + } + usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, + flags); + usbredirparser_do_write(dev->parser); +} - usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); - usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); - usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0); +static void usbredir_reject_device(USBRedirDevice *dev) +{ + usbredir_device_disconnect(dev); + if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) { + usbredirparser_send_filter_reject(dev->parser); usbredirparser_do_write(dev->parser); } } @@ -839,12 +1152,22 @@ static void usbredir_do_attach(void *opaque) { USBRedirDevice *dev = opaque; + /* In order to work properly with XHCI controllers we need these caps */ + if ((dev->dev.port->speedmask & USB_SPEED_MASK_SUPER) && !( + usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_ep_info_max_packet_size) && + usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_32bits_bulk_length) && + usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_64bits_ids))) { + ERROR("usb-redir-host lacks capabilities needed for use with XHCI\n"); + usbredir_reject_device(dev); + return; + } + if (usb_device_attach(&dev->dev) != 0) { - usbredir_device_disconnect(dev); - if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) { - usbredirparser_send_filter_reject(dev->parser); - usbredirparser_do_write(dev->parser); - } + WARNING("rejecting device due to speed mismatch\n"); + usbredir_reject_device(dev); } } @@ -856,13 +1179,18 @@ static int usbredir_chardev_can_read(void *opaque) { USBRedirDevice *dev = opaque; - if (dev->parser) { - /* usbredir_parser_do_read will consume *all* data we give it */ - return 1024 * 1024; - } else { - /* usbredir_open_close_bh hasn't handled the open event yet */ + if (!dev->parser) { + WARNING("chardev_can_read called on non open chardev!\n"); return 0; } + + /* Don't read new data from the chardev until our state is fully synced */ + if (!runstate_check(RUN_STATE_RUNNING)) { + return 0; + } + + /* usbredir_parser_do_read will consume *all* data we give it */ + return 1024 * 1024; } static void usbredir_chardev_read(void *opaque, const uint8_t *buf, int size) @@ -886,8 +1214,15 @@ static void usbredir_chardev_event(void *opaque, int event) switch (event) { case CHR_EVENT_OPENED: + DPRINTF("chardev open\n"); + /* Make sure any pending closes are handled (no-op if none pending) */ + usbredir_chardev_close_bh(dev); + qemu_bh_cancel(dev->chardev_close_bh); + usbredir_create_parser(dev); + break; case CHR_EVENT_CLOSED: - qemu_bh_schedule(dev->open_close_bh); + DPRINTF("chardev close\n"); + qemu_bh_schedule(dev->chardev_close_bh); break; } } @@ -896,6 +1231,27 @@ static void usbredir_chardev_event(void *opaque, int event) * init + destroy */ +static void usbredir_vm_state_change(void *priv, int running, RunState state) +{ + USBRedirDevice *dev = priv; + + if (state == RUN_STATE_RUNNING && dev->parser != NULL) { + usbredirparser_do_write(dev->parser); /* Flush any pending writes */ + } +} + +static void usbredir_init_endpoints(USBRedirDevice *dev) +{ + int i; + + usb_ep_init(&dev->dev); + memset(dev->endpoint, 0, sizeof(dev->endpoint)); + for (i = 0; i < MAX_ENDPOINTS; i++) { + dev->endpoint[i].dev = dev; + QTAILQ_INIT(&dev->endpoint[i].bufpq); + } +} + static int usbredir_initfn(USBDevice *udev) { USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); @@ -917,34 +1273,35 @@ static int usbredir_initfn(USBDevice *udev) } } - dev->open_close_bh = qemu_bh_new(usbredir_open_close_bh, dev); + dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); - QTAILQ_INIT(&dev->asyncq); - for (i = 0; i < MAX_ENDPOINTS; i++) { - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } + packet_id_queue_init(&dev->cancelled, dev, "cancelled"); + packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight"); + usbredir_init_endpoints(dev); /* We'll do the attach once we receive the speed from the usb-host */ udev->auto_attach = 0; + /* Will be cleared during setup when we find conflicts */ + dev->compatible_speedmask = USB_SPEED_MASK_FULL | USB_SPEED_MASK_HIGH; + /* Let the backend know we are ready */ qemu_chr_fe_open(dev->cs); qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read, usbredir_chardev_read, usbredir_chardev_event, dev); + qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev); add_boot_device_path(dev->bootindex, &udev->qdev, NULL); return 0; } static void usbredir_cleanup_device_queues(USBRedirDevice *dev) { - AsyncURB *aurb, *next_aurb; int i; - QTAILQ_FOREACH_SAFE(aurb, &dev->asyncq, next, next_aurb) { - async_free(dev, aurb); - } + packet_id_queue_empty(&dev->cancelled); + packet_id_queue_empty(&dev->already_in_flight); for (i = 0; i < MAX_ENDPOINTS; i++) { usbredir_free_bufpq(dev, I2EP(i)); } @@ -957,7 +1314,7 @@ static void usbredir_handle_destroy(USBDevice *udev) qemu_chr_fe_close(dev->cs); qemu_chr_delete(dev->cs); /* Note must be done after qemu_chr_close, as that causes a close event */ - qemu_bh_delete(dev->open_close_bh); + qemu_bh_delete(dev->chardev_close_bh); qemu_del_timer(dev->attach_timer); qemu_free_timer(dev->attach_timer); @@ -1007,38 +1364,88 @@ static int usbredir_check_filter(USBRedirDevice *dev) return 0; error: - usbredir_device_disconnect(dev); - if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) { - usbredirparser_send_filter_reject(dev->parser); - usbredirparser_do_write(dev->parser); - } + usbredir_reject_device(dev); return -1; } +static void usbredir_check_bulk_receiving(USBRedirDevice *dev) +{ + int i, j, quirks; + + if (!usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_bulk_receiving)) { + return; + } + + for (i = EP2I(USB_DIR_IN); i < MAX_ENDPOINTS; i++) { + dev->endpoint[i].bulk_receiving_enabled = 0; + } + for (i = 0; i < dev->interface_info.interface_count; i++) { + quirks = usb_get_quirks(dev->device_info.vendor_id, + dev->device_info.product_id, + dev->interface_info.interface_class[i], + dev->interface_info.interface_subclass[i], + dev->interface_info.interface_protocol[i]); + if (!(quirks & USB_QUIRK_BUFFER_BULK_IN)) { + continue; + } + if (quirks & USB_QUIRK_IS_FTDI) { + dev->buffered_bulk_in_complete = + usbredir_buffered_bulk_in_complete_ftdi; + } else { + dev->buffered_bulk_in_complete = + usbredir_buffered_bulk_in_complete_raw; + } + + for (j = EP2I(USB_DIR_IN); j < MAX_ENDPOINTS; j++) { + if (dev->endpoint[j].interface == + dev->interface_info.interface[i] && + dev->endpoint[j].type == USB_ENDPOINT_XFER_BULK && + dev->endpoint[j].max_packet_size != 0) { + dev->endpoint[j].bulk_receiving_enabled = 1; + /* + * With buffering pipelining is not necessary. Also packet + * combining and bulk in buffering don't play nice together! + */ + I2USBEP(dev, j)->pipeline = false; + break; /* Only buffer for the first ep of each intf */ + } + } + } +} + /* * usbredirparser packet complete callbacks */ -static int usbredir_handle_status(USBRedirDevice *dev, - int status, int actual_len) +static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p, + int status) { switch (status) { case usb_redir_success: - return actual_len; + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ + break; case usb_redir_stall: - return USB_RET_STALL; + p->status = USB_RET_STALL; + break; case usb_redir_cancelled: - WARNING("returning cancelled packet to HC?\n"); - return USB_RET_NAK; + /* + * When the usbredir-host unredirects a device, it will report a status + * of cancelled for all pending packets, followed by a disconnect msg. + */ + p->status = USB_RET_IOERROR; + break; case usb_redir_inval: WARNING("got invalid param error from usb-host?\n"); - return USB_RET_NAK; + p->status = USB_RET_IOERROR; + break; case usb_redir_babble: - return USB_RET_BABBLE; + p->status = USB_RET_BABBLE; + break; case usb_redir_ioerror: case usb_redir_timeout: default: - return USB_RET_IOERROR; + p->status = USB_RET_IOERROR; } } @@ -1070,10 +1477,13 @@ static void usbredir_device_connect(void *priv, case usb_redir_speed_low: speed = "low speed"; dev->dev.speed = USB_SPEED_LOW; + dev->compatible_speedmask &= ~USB_SPEED_MASK_FULL; + dev->compatible_speedmask &= ~USB_SPEED_MASK_HIGH; break; case usb_redir_speed_full: speed = "full speed"; dev->dev.speed = USB_SPEED_FULL; + dev->compatible_speedmask &= ~USB_SPEED_MASK_HIGH; break; case usb_redir_speed_high: speed = "high speed"; @@ -1103,7 +1513,7 @@ static void usbredir_device_connect(void *priv, device_connect->device_class); } - dev->dev.speedmask = (1 << dev->dev.speed); + dev->dev.speedmask = (1 << dev->dev.speed) | dev->compatible_speedmask; dev->device_info = *device_connect; if (usbredir_check_filter(dev)) { @@ -1112,18 +1522,19 @@ static void usbredir_device_connect(void *priv, return; } + usbredir_check_bulk_receiving(dev); qemu_mod_timer(dev->attach_timer, dev->next_attach_time); } static void usbredir_device_disconnect(void *priv) { USBRedirDevice *dev = priv; - int i; /* Stop any pending attaches */ qemu_del_timer(dev->attach_timer); if (dev->dev.attached) { + DPRINTF("detaching device\n"); usb_device_detach(&dev->dev); /* * Delay next usb device attach to give the guest a chance to see @@ -1134,14 +1545,11 @@ static void usbredir_device_disconnect(void *priv) /* Reset state so that the next dev connected starts with a clean slate */ usbredir_cleanup_device_queues(dev); - memset(dev->endpoint, 0, sizeof(dev->endpoint)); - for (i = 0; i < MAX_ENDPOINTS; i++) { - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } - usb_ep_init(&dev->dev); + usbredir_init_endpoints(dev); dev->interface_info.interface_count = NO_INTERFACE_INFO; dev->dev.addr = 0; dev->dev.speed = 0; + dev->compatible_speedmask = USB_SPEED_MASK_FULL | USB_SPEED_MASK_HIGH; } static void usbredir_interface_info(void *priv, @@ -1153,9 +1561,10 @@ static void usbredir_interface_info(void *priv, /* * If we receive interface info after the device has already been - * connected (ie on a set_config), re-check the filter. + * connected (ie on a set_config), re-check interface dependent things. */ if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) { + usbredir_check_bulk_receiving(dev); if (usbredir_check_filter(dev)) { ERROR("Device no longer matches filter after interface info " "change, disconnecting!\n"); @@ -1163,25 +1572,77 @@ static void usbredir_interface_info(void *priv, } } +static void usbredir_mark_speed_incompatible(USBRedirDevice *dev, int speed) +{ + dev->compatible_speedmask &= ~(1 << speed); + dev->dev.speedmask = (1 << dev->dev.speed) | dev->compatible_speedmask; +} + +static void usbredir_set_pipeline(USBRedirDevice *dev, struct USBEndpoint *uep) +{ + if (uep->type != USB_ENDPOINT_XFER_BULK) { + return; + } + if (uep->pid == USB_TOKEN_OUT) { + uep->pipeline = true; + } + if (uep->pid == USB_TOKEN_IN && uep->max_packet_size != 0 && + usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_32bits_bulk_length)) { + uep->pipeline = true; + } +} + +static void usbredir_setup_usb_eps(USBRedirDevice *dev) +{ + struct USBEndpoint *usb_ep; + int i; + + for (i = 0; i < MAX_ENDPOINTS; i++) { + usb_ep = I2USBEP(dev, i); + usb_ep->type = dev->endpoint[i].type; + usb_ep->ifnum = dev->endpoint[i].interface; + usb_ep->max_packet_size = dev->endpoint[i].max_packet_size; + usbredir_set_pipeline(dev, usb_ep); + } +} + static void usbredir_ep_info(void *priv, struct usb_redir_ep_info_header *ep_info) { USBRedirDevice *dev = priv; - struct USBEndpoint *usb_ep; int i; for (i = 0; i < MAX_ENDPOINTS; i++) { dev->endpoint[i].type = ep_info->type[i]; dev->endpoint[i].interval = ep_info->interval[i]; dev->endpoint[i].interface = ep_info->interface[i]; + if (usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_ep_info_max_packet_size)) { + dev->endpoint[i].max_packet_size = ep_info->max_packet_size[i]; + } switch (dev->endpoint[i].type) { case usb_redir_type_invalid: break; case usb_redir_type_iso: + usbredir_mark_speed_incompatible(dev, USB_SPEED_FULL); + usbredir_mark_speed_incompatible(dev, USB_SPEED_HIGH); + /* Fall through */ case usb_redir_type_interrupt: + if (!usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_ep_info_max_packet_size) || + ep_info->max_packet_size[i] > 64) { + usbredir_mark_speed_incompatible(dev, USB_SPEED_FULL); + } + if (!usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_ep_info_max_packet_size) || + ep_info->max_packet_size[i] > 1024) { + usbredir_mark_speed_incompatible(dev, USB_SPEED_HIGH); + } if (dev->endpoint[i].interval == 0) { ERROR("Received 0 interval for isoc or irq endpoint\n"); - usbredir_device_disconnect(dev); + usbredir_reject_device(dev); + return; } /* Fall through */ case usb_redir_type_control: @@ -1191,78 +1652,70 @@ static void usbredir_ep_info(void *priv, break; default: ERROR("Received invalid endpoint type\n"); - usbredir_device_disconnect(dev); + usbredir_reject_device(dev); return; } - usb_ep = usb_ep_get(&dev->dev, - (i & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, - i & 0x0f); - usb_ep->type = dev->endpoint[i].type; - usb_ep->ifnum = dev->endpoint[i].interface; } + /* The new ep info may have caused a speed incompatibility, recheck */ + if (dev->dev.attached && + !(dev->dev.port->speedmask & dev->dev.speedmask)) { + ERROR("Device no longer matches speed after endpoint info change, " + "disconnecting!\n"); + usbredir_reject_device(dev); + return; + } + usbredir_setup_usb_eps(dev); + usbredir_check_bulk_receiving(dev); } -static void usbredir_configuration_status(void *priv, uint32_t id, +static void usbredir_configuration_status(void *priv, uint64_t id, struct usb_redir_configuration_status_header *config_status) { USBRedirDevice *dev = priv; - AsyncURB *aurb; - int len = 0; + USBPacket *p; - DPRINTF("set config status %d config %d id %u\n", config_status->status, - config_status->configuration, id); + DPRINTF("set config status %d config %d id %"PRIu64"\n", + config_status->status, config_status->configuration, id); - aurb = async_find(dev, id); - if (!aurb) { - return; - } - if (aurb->packet) { - if (aurb->get) { + p = usbredir_find_packet_by_id(dev, 0, id); + if (p) { + if (dev->dev.setup_buf[0] & USB_DIR_IN) { dev->dev.data_buf[0] = config_status->configuration; - len = 1; + p->actual_length = 1; } - aurb->packet->result = - usbredir_handle_status(dev, config_status->status, len); - usb_generic_async_ctrl_complete(&dev->dev, aurb->packet); + usbredir_handle_status(dev, p, config_status->status); + usb_generic_async_ctrl_complete(&dev->dev, p); } - async_free(dev, aurb); } -static void usbredir_alt_setting_status(void *priv, uint32_t id, +static void usbredir_alt_setting_status(void *priv, uint64_t id, struct usb_redir_alt_setting_status_header *alt_setting_status) { USBRedirDevice *dev = priv; - AsyncURB *aurb; - int len = 0; + USBPacket *p; - DPRINTF("alt status %d intf %d alt %d id: %u\n", - alt_setting_status->status, - alt_setting_status->interface, + DPRINTF("alt status %d intf %d alt %d id: %"PRIu64"\n", + alt_setting_status->status, alt_setting_status->interface, alt_setting_status->alt, id); - aurb = async_find(dev, id); - if (!aurb) { - return; - } - if (aurb->packet) { - if (aurb->get) { + p = usbredir_find_packet_by_id(dev, 0, id); + if (p) { + if (dev->dev.setup_buf[0] & USB_DIR_IN) { dev->dev.data_buf[0] = alt_setting_status->alt; - len = 1; + p->actual_length = 1; } - aurb->packet->result = - usbredir_handle_status(dev, alt_setting_status->status, len); - usb_generic_async_ctrl_complete(&dev->dev, aurb->packet); + usbredir_handle_status(dev, p, alt_setting_status->status); + usb_generic_async_ctrl_complete(&dev->dev, p); } - async_free(dev, aurb); } -static void usbredir_iso_stream_status(void *priv, uint32_t id, +static void usbredir_iso_stream_status(void *priv, uint64_t id, struct usb_redir_iso_stream_status_header *iso_stream_status) { USBRedirDevice *dev = priv; uint8_t ep = iso_stream_status->endpoint; - DPRINTF("iso status %d ep %02X id %u\n", iso_stream_status->status, + DPRINTF("iso status %d ep %02X id %"PRIu64"\n", iso_stream_status->status, ep, id); if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].iso_started) { @@ -1276,14 +1729,14 @@ static void usbredir_iso_stream_status(void *priv, uint32_t id, } } -static void usbredir_interrupt_receiving_status(void *priv, uint32_t id, +static void usbredir_interrupt_receiving_status(void *priv, uint64_t id, struct usb_redir_interrupt_receiving_status_header *interrupt_receiving_status) { USBRedirDevice *dev = priv; uint8_t ep = interrupt_receiving_status->endpoint; - DPRINTF("interrupt recv status %d ep %02X id %u\n", + DPRINTF("interrupt recv status %d ep %02X id %"PRIu64"\n", interrupt_receiving_status->status, ep, id); if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].interrupt_started) { @@ -1298,107 +1751,121 @@ static void usbredir_interrupt_receiving_status(void *priv, uint32_t id, } } -static void usbredir_bulk_streams_status(void *priv, uint32_t id, +static void usbredir_bulk_streams_status(void *priv, uint64_t id, struct usb_redir_bulk_streams_status_header *bulk_streams_status) { } -static void usbredir_control_packet(void *priv, uint32_t id, - struct usb_redir_control_packet_header *control_packet, - uint8_t *data, int data_len) +static void usbredir_bulk_receiving_status(void *priv, uint64_t id, + struct usb_redir_bulk_receiving_status_header *bulk_receiving_status) { USBRedirDevice *dev = priv; - int len = control_packet->length; - AsyncURB *aurb; + uint8_t ep = bulk_receiving_status->endpoint; - DPRINTF("ctrl-in status %d len %d id %u\n", control_packet->status, - len, id); + DPRINTF("bulk recv status %d ep %02X id %"PRIu64"\n", + bulk_receiving_status->status, ep, id); - aurb = async_find(dev, id); - if (!aurb) { - free(data); + if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].bulk_receiving_started) { return; } - aurb->control_packet.status = control_packet->status; - aurb->control_packet.length = control_packet->length; - if (memcmp(&aurb->control_packet, control_packet, - sizeof(*control_packet))) { - ERROR("return control packet mismatch, please report this!\n"); - len = USB_RET_NAK; + if (bulk_receiving_status->status == usb_redir_stall) { + DPRINTF("bulk receiving stopped by peer ep %02X\n", ep); + dev->endpoint[EP2I(ep)].bulk_receiving_started = 0; } +} + +static void usbredir_control_packet(void *priv, uint64_t id, + struct usb_redir_control_packet_header *control_packet, + uint8_t *data, int data_len) +{ + USBRedirDevice *dev = priv; + USBPacket *p; + int len = control_packet->length; + + DPRINTF("ctrl-in status %d len %d id %"PRIu64"\n", control_packet->status, + len, id); - if (aurb->packet) { - len = usbredir_handle_status(dev, control_packet->status, len); - if (len > 0) { + /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices + * to work redirected to a not superspeed capable hcd */ + if (dev->dev.speed == USB_SPEED_SUPER && + !((dev->dev.port->speedmask & USB_SPEED_MASK_SUPER)) && + control_packet->requesttype == 0x80 && + control_packet->request == 6 && + control_packet->value == 0x100 && control_packet->index == 0 && + data_len >= 18 && data[7] == 9) { + data[7] = 64; + } + + p = usbredir_find_packet_by_id(dev, 0, id); + if (p) { + usbredir_handle_status(dev, p, control_packet->status); + if (data_len > 0) { usbredir_log_data(dev, "ctrl data in:", data, data_len); - if (data_len <= sizeof(dev->dev.data_buf)) { - memcpy(dev->dev.data_buf, data, data_len); - } else { + if (data_len > sizeof(dev->dev.data_buf)) { ERROR("ctrl buffer too small (%d > %zu)\n", data_len, sizeof(dev->dev.data_buf)); - len = USB_RET_STALL; + p->status = USB_RET_STALL; + data_len = len = sizeof(dev->dev.data_buf); } + memcpy(dev->dev.data_buf, data, data_len); } - aurb->packet->result = len; - usb_generic_async_ctrl_complete(&dev->dev, aurb->packet); + p->actual_length = len; + usb_generic_async_ctrl_complete(&dev->dev, p); } - async_free(dev, aurb); free(data); } -static void usbredir_bulk_packet(void *priv, uint32_t id, +static void usbredir_bulk_packet(void *priv, uint64_t id, struct usb_redir_bulk_packet_header *bulk_packet, uint8_t *data, int data_len) { USBRedirDevice *dev = priv; uint8_t ep = bulk_packet->endpoint; - int len = bulk_packet->length; - AsyncURB *aurb; - - DPRINTF("bulk-in status %d ep %02X len %d id %u\n", bulk_packet->status, - ep, len, id); - - aurb = async_find(dev, id); - if (!aurb) { - free(data); - return; - } + int len = (bulk_packet->length_high << 16) | bulk_packet->length; + USBPacket *p; - if (aurb->bulk_packet.endpoint != bulk_packet->endpoint || - aurb->bulk_packet.stream_id != bulk_packet->stream_id) { - ERROR("return bulk packet mismatch, please report this!\n"); - len = USB_RET_NAK; - } + DPRINTF("bulk-in status %d ep %02X len %d id %"PRIu64"\n", + bulk_packet->status, ep, len, id); - if (aurb->packet) { - len = usbredir_handle_status(dev, bulk_packet->status, len); - if (len > 0) { + p = usbredir_find_packet_by_id(dev, ep, id); + if (p) { + size_t size = (p->combined) ? p->combined->iov.size : p->iov.size; + usbredir_handle_status(dev, p, bulk_packet->status); + if (data_len > 0) { usbredir_log_data(dev, "bulk data in:", data, data_len); - if (data_len <= aurb->packet->iov.size) { - usb_packet_copy(aurb->packet, data, data_len); + if (data_len > size) { + ERROR("bulk got more data then requested (%d > %zd)\n", + data_len, p->iov.size); + p->status = USB_RET_BABBLE; + data_len = len = size; + } + if (p->combined) { + iov_from_buf(p->combined->iov.iov, p->combined->iov.niov, + 0, data, data_len); } else { - ERROR("bulk buffer too small (%d > %zd)\n", data_len, - aurb->packet->iov.size); - len = USB_RET_STALL; + usb_packet_copy(p, data, data_len); } } - aurb->packet->result = len; - usb_packet_complete(&dev->dev, aurb->packet); + p->actual_length = len; + if (p->pid == USB_TOKEN_IN && p->ep->pipeline) { + usb_combined_input_packet_complete(&dev->dev, p); + } else { + usb_packet_complete(&dev->dev, p); + } } - async_free(dev, aurb); free(data); } -static void usbredir_iso_packet(void *priv, uint32_t id, +static void usbredir_iso_packet(void *priv, uint64_t id, struct usb_redir_iso_packet_header *iso_packet, uint8_t *data, int data_len) { USBRedirDevice *dev = priv; uint8_t ep = iso_packet->endpoint; - DPRINTF2("iso-in status %d ep %02X len %d id %u\n", iso_packet->status, ep, - data_len, id); + DPRINTF2("iso-in status %d ep %02X len %d id %"PRIu64"\n", + iso_packet->status, ep, data_len, id); if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_ISOC) { ERROR("received iso packet for non iso endpoint %02X\n", ep); @@ -1413,17 +1880,17 @@ static void usbredir_iso_packet(void *priv, uint32_t id, } /* bufp_alloc also adds the packet to the ep queue */ - bufp_alloc(dev, data, data_len, iso_packet->status, ep); + bufp_alloc(dev, data, data_len, iso_packet->status, ep, data); } -static void usbredir_interrupt_packet(void *priv, uint32_t id, +static void usbredir_interrupt_packet(void *priv, uint64_t id, struct usb_redir_interrupt_packet_header *interrupt_packet, uint8_t *data, int data_len) { USBRedirDevice *dev = priv; uint8_t ep = interrupt_packet->endpoint; - DPRINTF("interrupt-in status %d ep %02X len %d id %u\n", + DPRINTF("interrupt-in status %d ep %02X len %d id %"PRIu64"\n", interrupt_packet->status, ep, data_len, id); if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_INT) { @@ -1439,33 +1906,418 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id, return; } + if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) { + usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f)); + } + /* bufp_alloc also adds the packet to the ep queue */ - bufp_alloc(dev, data, data_len, interrupt_packet->status, ep); + bufp_alloc(dev, data, data_len, interrupt_packet->status, ep, data); } else { - int len = interrupt_packet->length; - - AsyncURB *aurb = async_find(dev, id); - if (!aurb) { - return; + /* + * We report output interrupt packets as completed directly upon + * submission, so all we can do here if one failed is warn. + */ + if (interrupt_packet->status) { + WARNING("interrupt output failed status %d ep %02X id %"PRIu64"\n", + interrupt_packet->status, ep, id); } + } +} + +static void usbredir_buffered_bulk_packet(void *priv, uint64_t id, + struct usb_redir_buffered_bulk_packet_header *buffered_bulk_packet, + uint8_t *data, int data_len) +{ + USBRedirDevice *dev = priv; + uint8_t status, ep = buffered_bulk_packet->endpoint; + void *free_on_destroy; + int i, len; - if (aurb->interrupt_packet.endpoint != interrupt_packet->endpoint) { - ERROR("return int packet mismatch, please report this!\n"); - len = USB_RET_NAK; + DPRINTF("buffered-bulk-in status %d ep %02X len %d id %"PRIu64"\n", + buffered_bulk_packet->status, ep, data_len, id); + + if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_BULK) { + ERROR("received buffered-bulk packet for non bulk ep %02X\n", ep); + free(data); + return; + } + + if (dev->endpoint[EP2I(ep)].bulk_receiving_started == 0) { + DPRINTF("received buffered-bulk packet on not started ep %02X\n", ep); + free(data); + return; + } + + /* Data must be in maxp chunks for buffered_bulk_add_*_data_to_packet */ + len = dev->endpoint[EP2I(ep)].max_packet_size; + status = usb_redir_success; + free_on_destroy = NULL; + for (i = 0; i < data_len; i += len) { + if (len >= (data_len - i)) { + len = data_len - i; + status = buffered_bulk_packet->status; + free_on_destroy = data; } + /* bufp_alloc also adds the packet to the ep queue */ + bufp_alloc(dev, data + i, len, status, ep, free_on_destroy); + } + + if (dev->endpoint[EP2I(ep)].pending_async_packet) { + USBPacket *p = dev->endpoint[EP2I(ep)].pending_async_packet; + dev->endpoint[EP2I(ep)].pending_async_packet = NULL; + usbredir_buffered_bulk_in_complete(dev, p, ep); + usb_packet_complete(&dev->dev, p); + } +} + +/* + * Migration code + */ + +static void usbredir_pre_save(void *priv) +{ + USBRedirDevice *dev = priv; + + usbredir_fill_already_in_flight(dev); +} + +static int usbredir_post_load(void *priv, int version_id) +{ + USBRedirDevice *dev = priv; + + switch (dev->device_info.speed) { + case usb_redir_speed_low: + dev->dev.speed = USB_SPEED_LOW; + break; + case usb_redir_speed_full: + dev->dev.speed = USB_SPEED_FULL; + break; + case usb_redir_speed_high: + dev->dev.speed = USB_SPEED_HIGH; + break; + case usb_redir_speed_super: + dev->dev.speed = USB_SPEED_SUPER; + break; + default: + dev->dev.speed = USB_SPEED_FULL; + } + dev->dev.speedmask = (1 << dev->dev.speed); + + usbredir_setup_usb_eps(dev); + usbredir_check_bulk_receiving(dev); + + return 0; +} + +/* For usbredirparser migration */ +static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused) +{ + USBRedirDevice *dev = priv; + uint8_t *data; + int len; + + if (dev->parser == NULL) { + qemu_put_be32(f, 0); + return; + } + + usbredirparser_serialize(dev->parser, &data, &len); + qemu_oom_check(data); + + qemu_put_be32(f, len); + qemu_put_buffer(f, data, len); + + free(data); +} + +static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused) +{ + USBRedirDevice *dev = priv; + uint8_t *data; + int len, ret; + + len = qemu_get_be32(f); + if (len == 0) { + return 0; + } - if (aurb->packet) { - aurb->packet->result = usbredir_handle_status(dev, - interrupt_packet->status, len); - usb_packet_complete(&dev->dev, aurb->packet); + /* + * If our chardev is not open already at this point the usbredir connection + * has been broken (non seamless migration, or restore from disk). + * + * In this case create a temporary parser to receive the migration data, + * and schedule the close_bh to report the device as disconnected to the + * guest and to destroy the parser again. + */ + if (dev->parser == NULL) { + WARNING("usb-redir connection broken during migration\n"); + usbredir_create_parser(dev); + qemu_bh_schedule(dev->chardev_close_bh); + } + + data = g_malloc(len); + qemu_get_buffer(f, data, len); + + ret = usbredirparser_unserialize(dev->parser, data, len); + + g_free(data); + + return ret; +} + +static const VMStateInfo usbredir_parser_vmstate_info = { + .name = "usb-redir-parser", + .put = usbredir_put_parser, + .get = usbredir_get_parser, +}; + + +/* For buffered packets (iso/irq) queue migration */ +static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused) +{ + struct endp_data *endp = priv; + USBRedirDevice *dev = endp->dev; + struct buf_packet *bufp; + int len, i = 0; + + qemu_put_be32(f, endp->bufpq_size); + QTAILQ_FOREACH(bufp, &endp->bufpq, next) { + len = bufp->len - bufp->offset; + DPRINTF("put_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size, + len, bufp->status); + qemu_put_be32(f, len); + qemu_put_be32(f, bufp->status); + qemu_put_buffer(f, bufp->data + bufp->offset, len); + i++; + } + assert(i == endp->bufpq_size); +} + +static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused) +{ + struct endp_data *endp = priv; + USBRedirDevice *dev = endp->dev; + struct buf_packet *bufp; + int i; + + endp->bufpq_size = qemu_get_be32(f); + for (i = 0; i < endp->bufpq_size; i++) { + bufp = g_malloc(sizeof(struct buf_packet)); + bufp->len = qemu_get_be32(f); + bufp->status = qemu_get_be32(f); + bufp->offset = 0; + bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */ + bufp->free_on_destroy = bufp->data; + qemu_get_buffer(f, bufp->data, bufp->len); + QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next); + DPRINTF("get_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size, + bufp->len, bufp->status); + } + return 0; +} + +static const VMStateInfo usbredir_ep_bufpq_vmstate_info = { + .name = "usb-redir-bufpq", + .put = usbredir_put_bufpq, + .get = usbredir_get_bufpq, +}; + + +/* For endp_data migration */ +static const VMStateDescription usbredir_bulk_receiving_vmstate = { + .name = "usb-redir-ep/bulk-receiving", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(bulk_receiving_started, struct endp_data), + VMSTATE_END_OF_LIST() + } +}; + +static bool usbredir_bulk_receiving_needed(void *priv) +{ + struct endp_data *endp = priv; + + return endp->bulk_receiving_started; +} + +static const VMStateDescription usbredir_ep_vmstate = { + .name = "usb-redir-ep", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(type, struct endp_data), + VMSTATE_UINT8(interval, struct endp_data), + VMSTATE_UINT8(interface, struct endp_data), + VMSTATE_UINT16(max_packet_size, struct endp_data), + VMSTATE_UINT8(iso_started, struct endp_data), + VMSTATE_UINT8(iso_error, struct endp_data), + VMSTATE_UINT8(interrupt_started, struct endp_data), + VMSTATE_UINT8(interrupt_error, struct endp_data), + VMSTATE_UINT8(bufpq_prefilled, struct endp_data), + VMSTATE_UINT8(bufpq_dropping_packets, struct endp_data), + { + .name = "bufpq", + .version_id = 0, + .field_exists = NULL, + .size = 0, + .info = &usbredir_ep_bufpq_vmstate_info, + .flags = VMS_SINGLE, + .offset = 0, + }, + VMSTATE_INT32(bufpq_target_size, struct endp_data), + VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection[]) { + { + .vmsd = &usbredir_bulk_receiving_vmstate, + .needed = usbredir_bulk_receiving_needed, + }, { + /* empty */ } - async_free(dev, aurb); } +}; + + +/* For PacketIdQueue migration */ +static void usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused) +{ + struct PacketIdQueue *q = priv; + USBRedirDevice *dev = q->dev; + struct PacketIdQueueEntry *e; + int remain = q->size; + + DPRINTF("put_packet_id_q %s size %d\n", q->name, q->size); + qemu_put_be32(f, q->size); + QTAILQ_FOREACH(e, &q->head, next) { + qemu_put_be64(f, e->id); + remain--; + } + assert(remain == 0); } +static int usbredir_get_packet_id_q(QEMUFile *f, void *priv, size_t unused) +{ + struct PacketIdQueue *q = priv; + USBRedirDevice *dev = q->dev; + int i, size; + uint64_t id; + + size = qemu_get_be32(f); + DPRINTF("get_packet_id_q %s size %d\n", q->name, size); + for (i = 0; i < size; i++) { + id = qemu_get_be64(f); + packet_id_queue_add(q, id); + } + assert(q->size == size); + return 0; +} + +static const VMStateInfo usbredir_ep_packet_id_q_vmstate_info = { + .name = "usb-redir-packet-id-q", + .put = usbredir_put_packet_id_q, + .get = usbredir_get_packet_id_q, +}; + +static const VMStateDescription usbredir_ep_packet_id_queue_vmstate = { + .name = "usb-redir-packet-id-queue", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + { + .name = "queue", + .version_id = 0, + .field_exists = NULL, + .size = 0, + .info = &usbredir_ep_packet_id_q_vmstate_info, + .flags = VMS_SINGLE, + .offset = 0, + }, + VMSTATE_END_OF_LIST() + } +}; + + +/* For usb_redir_device_connect_header migration */ +static const VMStateDescription usbredir_device_info_vmstate = { + .name = "usb-redir-device-info", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(speed, struct usb_redir_device_connect_header), + VMSTATE_UINT8(device_class, struct usb_redir_device_connect_header), + VMSTATE_UINT8(device_subclass, struct usb_redir_device_connect_header), + VMSTATE_UINT8(device_protocol, struct usb_redir_device_connect_header), + VMSTATE_UINT16(vendor_id, struct usb_redir_device_connect_header), + VMSTATE_UINT16(product_id, struct usb_redir_device_connect_header), + VMSTATE_UINT16(device_version_bcd, + struct usb_redir_device_connect_header), + VMSTATE_END_OF_LIST() + } +}; + + +/* For usb_redir_interface_info_header migration */ +static const VMStateDescription usbredir_interface_info_vmstate = { + .name = "usb-redir-interface-info", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(interface_count, + struct usb_redir_interface_info_header), + VMSTATE_UINT8_ARRAY(interface, + struct usb_redir_interface_info_header, 32), + VMSTATE_UINT8_ARRAY(interface_class, + struct usb_redir_interface_info_header, 32), + VMSTATE_UINT8_ARRAY(interface_subclass, + struct usb_redir_interface_info_header, 32), + VMSTATE_UINT8_ARRAY(interface_protocol, + struct usb_redir_interface_info_header, 32), + VMSTATE_END_OF_LIST() + } +}; + + +/* And finally the USBRedirDevice vmstate itself */ +static const VMStateDescription usbredir_vmstate = { + .name = "usb-redir", + .version_id = 1, + .minimum_version_id = 1, + .pre_save = usbredir_pre_save, + .post_load = usbredir_post_load, + .fields = (VMStateField[]) { + VMSTATE_USB_DEVICE(dev, USBRedirDevice), + VMSTATE_TIMER(attach_timer, USBRedirDevice), + { + .name = "parser", + .version_id = 0, + .field_exists = NULL, + .size = 0, + .info = &usbredir_parser_vmstate_info, + .flags = VMS_SINGLE, + .offset = 0, + }, + VMSTATE_STRUCT_ARRAY(endpoint, USBRedirDevice, MAX_ENDPOINTS, 1, + usbredir_ep_vmstate, struct endp_data), + VMSTATE_STRUCT(cancelled, USBRedirDevice, 1, + usbredir_ep_packet_id_queue_vmstate, + struct PacketIdQueue), + VMSTATE_STRUCT(already_in_flight, USBRedirDevice, 1, + usbredir_ep_packet_id_queue_vmstate, + struct PacketIdQueue), + VMSTATE_STRUCT(device_info, USBRedirDevice, 1, + usbredir_device_info_vmstate, + struct usb_redir_device_connect_header), + VMSTATE_STRUCT(interface_info, USBRedirDevice, 1, + usbredir_interface_info_vmstate, + struct usb_redir_interface_info_header), + VMSTATE_END_OF_LIST() + } +}; + static Property usbredir_properties[] = { DEFINE_PROP_CHR("chardev", USBRedirDevice, cs), - DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0), + DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, usbredirparser_warning), DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str), DEFINE_PROP_INT32("bootindex", USBRedirDevice, bootindex, -1), DEFINE_PROP_END_OF_LIST(), @@ -1483,6 +2335,9 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) uc->handle_reset = usbredir_handle_reset; uc->handle_data = usbredir_handle_data; uc->handle_control = usbredir_handle_control; + uc->flush_ep_queue = usbredir_flush_ep_queue; + uc->ep_stopped = usbredir_ep_stopped; + dc->vmsd = &usbredir_vmstate; dc->props = usbredir_properties; } diff --git a/hw/versatile_i2c.c b/hw/versatile_i2c.c index 88f530aefc..ad71e9d92d 100644 --- a/hw/versatile_i2c.c +++ b/hw/versatile_i2c.c @@ -32,7 +32,7 @@ typedef struct { int in; } VersatileI2CState; -static uint64_t versatile_i2c_read(void *opaque, target_phys_addr_t offset, +static uint64_t versatile_i2c_read(void *opaque, hwaddr offset, unsigned size) { VersatileI2CState *s = (VersatileI2CState *)opaque; @@ -40,12 +40,13 @@ static uint64_t versatile_i2c_read(void *opaque, target_phys_addr_t offset, if (offset == 0) { return (s->out & 1) | (s->in << 1); } else { - hw_error("%s: Bad offset 0x%x\n", __func__, (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%x\n", __func__, (int)offset); return -1; } } -static void versatile_i2c_write(void *opaque, target_phys_addr_t offset, +static void versatile_i2c_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { VersatileI2CState *s = (VersatileI2CState *)opaque; @@ -58,7 +59,8 @@ static void versatile_i2c_write(void *opaque, target_phys_addr_t offset, s->out &= ~value; break; default: - hw_error("%s: Bad offset 0x%x\n", __func__, (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%x\n", __func__, (int)offset); } bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0); s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0); diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index ae53a8b37b..1f4d66934c 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -8,9 +8,9 @@ */ #include "sysbus.h" -#include "pci.h" -#include "pci_host.h" -#include "exec-memory.h" +#include "pci/pci.h" +#include "pci/pci_host.h" +#include "exec/address-spaces.h" typedef struct { SysBusDevice busdev; @@ -21,18 +21,18 @@ typedef struct { MemoryRegion isa; } PCIVPBState; -static inline uint32_t vpb_pci_config_addr(target_phys_addr_t addr) +static inline uint32_t vpb_pci_config_addr(hwaddr addr) { return addr & 0xffffff; } -static void pci_vpb_config_write(void *opaque, target_phys_addr_t addr, +static void pci_vpb_config_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { pci_data_write(opaque, vpb_pci_config_addr(addr), val, size); } -static uint64_t pci_vpb_config_read(void *opaque, target_phys_addr_t addr, +static uint64_t pci_vpb_config_read(void *opaque, hwaddr addr, unsigned size) { uint32_t val; diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 7a92034718..5e89e747a2 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -10,13 +10,13 @@ #include "sysbus.h" #include "arm-misc.h" #include "devices.h" -#include "net.h" -#include "sysemu.h" -#include "pci.h" +#include "net/net.h" +#include "sysemu/sysemu.h" +#include "pci/pci.h" #include "i2c.h" #include "boards.h" -#include "blockdev.h" -#include "exec-memory.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" #include "flash.h" #define VERSATILE_FLASH_ADDR 0x34000000 @@ -81,7 +81,7 @@ static void vpb_sic_set_irq(void *opaque, int irq, int level) vpb_sic_update(s); } -static uint64_t vpb_sic_read(void *opaque, target_phys_addr_t offset, +static uint64_t vpb_sic_read(void *opaque, hwaddr offset, unsigned size) { vpb_sic_state *s = (vpb_sic_state *)opaque; @@ -103,7 +103,7 @@ static uint64_t vpb_sic_read(void *opaque, target_phys_addr_t offset, } } -static void vpb_sic_write(void *opaque, target_phys_addr_t offset, +static void vpb_sic_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { vpb_sic_state *s = (vpb_sic_state *)opaque; @@ -167,11 +167,7 @@ static int vpb_sic_init(SysBusDevice *dev) static struct arm_boot_info versatile_binfo; -static void versatile_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model, - int board_id) +static void versatile_init(QEMUMachineInitArgs *args, int board_id) { ARMCPU *cpu; MemoryRegion *sysmem = get_system_memory(); @@ -189,15 +185,15 @@ static void versatile_init(ram_addr_t ram_size, int done_smc = 0; DriveInfo *dinfo; - if (!cpu_model) { - cpu_model = "arm926"; + if (!args->cpu_model) { + args->cpu_model = "arm926"; } - cpu = cpu_arm_init(cpu_model); + cpu = cpu_arm_init(args->cpu_model); if (!cpu) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } - memory_region_init_ram(ram, "versatile.ram", ram_size); + memory_region_init_ram(ram, "versatile.ram", args->ram_size); vmstate_register_ram_global(ram); /* ??? RAM should repeat to fill physical memory space. */ /* SDRAM at address zero. */ @@ -211,7 +207,8 @@ static void versatile_init(ram_addr_t ram_size, cpu_pic = arm_pic_init_cpu(cpu); dev = sysbus_create_varargs("pl190", 0x10140000, - cpu_pic[0], cpu_pic[1], NULL); + cpu_pic[ARM_PIC_CPU_IRQ], + cpu_pic[ARM_PIC_CPU_FIQ], NULL); for (n = 0; n < 32; n++) { pic[n] = qdev_get_gpio_in(dev, n); } @@ -247,7 +244,7 @@ static void versatile_init(ram_addr_t ram_size, pci_nic_init_nofail(nd, "rtl8139", NULL); } } - if (usb_enabled) { + if (usb_enabled(false)) { pci_create_simple(pci_bus, -1, "pci-ohci"); } n = drive_get_max_bus(IF_SCSI); @@ -265,6 +262,11 @@ static void versatile_init(ram_addr_t ram_size, sysbus_create_simple("sp804", 0x101e2000, pic[4]); sysbus_create_simple("sp804", 0x101e3000, pic[5]); + sysbus_create_simple("pl061", 0x101e4000, pic[6]); + sysbus_create_simple("pl061", 0x101e5000, pic[7]); + sysbus_create_simple("pl061", 0x101e6000, pic[8]); + sysbus_create_simple("pl061", 0x101e7000, pic[9]); + /* The versatile/PB actually has a modified Color LCD controller that includes hardware cursor support from the PL111. */ dev = sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]); @@ -334,48 +336,36 @@ static void versatile_init(ram_addr_t ram_size, fprintf(stderr, "qemu: Error registering flash memory.\n"); } - versatile_binfo.ram_size = ram_size; - versatile_binfo.kernel_filename = kernel_filename; - versatile_binfo.kernel_cmdline = kernel_cmdline; - versatile_binfo.initrd_filename = initrd_filename; + versatile_binfo.ram_size = args->ram_size; + versatile_binfo.kernel_filename = args->kernel_filename; + versatile_binfo.kernel_cmdline = args->kernel_cmdline; + versatile_binfo.initrd_filename = args->initrd_filename; versatile_binfo.board_id = board_id; arm_load_kernel(cpu, &versatile_binfo); } -static void vpb_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void vpb_init(QEMUMachineInitArgs *args) { - versatile_init(ram_size, - boot_device, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, 0x183); + versatile_init(args, 0x183); } -static void vab_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void vab_init(QEMUMachineInitArgs *args) { - versatile_init(ram_size, - boot_device, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, 0x25e); + versatile_init(args, 0x25e); } static QEMUMachine versatilepb_machine = { .name = "versatilepb", .desc = "ARM Versatile/PB (ARM926EJ-S)", .init = vpb_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, }; static QEMUMachine versatileab_machine = { .name = "versatileab", .desc = "ARM Versatile/AB (ARM926EJ-S)", .init = vab_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, }; static void versatile_machine_init(void) diff --git a/hw/vexpress.c b/hw/vexpress.c index b6158447d7..93c3176667 100644 --- a/hw/vexpress.c +++ b/hw/vexpress.c @@ -25,12 +25,16 @@ #include "arm-misc.h" #include "primecell.h" #include "devices.h" -#include "net.h" -#include "sysemu.h" +#include "net/net.h" +#include "sysemu/sysemu.h" #include "boards.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" +#include "sysemu/blockdev.h" +#include "flash.h" #define VEXPRESS_BOARD_ID 0x8e0 +#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024) +#define VEXPRESS_FLASH_SECT_SIZE (256 * 1024) static struct arm_boot_info vexpress_binfo; @@ -62,7 +66,6 @@ enum { VE_COMPACTFLASH, VE_CLCD, VE_NORFLASH0, - VE_NORFLASH0ALIAS, VE_NORFLASH1, VE_SRAM, VE_VIDEORAM, @@ -71,7 +74,7 @@ enum { VE_DAPROM, }; -static target_phys_addr_t motherboard_legacy_map[] = { +static hwaddr motherboard_legacy_map[] = { /* CS7: 0x10000000 .. 0x10020000 */ [VE_SYSREGS] = 0x10000000, [VE_SP810] = 0x10001000, @@ -103,10 +106,9 @@ static target_phys_addr_t motherboard_legacy_map[] = { [VE_USB] = 0x4f000000, }; -static target_phys_addr_t motherboard_aseries_map[] = { - /* CS0: 0x00000000 .. 0x0c000000 */ - [VE_NORFLASH0] = 0x00000000, - [VE_NORFLASH0ALIAS] = 0x08000000, +static hwaddr motherboard_aseries_map[] = { + /* CS0: 0x08000000 .. 0x0c000000 */ + [VE_NORFLASH0] = 0x08000000, /* CS4: 0x0c000000 .. 0x10000000 */ [VE_NORFLASH1] = 0x0c000000, /* CS5: 0x10000000 .. 0x14000000 */ @@ -148,9 +150,9 @@ typedef void DBoardInitFn(const VEDBoardInfo *daughterboard, qemu_irq *pic, uint32_t *proc_id); struct VEDBoardInfo { - const target_phys_addr_t *motherboard_map; - target_phys_addr_t loader_start; - const target_phys_addr_t gic_cpu_if_addr; + const hwaddr *motherboard_map; + hwaddr loader_start; + const hwaddr gic_cpu_if_addr; DBoardInitFn *init; }; @@ -346,24 +348,21 @@ static const VEDBoardInfo a15_daughterboard = { }; static void vexpress_common_init(const VEDBoardInfo *daughterboard, - ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) + QEMUMachineInitArgs *args) { DeviceState *dev, *sysctl, *pl041; qemu_irq pic[64]; uint32_t proc_id; uint32_t sys_id; + DriveInfo *dinfo; ram_addr_t vram_size, sram_size; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *vram = g_new(MemoryRegion, 1); MemoryRegion *sram = g_new(MemoryRegion, 1); - const target_phys_addr_t *map = daughterboard->motherboard_map; + const hwaddr *map = daughterboard->motherboard_map; - daughterboard->init(daughterboard, ram_size, cpu_model, pic, &proc_id); + daughterboard->init(daughterboard, args->ram_size, args->cpu_model, + pic, &proc_id); /* Motherboard peripherals: the wiring is the same but the * addresses vary between the legacy and A-Series memory maps. @@ -412,9 +411,25 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, sysbus_create_simple("pl111", map[VE_CLCD], pic[14]); - /* VE_NORFLASH0: not modelled */ - /* VE_NORFLASH0ALIAS: not modelled */ - /* VE_NORFLASH1: not modelled */ + dinfo = drive_get_next(IF_PFLASH); + if (!pflash_cfi01_register(map[VE_NORFLASH0], NULL, "vexpress.flash0", + VEXPRESS_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL, + VEXPRESS_FLASH_SECT_SIZE, + VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE, 4, + 0x00, 0x89, 0x00, 0x18, 0)) { + fprintf(stderr, "vexpress: error registering flash 0.\n"); + exit(1); + } + + dinfo = drive_get_next(IF_PFLASH); + if (!pflash_cfi01_register(map[VE_NORFLASH1], NULL, "vexpress.flash1", + VEXPRESS_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL, + VEXPRESS_FLASH_SECT_SIZE, + VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE, 4, + 0x00, 0x89, 0x00, 0x18, 0)) { + fprintf(stderr, "vexpress: error registering flash 1.\n"); + exit(1); + } sram_size = 0x2000000; memory_region_init_ram(sram, "vexpress.sram", sram_size); @@ -435,10 +450,10 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, /* VE_DAPROM: not modelled */ - vexpress_binfo.ram_size = ram_size; - vexpress_binfo.kernel_filename = kernel_filename; - vexpress_binfo.kernel_cmdline = kernel_cmdline; - vexpress_binfo.initrd_filename = initrd_filename; + vexpress_binfo.ram_size = args->ram_size; + vexpress_binfo.kernel_filename = args->kernel_filename; + vexpress_binfo.kernel_cmdline = args->kernel_cmdline; + vexpress_binfo.initrd_filename = args->initrd_filename; vexpress_binfo.nb_cpus = smp_cpus; vexpress_binfo.board_id = VEXPRESS_BOARD_ID; vexpress_binfo.loader_start = daughterboard->loader_start; @@ -448,35 +463,21 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, arm_load_kernel(arm_env_get_cpu(first_cpu), &vexpress_binfo); } -static void vexpress_a9_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void vexpress_a9_init(QEMUMachineInitArgs *args) { - vexpress_common_init(&a9_daughterboard, - ram_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); + vexpress_common_init(&a9_daughterboard, args); } -static void vexpress_a15_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void vexpress_a15_init(QEMUMachineInitArgs *args) { - vexpress_common_init(&a15_daughterboard, - ram_size, boot_device, kernel_filename, - kernel_cmdline, initrd_filename, cpu_model); + vexpress_common_init(&a15_daughterboard, args); } static QEMUMachine vexpress_a9_machine = { .name = "vexpress-a9", .desc = "ARM Versatile Express for Cortex-A9", .init = vexpress_a9_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, .max_cpus = 4, }; @@ -484,7 +485,7 @@ static QEMUMachine vexpress_a15_machine = { .name = "vexpress-a15", .desc = "ARM Versatile Express for Cortex-A15", .init = vexpress_a15_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, .max_cpus = 4, }; diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c new file mode 100644 index 0000000000..c51ae6761b --- /dev/null +++ b/hw/vfio_pci.c @@ -0,0 +1,2138 @@ +/* + * vfio based device assignment support + * + * Copyright Red Hat, Inc. 2012 + * + * Authors: + * Alex Williamson <alex.williamson@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Based on qemu-kvm device-assignment: + * Adapted for KVM by Qumranet. + * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com) + * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com) + * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com) + * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com) + * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com) + */ + +#include <dirent.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <linux/vfio.h> + +#include "config.h" +#include "qemu/event_notifier.h" +#include "exec/address-spaces.h" +#include "sysemu/kvm.h" +#include "exec/memory.h" +#include "pci/msi.h" +#include "pci/msix.h" +#include "pci/pci.h" +#include "qemu-common.h" +#include "qemu/error-report.h" +#include "qemu/queue.h" +#include "qemu/range.h" + +/* #define DEBUG_VFIO */ +#ifdef DEBUG_VFIO +#define DPRINTF(fmt, ...) \ + do { fprintf(stderr, "vfio: " fmt, ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) \ + do { } while (0) +#endif + +typedef struct VFIOBAR { + off_t fd_offset; /* offset of BAR within device fd */ + int fd; /* device fd, allows us to pass VFIOBAR as opaque data */ + MemoryRegion mem; /* slow, read/write access */ + MemoryRegion mmap_mem; /* direct mapped access */ + void *mmap; + size_t size; + uint32_t flags; /* VFIO region flags (rd/wr/mmap) */ + uint8_t nr; /* cache the BAR number for debug */ +} VFIOBAR; + +typedef struct VFIOINTx { + bool pending; /* interrupt pending */ + bool kvm_accel; /* set when QEMU bypass through KVM enabled */ + uint8_t pin; /* which pin to pull for qemu_set_irq */ + EventNotifier interrupt; /* eventfd triggered on interrupt */ + EventNotifier unmask; /* eventfd for unmask on QEMU bypass */ + PCIINTxRoute route; /* routing info for QEMU bypass */ + uint32_t mmap_timeout; /* delay to re-enable mmaps after interrupt */ + QEMUTimer *mmap_timer; /* enable mmaps after periods w/o interrupts */ +} VFIOINTx; + +struct VFIODevice; + +typedef struct VFIOMSIVector { + EventNotifier interrupt; /* eventfd triggered on interrupt */ + struct VFIODevice *vdev; /* back pointer to device */ + int virq; /* KVM irqchip route for QEMU bypass */ + bool use; +} VFIOMSIVector; + +enum { + VFIO_INT_NONE = 0, + VFIO_INT_INTx = 1, + VFIO_INT_MSI = 2, + VFIO_INT_MSIX = 3, +}; + +struct VFIOGroup; + +typedef struct VFIOContainer { + int fd; /* /dev/vfio/vfio, empowered by the attached groups */ + struct { + /* enable abstraction to support various iommu backends */ + union { + MemoryListener listener; /* Used by type1 iommu */ + }; + void (*release)(struct VFIOContainer *); + } iommu_data; + QLIST_HEAD(, VFIOGroup) group_list; + QLIST_ENTRY(VFIOContainer) next; +} VFIOContainer; + +/* Cache of MSI-X setup plus extra mmap and memory region for split BAR map */ +typedef struct VFIOMSIXInfo { + uint8_t table_bar; + uint8_t pba_bar; + uint16_t entries; + uint32_t table_offset; + uint32_t pba_offset; + MemoryRegion mmap_mem; + void *mmap; +} VFIOMSIXInfo; + +typedef struct VFIODevice { + PCIDevice pdev; + int fd; + VFIOINTx intx; + unsigned int config_size; + off_t config_offset; /* Offset of config space region within device fd */ + unsigned int rom_size; + off_t rom_offset; /* Offset of ROM region within device fd */ + int msi_cap_size; + VFIOMSIVector *msi_vectors; + VFIOMSIXInfo *msix; + int nr_vectors; /* Number of MSI/MSIX vectors currently in use */ + int interrupt; /* Current interrupt type */ + VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */ + PCIHostDeviceAddress host; + QLIST_ENTRY(VFIODevice) next; + struct VFIOGroup *group; + bool reset_works; +} VFIODevice; + +typedef struct VFIOGroup { + int fd; + int groupid; + VFIOContainer *container; + QLIST_HEAD(, VFIODevice) device_list; + QLIST_ENTRY(VFIOGroup) next; + QLIST_ENTRY(VFIOGroup) container_next; +} VFIOGroup; + +#define MSIX_CAP_LENGTH 12 + +static QLIST_HEAD(, VFIOContainer) + container_list = QLIST_HEAD_INITIALIZER(container_list); + +static QLIST_HEAD(, VFIOGroup) + group_list = QLIST_HEAD_INITIALIZER(group_list); + +static void vfio_disable_interrupts(VFIODevice *vdev); +static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len); +static void vfio_mmap_set_enabled(VFIODevice *vdev, bool enabled); + +/* + * Common VFIO interrupt disable + */ +static void vfio_disable_irqindex(VFIODevice *vdev, int index) +{ + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER, + .index = index, + .start = 0, + .count = 0, + }; + + ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); +} + +/* + * INTx + */ +static void vfio_unmask_intx(VFIODevice *vdev) +{ + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK, + .index = VFIO_PCI_INTX_IRQ_INDEX, + .start = 0, + .count = 1, + }; + + ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); +} + +#ifdef CONFIG_KVM /* Unused outside of CONFIG_KVM code */ +static void vfio_mask_intx(VFIODevice *vdev) +{ + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK, + .index = VFIO_PCI_INTX_IRQ_INDEX, + .start = 0, + .count = 1, + }; + + ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); +} +#endif + +/* + * Disabling BAR mmaping can be slow, but toggling it around INTx can + * also be a huge overhead. We try to get the best of both worlds by + * waiting until an interrupt to disable mmaps (subsequent transitions + * to the same state are effectively no overhead). If the interrupt has + * been serviced and the time gap is long enough, we re-enable mmaps for + * performance. This works well for things like graphics cards, which + * may not use their interrupt at all and are penalized to an unusable + * level by read/write BAR traps. Other devices, like NICs, have more + * regular interrupts and see much better latency by staying in non-mmap + * mode. We therefore set the default mmap_timeout such that a ping + * is just enough to keep the mmap disabled. Users can experiment with + * other options with the x-intx-mmap-timeout-ms parameter (a value of + * zero disables the timer). + */ +static void vfio_intx_mmap_enable(void *opaque) +{ + VFIODevice *vdev = opaque; + + if (vdev->intx.pending) { + qemu_mod_timer(vdev->intx.mmap_timer, + qemu_get_clock_ms(vm_clock) + vdev->intx.mmap_timeout); + return; + } + + vfio_mmap_set_enabled(vdev, true); +} + +static void vfio_intx_interrupt(void *opaque) +{ + VFIODevice *vdev = opaque; + + if (!event_notifier_test_and_clear(&vdev->intx.interrupt)) { + return; + } + + DPRINTF("%s(%04x:%02x:%02x.%x) Pin %c\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function, + 'A' + vdev->intx.pin); + + vdev->intx.pending = true; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 1); + vfio_mmap_set_enabled(vdev, false); + if (vdev->intx.mmap_timeout) { + qemu_mod_timer(vdev->intx.mmap_timer, + qemu_get_clock_ms(vm_clock) + vdev->intx.mmap_timeout); + } +} + +static void vfio_eoi(VFIODevice *vdev) +{ + if (!vdev->intx.pending) { + return; + } + + DPRINTF("%s(%04x:%02x:%02x.%x) EOI\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + + vdev->intx.pending = false; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); + vfio_unmask_intx(vdev); +} + +static void vfio_enable_intx_kvm(VFIODevice *vdev) +{ +#ifdef CONFIG_KVM + struct kvm_irqfd irqfd = { + .fd = event_notifier_get_fd(&vdev->intx.interrupt), + .gsi = vdev->intx.route.irq, + .flags = KVM_IRQFD_FLAG_RESAMPLE, + }; + struct vfio_irq_set *irq_set; + int ret, argsz; + int32_t *pfd; + + if (!kvm_irqfds_enabled() || + vdev->intx.route.mode != PCI_INTX_ENABLED || + !kvm_check_extension(kvm_state, KVM_CAP_IRQFD_RESAMPLE)) { + return; + } + + /* Get to a known interrupt state */ + qemu_set_fd_handler(irqfd.fd, NULL, NULL, vdev); + vfio_mask_intx(vdev); + vdev->intx.pending = false; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); + + /* Get an eventfd for resample/unmask */ + if (event_notifier_init(&vdev->intx.unmask, 0)) { + error_report("vfio: Error: event_notifier_init failed eoi\n"); + goto fail; + } + + /* KVM triggers it, VFIO listens for it */ + irqfd.resamplefd = event_notifier_get_fd(&vdev->intx.unmask); + + if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) { + error_report("vfio: Error: Failed to setup resample irqfd: %m\n"); + goto fail_irqfd; + } + + argsz = sizeof(*irq_set) + sizeof(*pfd); + + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK; + irq_set->index = VFIO_PCI_INTX_IRQ_INDEX; + irq_set->start = 0; + irq_set->count = 1; + pfd = (int32_t *)&irq_set->data; + + *pfd = irqfd.resamplefd; + + ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); + g_free(irq_set); + if (ret) { + error_report("vfio: Error: Failed to setup INTx unmask fd: %m\n"); + goto fail_vfio; + } + + /* Let'em rip */ + vfio_unmask_intx(vdev); + + vdev->intx.kvm_accel = true; + + DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel enabled\n", + __func__, vdev->host.domain, vdev->host.bus, + vdev->host.slot, vdev->host.function); + + return; + +fail_vfio: + irqfd.flags = KVM_IRQFD_FLAG_DEASSIGN; + kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd); +fail_irqfd: + event_notifier_cleanup(&vdev->intx.unmask); +fail: + qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev); + vfio_unmask_intx(vdev); +#endif +} + +static void vfio_disable_intx_kvm(VFIODevice *vdev) +{ +#ifdef CONFIG_KVM + struct kvm_irqfd irqfd = { + .fd = event_notifier_get_fd(&vdev->intx.interrupt), + .gsi = vdev->intx.route.irq, + .flags = KVM_IRQFD_FLAG_DEASSIGN, + }; + + if (!vdev->intx.kvm_accel) { + return; + } + + /* + * Get to a known state, hardware masked, QEMU ready to accept new + * interrupts, QEMU IRQ de-asserted. + */ + vfio_mask_intx(vdev); + vdev->intx.pending = false; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); + + /* Tell KVM to stop listening for an INTx irqfd */ + if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) { + error_report("vfio: Error: Failed to disable INTx irqfd: %m\n"); + } + + /* We only need to close the eventfd for VFIO to cleanup the kernel side */ + event_notifier_cleanup(&vdev->intx.unmask); + + /* QEMU starts listening for interrupt events. */ + qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev); + + vdev->intx.kvm_accel = false; + + /* If we've missed an event, let it re-fire through QEMU */ + vfio_unmask_intx(vdev); + + DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel disabled\n", + __func__, vdev->host.domain, vdev->host.bus, + vdev->host.slot, vdev->host.function); +#endif +} + +static void vfio_update_irq(PCIDevice *pdev) +{ + VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); + PCIINTxRoute route; + + if (vdev->interrupt != VFIO_INT_INTx) { + return; + } + + route = pci_device_route_intx_to_irq(&vdev->pdev, vdev->intx.pin); + + if (!pci_intx_route_changed(&vdev->intx.route, &route)) { + return; /* Nothing changed */ + } + + DPRINTF("%s(%04x:%02x:%02x.%x) IRQ moved %d -> %d\n", __func__, + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function, vdev->intx.route.irq, route.irq); + + vfio_disable_intx_kvm(vdev); + + vdev->intx.route = route; + + if (route.mode != PCI_INTX_ENABLED) { + return; + } + + vfio_enable_intx_kvm(vdev); + + /* Re-enable the interrupt in cased we missed an EOI */ + vfio_eoi(vdev); +} + +static int vfio_enable_intx(VFIODevice *vdev) +{ + uint8_t pin = vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1); + int ret, argsz; + struct vfio_irq_set *irq_set; + int32_t *pfd; + + if (!pin) { + return 0; + } + + vfio_disable_interrupts(vdev); + + vdev->intx.pin = pin - 1; /* Pin A (1) -> irq[0] */ + +#ifdef CONFIG_KVM + /* + * Only conditional to avoid generating error messages on platforms + * where we won't actually use the result anyway. + */ + if (kvm_irqfds_enabled() && + kvm_check_extension(kvm_state, KVM_CAP_IRQFD_RESAMPLE)) { + vdev->intx.route = pci_device_route_intx_to_irq(&vdev->pdev, + vdev->intx.pin); + } +#endif + + ret = event_notifier_init(&vdev->intx.interrupt, 0); + if (ret) { + error_report("vfio: Error: event_notifier_init failed\n"); + return ret; + } + + argsz = sizeof(*irq_set) + sizeof(*pfd); + + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_INTX_IRQ_INDEX; + irq_set->start = 0; + irq_set->count = 1; + pfd = (int32_t *)&irq_set->data; + + *pfd = event_notifier_get_fd(&vdev->intx.interrupt); + qemu_set_fd_handler(*pfd, vfio_intx_interrupt, NULL, vdev); + + ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); + g_free(irq_set); + if (ret) { + error_report("vfio: Error: Failed to setup INTx fd: %m\n"); + qemu_set_fd_handler(*pfd, NULL, NULL, vdev); + event_notifier_cleanup(&vdev->intx.interrupt); + return -errno; + } + + vfio_enable_intx_kvm(vdev); + + vdev->interrupt = VFIO_INT_INTx; + + DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + + return 0; +} + +static void vfio_disable_intx(VFIODevice *vdev) +{ + int fd; + + qemu_del_timer(vdev->intx.mmap_timer); + vfio_disable_intx_kvm(vdev); + vfio_disable_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); + vdev->intx.pending = false; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); + vfio_mmap_set_enabled(vdev, true); + + fd = event_notifier_get_fd(&vdev->intx.interrupt); + qemu_set_fd_handler(fd, NULL, NULL, vdev); + event_notifier_cleanup(&vdev->intx.interrupt); + + vdev->interrupt = VFIO_INT_NONE; + + DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); +} + +/* + * MSI/X + */ +static void vfio_msi_interrupt(void *opaque) +{ + VFIOMSIVector *vector = opaque; + VFIODevice *vdev = vector->vdev; + int nr = vector - vdev->msi_vectors; + + if (!event_notifier_test_and_clear(&vector->interrupt)) { + return; + } + + DPRINTF("%s(%04x:%02x:%02x.%x) vector %d\n", __func__, + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function, nr); + + if (vdev->interrupt == VFIO_INT_MSIX) { + msix_notify(&vdev->pdev, nr); + } else if (vdev->interrupt == VFIO_INT_MSI) { + msi_notify(&vdev->pdev, nr); + } else { + error_report("vfio: MSI interrupt receieved, but not enabled?\n"); + } +} + +static int vfio_enable_vectors(VFIODevice *vdev, bool msix) +{ + struct vfio_irq_set *irq_set; + int ret = 0, i, argsz; + int32_t *fds; + + argsz = sizeof(*irq_set) + (vdev->nr_vectors * sizeof(*fds)); + + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = msix ? VFIO_PCI_MSIX_IRQ_INDEX : VFIO_PCI_MSI_IRQ_INDEX; + irq_set->start = 0; + irq_set->count = vdev->nr_vectors; + fds = (int32_t *)&irq_set->data; + + for (i = 0; i < vdev->nr_vectors; i++) { + if (!vdev->msi_vectors[i].use) { + fds[i] = -1; + continue; + } + + fds[i] = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt); + } + + ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); + + g_free(irq_set); + + return ret; +} + +static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, + MSIMessage *msg, IOHandler *handler) +{ + VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); + VFIOMSIVector *vector; + int ret; + + DPRINTF("%s(%04x:%02x:%02x.%x) vector %d used\n", __func__, + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function, nr); + + vector = &vdev->msi_vectors[nr]; + vector->vdev = vdev; + vector->use = true; + + msix_vector_use(pdev, nr); + + if (event_notifier_init(&vector->interrupt, 0)) { + error_report("vfio: Error: event_notifier_init failed\n"); + } + + /* + * Attempt to enable route through KVM irqchip, + * default to userspace handling if unavailable. + */ + vector->virq = msg ? kvm_irqchip_add_msi_route(kvm_state, *msg) : -1; + if (vector->virq < 0 || + kvm_irqchip_add_irqfd_notifier(kvm_state, &vector->interrupt, + vector->virq) < 0) { + if (vector->virq >= 0) { + kvm_irqchip_release_virq(kvm_state, vector->virq); + vector->virq = -1; + } + qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt), + handler, NULL, vector); + } + + /* + * We don't want to have the host allocate all possible MSI vectors + * for a device if they're not in use, so we shutdown and incrementally + * increase them as needed. + */ + if (vdev->nr_vectors < nr + 1) { + vfio_disable_irqindex(vdev, VFIO_PCI_MSIX_IRQ_INDEX); + vdev->nr_vectors = nr + 1; + ret = vfio_enable_vectors(vdev, true); + if (ret) { + error_report("vfio: failed to enable vectors, %d\n", ret); + } + } else { + int argsz; + struct vfio_irq_set *irq_set; + int32_t *pfd; + + argsz = sizeof(*irq_set) + sizeof(*pfd); + + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; + irq_set->start = nr; + irq_set->count = 1; + pfd = (int32_t *)&irq_set->data; + + *pfd = event_notifier_get_fd(&vector->interrupt); + + ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); + g_free(irq_set); + if (ret) { + error_report("vfio: failed to modify vector, %d\n", ret); + } + } + + return 0; +} + +static int vfio_msix_vector_use(PCIDevice *pdev, + unsigned int nr, MSIMessage msg) +{ + return vfio_msix_vector_do_use(pdev, nr, &msg, vfio_msi_interrupt); +} + +static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) +{ + VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); + VFIOMSIVector *vector = &vdev->msi_vectors[nr]; + int argsz; + struct vfio_irq_set *irq_set; + int32_t *pfd; + + DPRINTF("%s(%04x:%02x:%02x.%x) vector %d released\n", __func__, + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function, nr); + + /* + * XXX What's the right thing to do here? This turns off the interrupt + * completely, but do we really just want to switch the interrupt to + * bouncing through userspace and let msix.c drop it? Not sure. + */ + msix_vector_unuse(pdev, nr); + + argsz = sizeof(*irq_set) + sizeof(*pfd); + + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | + VFIO_IRQ_SET_ACTION_TRIGGER; + irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; + irq_set->start = nr; + irq_set->count = 1; + pfd = (int32_t *)&irq_set->data; + + *pfd = -1; + + ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); + + g_free(irq_set); + + if (vector->virq < 0) { + qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt), + NULL, NULL, NULL); + } else { + kvm_irqchip_remove_irqfd_notifier(kvm_state, &vector->interrupt, + vector->virq); + kvm_irqchip_release_virq(kvm_state, vector->virq); + vector->virq = -1; + } + + event_notifier_cleanup(&vector->interrupt); + vector->use = false; +} + +static void vfio_enable_msix(VFIODevice *vdev) +{ + vfio_disable_interrupts(vdev); + + vdev->msi_vectors = g_malloc0(vdev->msix->entries * sizeof(VFIOMSIVector)); + + vdev->interrupt = VFIO_INT_MSIX; + + /* + * Some communication channels between VF & PF or PF & fw rely on the + * physical state of the device and expect that enabling MSI-X from the + * guest enables the same on the host. When our guest is Linux, the + * guest driver call to pci_enable_msix() sets the enabling bit in the + * MSI-X capability, but leaves the vector table masked. We therefore + * can't rely on a vector_use callback (from request_irq() in the guest) + * to switch the physical device into MSI-X mode because that may come a + * long time after pci_enable_msix(). This code enables vector 0 with + * triggering to userspace, then immediately release the vector, leaving + * the physical device with no vectors enabled, but MSI-X enabled, just + * like the guest view. + */ + vfio_msix_vector_do_use(&vdev->pdev, 0, NULL, NULL); + vfio_msix_vector_release(&vdev->pdev, 0); + + if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use, + vfio_msix_vector_release, NULL)) { + error_report("vfio: msix_set_vector_notifiers failed\n"); + } + + DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); +} + +static void vfio_enable_msi(VFIODevice *vdev) +{ + int ret, i; + + vfio_disable_interrupts(vdev); + + vdev->nr_vectors = msi_nr_vectors_allocated(&vdev->pdev); +retry: + vdev->msi_vectors = g_malloc0(vdev->nr_vectors * sizeof(VFIOMSIVector)); + + for (i = 0; i < vdev->nr_vectors; i++) { + MSIMessage msg; + VFIOMSIVector *vector = &vdev->msi_vectors[i]; + + vector->vdev = vdev; + vector->use = true; + + if (event_notifier_init(&vector->interrupt, 0)) { + error_report("vfio: Error: event_notifier_init failed\n"); + } + + msg = msi_get_message(&vdev->pdev, i); + + /* + * Attempt to enable route through KVM irqchip, + * default to userspace handling if unavailable. + */ + vector->virq = kvm_irqchip_add_msi_route(kvm_state, msg); + if (vector->virq < 0 || + kvm_irqchip_add_irqfd_notifier(kvm_state, &vector->interrupt, + vector->virq) < 0) { + qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt), + vfio_msi_interrupt, NULL, vector); + } + } + + ret = vfio_enable_vectors(vdev, false); + if (ret) { + if (ret < 0) { + error_report("vfio: Error: Failed to setup MSI fds: %m\n"); + } else if (ret != vdev->nr_vectors) { + error_report("vfio: Error: Failed to enable %d " + "MSI vectors, retry with %d\n", vdev->nr_vectors, ret); + } + + for (i = 0; i < vdev->nr_vectors; i++) { + VFIOMSIVector *vector = &vdev->msi_vectors[i]; + if (vector->virq >= 0) { + kvm_irqchip_remove_irqfd_notifier(kvm_state, &vector->interrupt, + vector->virq); + kvm_irqchip_release_virq(kvm_state, vector->virq); + vector->virq = -1; + } else { + qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt), + NULL, NULL, NULL); + } + event_notifier_cleanup(&vector->interrupt); + } + + g_free(vdev->msi_vectors); + + if (ret > 0 && ret != vdev->nr_vectors) { + vdev->nr_vectors = ret; + goto retry; + } + vdev->nr_vectors = 0; + + return; + } + + vdev->interrupt = VFIO_INT_MSI; + + DPRINTF("%s(%04x:%02x:%02x.%x) Enabled %d MSI vectors\n", __func__, + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function, vdev->nr_vectors); +} + +static void vfio_disable_msi_common(VFIODevice *vdev) +{ + g_free(vdev->msi_vectors); + vdev->msi_vectors = NULL; + vdev->nr_vectors = 0; + vdev->interrupt = VFIO_INT_NONE; + + vfio_enable_intx(vdev); +} + +static void vfio_disable_msix(VFIODevice *vdev) +{ + msix_unset_vector_notifiers(&vdev->pdev); + + if (vdev->nr_vectors) { + vfio_disable_irqindex(vdev, VFIO_PCI_MSIX_IRQ_INDEX); + } + + vfio_disable_msi_common(vdev); + + DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); +} + +static void vfio_disable_msi(VFIODevice *vdev) +{ + int i; + + vfio_disable_irqindex(vdev, VFIO_PCI_MSI_IRQ_INDEX); + + for (i = 0; i < vdev->nr_vectors; i++) { + VFIOMSIVector *vector = &vdev->msi_vectors[i]; + + if (!vector->use) { + continue; + } + + if (vector->virq >= 0) { + kvm_irqchip_remove_irqfd_notifier(kvm_state, + &vector->interrupt, vector->virq); + kvm_irqchip_release_virq(kvm_state, vector->virq); + vector->virq = -1; + } else { + qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt), + NULL, NULL, NULL); + } + + event_notifier_cleanup(&vector->interrupt); + } + + vfio_disable_msi_common(vdev); + + DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); +} + +/* + * IO Port/MMIO - Beware of the endians, VFIO is always little endian + */ +static void vfio_bar_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + VFIOBAR *bar = opaque; + union { + uint8_t byte; + uint16_t word; + uint32_t dword; + uint64_t qword; + } buf; + + switch (size) { + case 1: + buf.byte = data; + break; + case 2: + buf.word = cpu_to_le16(data); + break; + case 4: + buf.dword = cpu_to_le32(data); + break; + default: + hw_error("vfio: unsupported write size, %d bytes\n", size); + break; + } + + if (pwrite(bar->fd, &buf, size, bar->fd_offset + addr) != size) { + error_report("%s(,0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m\n", + __func__, addr, data, size); + } + + DPRINTF("%s(BAR%d+0x%"HWADDR_PRIx", 0x%"PRIx64", %d)\n", + __func__, bar->nr, addr, data, size); + + /* + * A read or write to a BAR always signals an INTx EOI. This will + * do nothing if not pending (including not in INTx mode). We assume + * that a BAR access is in response to an interrupt and that BAR + * accesses will service the interrupt. Unfortunately, we don't know + * which access will service the interrupt, so we're potentially + * getting quite a few host interrupts per guest interrupt. + */ + vfio_eoi(container_of(bar, VFIODevice, bars[bar->nr])); +} + +static uint64_t vfio_bar_read(void *opaque, + hwaddr addr, unsigned size) +{ + VFIOBAR *bar = opaque; + union { + uint8_t byte; + uint16_t word; + uint32_t dword; + uint64_t qword; + } buf; + uint64_t data = 0; + + if (pread(bar->fd, &buf, size, bar->fd_offset + addr) != size) { + error_report("%s(,0x%"HWADDR_PRIx", %d) failed: %m\n", + __func__, addr, size); + return (uint64_t)-1; + } + + switch (size) { + case 1: + data = buf.byte; + break; + case 2: + data = le16_to_cpu(buf.word); + break; + case 4: + data = le32_to_cpu(buf.dword); + break; + default: + hw_error("vfio: unsupported read size, %d bytes\n", size); + break; + } + + DPRINTF("%s(BAR%d+0x%"HWADDR_PRIx", %d) = 0x%"PRIx64"\n", + __func__, bar->nr, addr, size, data); + + /* Same as write above */ + vfio_eoi(container_of(bar, VFIODevice, bars[bar->nr])); + + return data; +} + +static const MemoryRegionOps vfio_bar_ops = { + .read = vfio_bar_read, + .write = vfio_bar_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +/* + * PCI config space + */ +static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len) +{ + VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); + uint32_t val = 0; + + /* + * We only need QEMU PCI config support for the ROM BAR, the MSI and MSIX + * capabilities, and the multifunction bit below. We let VFIO handle + * virtualizing everything else. Performance is not a concern here. + */ + if (ranges_overlap(addr, len, PCI_ROM_ADDRESS, 4) || + (pdev->cap_present & QEMU_PCI_CAP_MSIX && + ranges_overlap(addr, len, pdev->msix_cap, MSIX_CAP_LENGTH)) || + (pdev->cap_present & QEMU_PCI_CAP_MSI && + ranges_overlap(addr, len, pdev->msi_cap, vdev->msi_cap_size))) { + + val = pci_default_read_config(pdev, addr, len); + } else { + if (pread(vdev->fd, &val, len, vdev->config_offset + addr) != len) { + error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m\n", + __func__, vdev->host.domain, vdev->host.bus, + vdev->host.slot, vdev->host.function, addr, len); + return -errno; + } + val = le32_to_cpu(val); + } + + /* Multifunction bit is virualized in QEMU */ + if (unlikely(ranges_overlap(addr, len, PCI_HEADER_TYPE, 1))) { + uint32_t mask = PCI_HEADER_TYPE_MULTI_FUNCTION; + + if (len == 4) { + mask <<= 16; + } + + if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { + val |= mask; + } else { + val &= ~mask; + } + } + + DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, len=0x%x) %x\n", __func__, + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function, addr, len, val); + + return val; +} + +static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, + uint32_t val, int len) +{ + VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); + uint32_t val_le = cpu_to_le32(val); + + DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, 0x%x, len=0x%x)\n", __func__, + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function, addr, val, len); + + /* Write everything to VFIO, let it filter out what we can't write */ + if (pwrite(vdev->fd, &val_le, len, vdev->config_offset + addr) != len) { + error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x, 0x%x) failed: %m\n", + __func__, vdev->host.domain, vdev->host.bus, + vdev->host.slot, vdev->host.function, addr, val, len); + } + + /* Write standard header bits to emulation */ + if (addr < PCI_CONFIG_HEADER_SIZE) { + pci_default_write_config(pdev, addr, val, len); + return; + } + + /* MSI/MSI-X Enabling/Disabling */ + if (pdev->cap_present & QEMU_PCI_CAP_MSI && + ranges_overlap(addr, len, pdev->msi_cap, vdev->msi_cap_size)) { + int is_enabled, was_enabled = msi_enabled(pdev); + + pci_default_write_config(pdev, addr, val, len); + + is_enabled = msi_enabled(pdev); + + if (!was_enabled && is_enabled) { + vfio_enable_msi(vdev); + } else if (was_enabled && !is_enabled) { + vfio_disable_msi(vdev); + } + } + + if (pdev->cap_present & QEMU_PCI_CAP_MSIX && + ranges_overlap(addr, len, pdev->msix_cap, MSIX_CAP_LENGTH)) { + int is_enabled, was_enabled = msix_enabled(pdev); + + pci_default_write_config(pdev, addr, val, len); + + is_enabled = msix_enabled(pdev); + + if (!was_enabled && is_enabled) { + vfio_enable_msix(vdev); + } else if (was_enabled && !is_enabled) { + vfio_disable_msix(vdev); + } + } +} + +/* + * DMA - Mapping and unmapping for the "type1" IOMMU interface used on x86 + */ +static int vfio_dma_unmap(VFIOContainer *container, + hwaddr iova, ram_addr_t size) +{ + struct vfio_iommu_type1_dma_unmap unmap = { + .argsz = sizeof(unmap), + .flags = 0, + .iova = iova, + .size = size, + }; + + if (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) { + DPRINTF("VFIO_UNMAP_DMA: %d\n", -errno); + return -errno; + } + + return 0; +} + +static int vfio_dma_map(VFIOContainer *container, hwaddr iova, + ram_addr_t size, void *vaddr, bool readonly) +{ + struct vfio_iommu_type1_dma_map map = { + .argsz = sizeof(map), + .flags = VFIO_DMA_MAP_FLAG_READ, + .vaddr = (__u64)(uintptr_t)vaddr, + .iova = iova, + .size = size, + }; + + if (!readonly) { + map.flags |= VFIO_DMA_MAP_FLAG_WRITE; + } + + /* + * Try the mapping, if it fails with EBUSY, unmap the region and try + * again. This shouldn't be necessary, but we sometimes see it in + * the the VGA ROM space. + */ + if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0 || + (errno == EBUSY && vfio_dma_unmap(container, iova, size) == 0 && + ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0)) { + return 0; + } + + DPRINTF("VFIO_MAP_DMA: %d\n", -errno); + return -errno; +} + +static bool vfio_listener_skipped_section(MemoryRegionSection *section) +{ + return !memory_region_is_ram(section->mr); +} + +static void vfio_listener_region_add(MemoryListener *listener, + MemoryRegionSection *section) +{ + VFIOContainer *container = container_of(listener, VFIOContainer, + iommu_data.listener); + hwaddr iova, end; + void *vaddr; + int ret; + + if (vfio_listener_skipped_section(section)) { + DPRINTF("vfio: SKIPPING region_add %"HWADDR_PRIx" - %"PRIx64"\n", + section->offset_within_address_space, + section->offset_within_address_space + section->size - 1); + return; + } + + if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) != + (section->offset_within_region & ~TARGET_PAGE_MASK))) { + error_report("%s received unaligned region\n", __func__); + return; + } + + iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); + end = (section->offset_within_address_space + section->size) & + TARGET_PAGE_MASK; + + if (iova >= end) { + return; + } + + vaddr = memory_region_get_ram_ptr(section->mr) + + section->offset_within_region + + (iova - section->offset_within_address_space); + + DPRINTF("vfio: region_add %"HWADDR_PRIx" - %"HWADDR_PRIx" [%p]\n", + iova, end - 1, vaddr); + + ret = vfio_dma_map(container, iova, end - iova, vaddr, section->readonly); + if (ret) { + error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", " + "0x%"HWADDR_PRIx", %p) = %d (%m)\n", + container, iova, end - iova, vaddr, ret); + } +} + +static void vfio_listener_region_del(MemoryListener *listener, + MemoryRegionSection *section) +{ + VFIOContainer *container = container_of(listener, VFIOContainer, + iommu_data.listener); + hwaddr iova, end; + int ret; + + if (vfio_listener_skipped_section(section)) { + DPRINTF("vfio: SKIPPING region_del %"HWADDR_PRIx" - %"PRIx64"\n", + section->offset_within_address_space, + section->offset_within_address_space + section->size - 1); + return; + } + + if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) != + (section->offset_within_region & ~TARGET_PAGE_MASK))) { + error_report("%s received unaligned region\n", __func__); + return; + } + + iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); + end = (section->offset_within_address_space + section->size) & + TARGET_PAGE_MASK; + + if (iova >= end) { + return; + } + + DPRINTF("vfio: region_del %"HWADDR_PRIx" - %"HWADDR_PRIx"\n", + iova, end - 1); + + ret = vfio_dma_unmap(container, iova, end - iova); + if (ret) { + error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " + "0x%"HWADDR_PRIx") = %d (%m)\n", + container, iova, end - iova, ret); + } +} + +static MemoryListener vfio_memory_listener = { + .region_add = vfio_listener_region_add, + .region_del = vfio_listener_region_del, +}; + +static void vfio_listener_release(VFIOContainer *container) +{ + memory_listener_unregister(&container->iommu_data.listener); +} + +/* + * Interrupt setup + */ +static void vfio_disable_interrupts(VFIODevice *vdev) +{ + switch (vdev->interrupt) { + case VFIO_INT_INTx: + vfio_disable_intx(vdev); + break; + case VFIO_INT_MSI: + vfio_disable_msi(vdev); + break; + case VFIO_INT_MSIX: + vfio_disable_msix(vdev); + break; + } +} + +static int vfio_setup_msi(VFIODevice *vdev, int pos) +{ + uint16_t ctrl; + bool msi_64bit, msi_maskbit; + int ret, entries; + + if (pread(vdev->fd, &ctrl, sizeof(ctrl), + vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) { + return -errno; + } + ctrl = le16_to_cpu(ctrl); + + msi_64bit = !!(ctrl & PCI_MSI_FLAGS_64BIT); + msi_maskbit = !!(ctrl & PCI_MSI_FLAGS_MASKBIT); + entries = 1 << ((ctrl & PCI_MSI_FLAGS_QMASK) >> 1); + + DPRINTF("%04x:%02x:%02x.%x PCI MSI CAP @0x%x\n", vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function, pos); + + ret = msi_init(&vdev->pdev, pos, entries, msi_64bit, msi_maskbit); + if (ret < 0) { + if (ret == -ENOTSUP) { + return 0; + } + error_report("vfio: msi_init failed\n"); + return ret; + } + vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0); + + return 0; +} + +/* + * We don't have any control over how pci_add_capability() inserts + * capabilities into the chain. In order to setup MSI-X we need a + * MemoryRegion for the BAR. In order to setup the BAR and not + * attempt to mmap the MSI-X table area, which VFIO won't allow, we + * need to first look for where the MSI-X table lives. So we + * unfortunately split MSI-X setup across two functions. + */ +static int vfio_early_setup_msix(VFIODevice *vdev) +{ + uint8_t pos; + uint16_t ctrl; + uint32_t table, pba; + + pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSIX); + if (!pos) { + return 0; + } + + if (pread(vdev->fd, &ctrl, sizeof(ctrl), + vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) { + return -errno; + } + + if (pread(vdev->fd, &table, sizeof(table), + vdev->config_offset + pos + PCI_MSIX_TABLE) != sizeof(table)) { + return -errno; + } + + if (pread(vdev->fd, &pba, sizeof(pba), + vdev->config_offset + pos + PCI_MSIX_PBA) != sizeof(pba)) { + return -errno; + } + + ctrl = le16_to_cpu(ctrl); + table = le32_to_cpu(table); + pba = le32_to_cpu(pba); + + vdev->msix = g_malloc0(sizeof(*(vdev->msix))); + vdev->msix->table_bar = table & PCI_MSIX_FLAGS_BIRMASK; + vdev->msix->table_offset = table & ~PCI_MSIX_FLAGS_BIRMASK; + vdev->msix->pba_bar = pba & PCI_MSIX_FLAGS_BIRMASK; + vdev->msix->pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK; + vdev->msix->entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1; + + DPRINTF("%04x:%02x:%02x.%x " + "PCI MSI-X CAP @0x%x, BAR %d, offset 0x%x, entries %d\n", + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function, pos, vdev->msix->table_bar, + vdev->msix->table_offset, vdev->msix->entries); + + return 0; +} + +static int vfio_setup_msix(VFIODevice *vdev, int pos) +{ + int ret; + + ret = msix_init(&vdev->pdev, vdev->msix->entries, + &vdev->bars[vdev->msix->table_bar].mem, + vdev->msix->table_bar, vdev->msix->table_offset, + &vdev->bars[vdev->msix->pba_bar].mem, + vdev->msix->pba_bar, vdev->msix->pba_offset, pos); + if (ret < 0) { + if (ret == -ENOTSUP) { + return 0; + } + error_report("vfio: msix_init failed\n"); + return ret; + } + + return 0; +} + +static void vfio_teardown_msi(VFIODevice *vdev) +{ + msi_uninit(&vdev->pdev); + + if (vdev->msix) { + msix_uninit(&vdev->pdev, &vdev->bars[vdev->msix->table_bar].mem, + &vdev->bars[vdev->msix->pba_bar].mem); + } +} + +/* + * Resource setup + */ +static void vfio_mmap_set_enabled(VFIODevice *vdev, bool enabled) +{ + int i; + + for (i = 0; i < PCI_ROM_SLOT; i++) { + VFIOBAR *bar = &vdev->bars[i]; + + if (!bar->size) { + continue; + } + + memory_region_set_enabled(&bar->mmap_mem, enabled); + if (vdev->msix && vdev->msix->table_bar == i) { + memory_region_set_enabled(&vdev->msix->mmap_mem, enabled); + } + } +} + +static void vfio_unmap_bar(VFIODevice *vdev, int nr) +{ + VFIOBAR *bar = &vdev->bars[nr]; + + if (!bar->size) { + return; + } + + memory_region_del_subregion(&bar->mem, &bar->mmap_mem); + munmap(bar->mmap, memory_region_size(&bar->mmap_mem)); + + if (vdev->msix && vdev->msix->table_bar == nr) { + memory_region_del_subregion(&bar->mem, &vdev->msix->mmap_mem); + munmap(vdev->msix->mmap, memory_region_size(&vdev->msix->mmap_mem)); + } + + memory_region_destroy(&bar->mem); +} + +static int vfio_mmap_bar(VFIOBAR *bar, MemoryRegion *mem, MemoryRegion *submem, + void **map, size_t size, off_t offset, + const char *name) +{ + int ret = 0; + + if (size && bar->flags & VFIO_REGION_INFO_FLAG_MMAP) { + int prot = 0; + + if (bar->flags & VFIO_REGION_INFO_FLAG_READ) { + prot |= PROT_READ; + } + + if (bar->flags & VFIO_REGION_INFO_FLAG_WRITE) { + prot |= PROT_WRITE; + } + + *map = mmap(NULL, size, prot, MAP_SHARED, + bar->fd, bar->fd_offset + offset); + if (*map == MAP_FAILED) { + *map = NULL; + ret = -errno; + goto empty_region; + } + + memory_region_init_ram_ptr(submem, name, size, *map); + } else { +empty_region: + /* Create a zero sized sub-region to make cleanup easy. */ + memory_region_init(submem, name, 0); + } + + memory_region_add_subregion(mem, offset, submem); + + return ret; +} + +static void vfio_map_bar(VFIODevice *vdev, int nr) +{ + VFIOBAR *bar = &vdev->bars[nr]; + unsigned size = bar->size; + char name[64]; + uint32_t pci_bar; + uint8_t type; + int ret; + + /* Skip both unimplemented BARs and the upper half of 64bit BARS. */ + if (!size) { + return; + } + + snprintf(name, sizeof(name), "VFIO %04x:%02x:%02x.%x BAR %d", + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function, nr); + + /* Determine what type of BAR this is for registration */ + ret = pread(vdev->fd, &pci_bar, sizeof(pci_bar), + vdev->config_offset + PCI_BASE_ADDRESS_0 + (4 * nr)); + if (ret != sizeof(pci_bar)) { + error_report("vfio: Failed to read BAR %d (%m)\n", nr); + return; + } + + pci_bar = le32_to_cpu(pci_bar); + type = pci_bar & (pci_bar & PCI_BASE_ADDRESS_SPACE_IO ? + ~PCI_BASE_ADDRESS_IO_MASK : ~PCI_BASE_ADDRESS_MEM_MASK); + + /* A "slow" read/write mapping underlies all BARs */ + memory_region_init_io(&bar->mem, &vfio_bar_ops, bar, name, size); + pci_register_bar(&vdev->pdev, nr, type, &bar->mem); + + /* + * We can't mmap areas overlapping the MSIX vector table, so we + * potentially insert a direct-mapped subregion before and after it. + */ + if (vdev->msix && vdev->msix->table_bar == nr) { + size = vdev->msix->table_offset & TARGET_PAGE_MASK; + } + + strncat(name, " mmap", sizeof(name) - strlen(name) - 1); + if (vfio_mmap_bar(bar, &bar->mem, + &bar->mmap_mem, &bar->mmap, size, 0, name)) { + error_report("%s unsupported. Performance may be slow\n", name); + } + + if (vdev->msix && vdev->msix->table_bar == nr) { + unsigned start; + + start = TARGET_PAGE_ALIGN(vdev->msix->table_offset + + (vdev->msix->entries * PCI_MSIX_ENTRY_SIZE)); + + size = start < bar->size ? bar->size - start : 0; + strncat(name, " msix-hi", sizeof(name) - strlen(name) - 1); + /* VFIOMSIXInfo contains another MemoryRegion for this mapping */ + if (vfio_mmap_bar(bar, &bar->mem, &vdev->msix->mmap_mem, + &vdev->msix->mmap, size, start, name)) { + error_report("%s unsupported. Performance may be slow\n", name); + } + } +} + +static void vfio_map_bars(VFIODevice *vdev) +{ + int i; + + for (i = 0; i < PCI_ROM_SLOT; i++) { + vfio_map_bar(vdev, i); + } +} + +static void vfio_unmap_bars(VFIODevice *vdev) +{ + int i; + + for (i = 0; i < PCI_ROM_SLOT; i++) { + vfio_unmap_bar(vdev, i); + } +} + +/* + * General setup + */ +static uint8_t vfio_std_cap_max_size(PCIDevice *pdev, uint8_t pos) +{ + uint8_t tmp, next = 0xff; + + for (tmp = pdev->config[PCI_CAPABILITY_LIST]; tmp; + tmp = pdev->config[tmp + 1]) { + if (tmp > pos && tmp < next) { + next = tmp; + } + } + + return next - pos; +} + +static int vfio_add_std_cap(VFIODevice *vdev, uint8_t pos) +{ + PCIDevice *pdev = &vdev->pdev; + uint8_t cap_id, next, size; + int ret; + + cap_id = pdev->config[pos]; + next = pdev->config[pos + 1]; + + /* + * If it becomes important to configure capabilities to their actual + * size, use this as the default when it's something we don't recognize. + * Since QEMU doesn't actually handle many of the config accesses, + * exact size doesn't seem worthwhile. + */ + size = vfio_std_cap_max_size(pdev, pos); + + /* + * pci_add_capability always inserts the new capability at the head + * of the chain. Therefore to end up with a chain that matches the + * physical device, we insert from the end by making this recursive. + * This is also why we pre-caclulate size above as cached config space + * will be changed as we unwind the stack. + */ + if (next) { + ret = vfio_add_std_cap(vdev, next); + if (ret) { + return ret; + } + } else { + pdev->config[PCI_CAPABILITY_LIST] = 0; /* Begin the rebuild */ + } + + switch (cap_id) { + case PCI_CAP_ID_MSI: + ret = vfio_setup_msi(vdev, pos); + break; + case PCI_CAP_ID_MSIX: + ret = vfio_setup_msix(vdev, pos); + break; + default: + ret = pci_add_capability(pdev, cap_id, pos, size); + break; + } + + if (ret < 0) { + error_report("vfio: %04x:%02x:%02x.%x Error adding PCI capability " + "0x%x[0x%x]@0x%x: %d\n", vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function, + cap_id, size, pos, ret); + return ret; + } + + return 0; +} + +static int vfio_add_capabilities(VFIODevice *vdev) +{ + PCIDevice *pdev = &vdev->pdev; + + if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST) || + !pdev->config[PCI_CAPABILITY_LIST]) { + return 0; /* Nothing to add */ + } + + return vfio_add_std_cap(vdev, pdev->config[PCI_CAPABILITY_LIST]); +} + +static int vfio_load_rom(VFIODevice *vdev) +{ + uint64_t size = vdev->rom_size; + char name[32]; + off_t off = 0, voff = vdev->rom_offset; + ssize_t bytes; + void *ptr; + + /* If loading ROM from file, pci handles it */ + if (vdev->pdev.romfile || !vdev->pdev.rom_bar || !size) { + return 0; + } + + DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + + snprintf(name, sizeof(name), "vfio[%04x:%02x:%02x.%x].rom", + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function); + memory_region_init_ram(&vdev->pdev.rom, name, size); + ptr = memory_region_get_ram_ptr(&vdev->pdev.rom); + memset(ptr, 0xff, size); + + while (size) { + bytes = pread(vdev->fd, ptr + off, size, voff + off); + if (bytes == 0) { + break; /* expect that we could get back less than the ROM BAR */ + } else if (bytes > 0) { + off += bytes; + size -= bytes; + } else { + if (errno == EINTR || errno == EAGAIN) { + continue; + } + error_report("vfio: Error reading device ROM: %m\n"); + memory_region_destroy(&vdev->pdev.rom); + return -errno; + } + } + + pci_register_bar(&vdev->pdev, PCI_ROM_SLOT, 0, &vdev->pdev.rom); + vdev->pdev.has_rom = true; + return 0; +} + +static int vfio_connect_container(VFIOGroup *group) +{ + VFIOContainer *container; + int ret, fd; + + if (group->container) { + return 0; + } + + QLIST_FOREACH(container, &container_list, next) { + if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) { + group->container = container; + QLIST_INSERT_HEAD(&container->group_list, group, container_next); + return 0; + } + } + + fd = qemu_open("/dev/vfio/vfio", O_RDWR); + if (fd < 0) { + error_report("vfio: failed to open /dev/vfio/vfio: %m\n"); + return -errno; + } + + ret = ioctl(fd, VFIO_GET_API_VERSION); + if (ret != VFIO_API_VERSION) { + error_report("vfio: supported vfio version: %d, " + "reported version: %d\n", VFIO_API_VERSION, ret); + close(fd); + return -EINVAL; + } + + container = g_malloc0(sizeof(*container)); + container->fd = fd; + + if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)) { + ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd); + if (ret) { + error_report("vfio: failed to set group container: %m\n"); + g_free(container); + close(fd); + return -errno; + } + + ret = ioctl(fd, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU); + if (ret) { + error_report("vfio: failed to set iommu for container: %m\n"); + g_free(container); + close(fd); + return -errno; + } + + container->iommu_data.listener = vfio_memory_listener; + container->iommu_data.release = vfio_listener_release; + + memory_listener_register(&container->iommu_data.listener, &address_space_memory); + } else { + error_report("vfio: No available IOMMU models\n"); + g_free(container); + close(fd); + return -EINVAL; + } + + QLIST_INIT(&container->group_list); + QLIST_INSERT_HEAD(&container_list, container, next); + + group->container = container; + QLIST_INSERT_HEAD(&container->group_list, group, container_next); + + return 0; +} + +static void vfio_disconnect_container(VFIOGroup *group) +{ + VFIOContainer *container = group->container; + + if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER, &container->fd)) { + error_report("vfio: error disconnecting group %d from container\n", + group->groupid); + } + + QLIST_REMOVE(group, container_next); + group->container = NULL; + + if (QLIST_EMPTY(&container->group_list)) { + if (container->iommu_data.release) { + container->iommu_data.release(container); + } + QLIST_REMOVE(container, next); + DPRINTF("vfio_disconnect_container: close container->fd\n"); + close(container->fd); + g_free(container); + } +} + +static VFIOGroup *vfio_get_group(int groupid) +{ + VFIOGroup *group; + char path[32]; + struct vfio_group_status status = { .argsz = sizeof(status) }; + + QLIST_FOREACH(group, &group_list, next) { + if (group->groupid == groupid) { + return group; + } + } + + group = g_malloc0(sizeof(*group)); + + snprintf(path, sizeof(path), "/dev/vfio/%d", groupid); + group->fd = qemu_open(path, O_RDWR); + if (group->fd < 0) { + error_report("vfio: error opening %s: %m\n", path); + g_free(group); + return NULL; + } + + if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &status)) { + error_report("vfio: error getting group status: %m\n"); + close(group->fd); + g_free(group); + return NULL; + } + + if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) { + error_report("vfio: error, group %d is not viable, please ensure " + "all devices within the iommu_group are bound to their " + "vfio bus driver.\n", groupid); + close(group->fd); + g_free(group); + return NULL; + } + + group->groupid = groupid; + QLIST_INIT(&group->device_list); + + if (vfio_connect_container(group)) { + error_report("vfio: failed to setup container for group %d\n", groupid); + close(group->fd); + g_free(group); + return NULL; + } + + QLIST_INSERT_HEAD(&group_list, group, next); + + return group; +} + +static void vfio_put_group(VFIOGroup *group) +{ + if (!QLIST_EMPTY(&group->device_list)) { + return; + } + + vfio_disconnect_container(group); + QLIST_REMOVE(group, next); + DPRINTF("vfio_put_group: close group->fd\n"); + close(group->fd); + g_free(group); +} + +static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev) +{ + struct vfio_device_info dev_info = { .argsz = sizeof(dev_info) }; + struct vfio_region_info reg_info = { .argsz = sizeof(reg_info) }; + int ret, i; + + ret = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name); + if (ret < 0) { + error_report("vfio: error getting device %s from group %d: %m\n", + name, group->groupid); + error_report("Verify all devices in group %d are bound to vfio-pci " + "or pci-stub and not already in use\n", group->groupid); + return ret; + } + + vdev->fd = ret; + vdev->group = group; + QLIST_INSERT_HEAD(&group->device_list, vdev, next); + + /* Sanity check device */ + ret = ioctl(vdev->fd, VFIO_DEVICE_GET_INFO, &dev_info); + if (ret) { + error_report("vfio: error getting device info: %m\n"); + goto error; + } + + DPRINTF("Device %s flags: %u, regions: %u, irgs: %u\n", name, + dev_info.flags, dev_info.num_regions, dev_info.num_irqs); + + if (!(dev_info.flags & VFIO_DEVICE_FLAGS_PCI)) { + error_report("vfio: Um, this isn't a PCI device\n"); + goto error; + } + + vdev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET); + if (!vdev->reset_works) { + error_report("Warning, device %s does not support reset\n", name); + } + + if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) { + error_report("vfio: unexpected number of io regions %u\n", + dev_info.num_regions); + goto error; + } + + if (dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) { + error_report("vfio: unexpected number of irqs %u\n", dev_info.num_irqs); + goto error; + } + + for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX; i++) { + reg_info.index = i; + + ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); + if (ret) { + error_report("vfio: Error getting region %d info: %m\n", i); + goto error; + } + + DPRINTF("Device %s region %d:\n", name, i); + DPRINTF(" size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n", + (unsigned long)reg_info.size, (unsigned long)reg_info.offset, + (unsigned long)reg_info.flags); + + vdev->bars[i].flags = reg_info.flags; + vdev->bars[i].size = reg_info.size; + vdev->bars[i].fd_offset = reg_info.offset; + vdev->bars[i].fd = vdev->fd; + vdev->bars[i].nr = i; + } + + reg_info.index = VFIO_PCI_ROM_REGION_INDEX; + + ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); + if (ret) { + error_report("vfio: Error getting ROM info: %m\n"); + goto error; + } + + DPRINTF("Device %s ROM:\n", name); + DPRINTF(" size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n", + (unsigned long)reg_info.size, (unsigned long)reg_info.offset, + (unsigned long)reg_info.flags); + + vdev->rom_size = reg_info.size; + vdev->rom_offset = reg_info.offset; + + reg_info.index = VFIO_PCI_CONFIG_REGION_INDEX; + + ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); + if (ret) { + error_report("vfio: Error getting config info: %m\n"); + goto error; + } + + DPRINTF("Device %s config:\n", name); + DPRINTF(" size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n", + (unsigned long)reg_info.size, (unsigned long)reg_info.offset, + (unsigned long)reg_info.flags); + + vdev->config_size = reg_info.size; + vdev->config_offset = reg_info.offset; + +error: + if (ret) { + QLIST_REMOVE(vdev, next); + vdev->group = NULL; + close(vdev->fd); + } + return ret; +} + +static void vfio_put_device(VFIODevice *vdev) +{ + QLIST_REMOVE(vdev, next); + vdev->group = NULL; + DPRINTF("vfio_put_device: close vdev->fd\n"); + close(vdev->fd); + if (vdev->msix) { + g_free(vdev->msix); + vdev->msix = NULL; + } +} + +static int vfio_initfn(PCIDevice *pdev) +{ + VFIODevice *pvdev, *vdev = DO_UPCAST(VFIODevice, pdev, pdev); + VFIOGroup *group; + char path[PATH_MAX], iommu_group_path[PATH_MAX], *group_name; + ssize_t len; + struct stat st; + int groupid; + int ret; + + /* Check that the host device exists */ + snprintf(path, sizeof(path), + "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/", + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function); + if (stat(path, &st) < 0) { + error_report("vfio: error: no such host device: %s\n", path); + return -errno; + } + + strncat(path, "iommu_group", sizeof(path) - strlen(path) - 1); + + len = readlink(path, iommu_group_path, PATH_MAX); + if (len <= 0) { + error_report("vfio: error no iommu_group for device\n"); + return -errno; + } + + iommu_group_path[len] = 0; + group_name = basename(iommu_group_path); + + if (sscanf(group_name, "%d", &groupid) != 1) { + error_report("vfio: error reading %s: %m\n", path); + return -errno; + } + + DPRINTF("%s(%04x:%02x:%02x.%x) group %d\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function, groupid); + + group = vfio_get_group(groupid); + if (!group) { + error_report("vfio: failed to get group %d\n", groupid); + return -ENOENT; + } + + snprintf(path, sizeof(path), "%04x:%02x:%02x.%01x", + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function); + + QLIST_FOREACH(pvdev, &group->device_list, next) { + if (pvdev->host.domain == vdev->host.domain && + pvdev->host.bus == vdev->host.bus && + pvdev->host.slot == vdev->host.slot && + pvdev->host.function == vdev->host.function) { + + error_report("vfio: error: device %s is already attached\n", path); + vfio_put_group(group); + return -EBUSY; + } + } + + ret = vfio_get_device(group, path, vdev); + if (ret) { + error_report("vfio: failed to get device %s\n", path); + vfio_put_group(group); + return ret; + } + + /* Get a copy of config space */ + ret = pread(vdev->fd, vdev->pdev.config, + MIN(pci_config_size(&vdev->pdev), vdev->config_size), + vdev->config_offset); + if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) { + ret = ret < 0 ? -errno : -EFAULT; + error_report("vfio: Failed to read device config space\n"); + goto out_put; + } + + /* + * Clear host resource mapping info. If we choose not to register a + * BAR, such as might be the case with the option ROM, we can get + * confusing, unwritable, residual addresses from the host here. + */ + memset(&vdev->pdev.config[PCI_BASE_ADDRESS_0], 0, 24); + memset(&vdev->pdev.config[PCI_ROM_ADDRESS], 0, 4); + + vfio_load_rom(vdev); + + ret = vfio_early_setup_msix(vdev); + if (ret) { + goto out_put; + } + + vfio_map_bars(vdev); + + ret = vfio_add_capabilities(vdev); + if (ret) { + goto out_teardown; + } + + if (vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1)) { + vdev->intx.mmap_timer = qemu_new_timer_ms(vm_clock, + vfio_intx_mmap_enable, vdev); + pci_device_set_intx_routing_notifier(&vdev->pdev, vfio_update_irq); + ret = vfio_enable_intx(vdev); + if (ret) { + goto out_teardown; + } + } + + return 0; + +out_teardown: + pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); + vfio_teardown_msi(vdev); + vfio_unmap_bars(vdev); +out_put: + vfio_put_device(vdev); + vfio_put_group(group); + return ret; +} + +static void vfio_exitfn(PCIDevice *pdev) +{ + VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); + VFIOGroup *group = vdev->group; + + pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); + vfio_disable_interrupts(vdev); + if (vdev->intx.mmap_timer) { + qemu_free_timer(vdev->intx.mmap_timer); + } + vfio_teardown_msi(vdev); + vfio_unmap_bars(vdev); + vfio_put_device(vdev); + vfio_put_group(group); +} + +static void vfio_pci_reset(DeviceState *dev) +{ + PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev); + VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); + uint16_t cmd; + + DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + + vfio_disable_interrupts(vdev); + + /* + * Stop any ongoing DMA by disconecting I/O, MMIO, and bus master. + * Also put INTx Disable in known state. + */ + cmd = vfio_pci_read_config(pdev, PCI_COMMAND, 2); + cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + PCI_COMMAND_INTX_DISABLE); + vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2); + + if (vdev->reset_works) { + if (ioctl(vdev->fd, VFIO_DEVICE_RESET)) { + error_report("vfio: Error unable to reset physical device " + "(%04x:%02x:%02x.%x): %m\n", vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + } + } + + vfio_enable_intx(vdev); +} + +static Property vfio_pci_dev_properties[] = { + DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIODevice, host), + DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIODevice, + intx.mmap_timeout, 1100), + /* + * TODO - support passed fds... is this necessary? + * DEFINE_PROP_STRING("vfiofd", VFIODevice, vfiofd_name), + * DEFINE_PROP_STRING("vfiogroupfd, VFIODevice, vfiogroupfd_name), + */ + DEFINE_PROP_END_OF_LIST(), +}; + +static const VMStateDescription vfio_pci_vmstate = { + .name = "vfio-pci", + .unmigratable = 1, +}; + +static void vfio_pci_dev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass); + + dc->reset = vfio_pci_reset; + dc->props = vfio_pci_dev_properties; + dc->vmsd = &vfio_pci_vmstate; + dc->desc = "VFIO-based PCI device assignment"; + pdc->init = vfio_initfn; + pdc->exit = vfio_exitfn; + pdc->config_read = vfio_pci_read_config; + pdc->config_write = vfio_pci_write_config; +} + +static const TypeInfo vfio_pci_dev_info = { + .name = "vfio-pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VFIODevice), + .class_init = vfio_pci_dev_class_init, +}; + +static void register_vfio_pci_dev_type(void) +{ + type_register_static(&vfio_pci_dev_info); +} + +type_init(register_vfio_pci_dev_type) diff --git a/hw/vga-isa-mm.c b/hw/vga-isa-mm.c index 44ae7d92c8..311c966f77 100644 --- a/hw/vga-isa-mm.c +++ b/hw/vga-isa-mm.c @@ -22,11 +22,11 @@ * THE SOFTWARE. */ #include "hw.h" -#include "console.h" +#include "ui/console.h" #include "pc.h" #include "vga_int.h" -#include "pixel_ops.h" -#include "qemu-timer.h" +#include "ui/pixel_ops.h" +#include "qemu/timer.h" #define VGA_RAM_SIZE (8192 * 1024) @@ -36,7 +36,7 @@ typedef struct ISAVGAMMState { } ISAVGAMMState; /* Memory mapped interface */ -static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr) +static uint32_t vga_mm_readb (void *opaque, hwaddr addr) { ISAVGAMMState *s = opaque; @@ -44,14 +44,14 @@ static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr) } static void vga_mm_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { ISAVGAMMState *s = opaque; vga_ioport_write(&s->vga, addr >> s->it_shift, value & 0xff); } -static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr) +static uint32_t vga_mm_readw (void *opaque, hwaddr addr) { ISAVGAMMState *s = opaque; @@ -59,14 +59,14 @@ static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr) } static void vga_mm_writew (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { ISAVGAMMState *s = opaque; vga_ioport_write(&s->vga, addr >> s->it_shift, value & 0xffff); } -static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr) +static uint32_t vga_mm_readl (void *opaque, hwaddr addr) { ISAVGAMMState *s = opaque; @@ -74,7 +74,7 @@ static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr) } static void vga_mm_writel (void *opaque, - target_phys_addr_t addr, uint32_t value) + hwaddr addr, uint32_t value) { ISAVGAMMState *s = opaque; @@ -97,8 +97,8 @@ static const MemoryRegionOps vga_mm_ctrl_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void vga_mm_init(ISAVGAMMState *s, target_phys_addr_t vram_base, - target_phys_addr_t ctrl_base, int it_shift, +static void vga_mm_init(ISAVGAMMState *s, hwaddr vram_base, + hwaddr ctrl_base, int it_shift, MemoryRegion *address_space) { MemoryRegion *s_ioport_ctrl, *vga_io_memory; @@ -107,6 +107,7 @@ static void vga_mm_init(ISAVGAMMState *s, target_phys_addr_t vram_base, s_ioport_ctrl = g_malloc(sizeof(*s_ioport_ctrl)); memory_region_init_io(s_ioport_ctrl, &vga_mm_ctrl_ops, s, "vga-mm-ctrl", 0x100000); + memory_region_set_flush_coalesced(s_ioport_ctrl); vga_io_memory = g_malloc(sizeof(*vga_io_memory)); /* XXX: endianness? */ @@ -122,8 +123,8 @@ static void vga_mm_init(ISAVGAMMState *s, target_phys_addr_t vram_base, memory_region_set_coalescing(vga_io_memory); } -int isa_vga_mm_init(target_phys_addr_t vram_base, - target_phys_addr_t ctrl_base, int it_shift, +int isa_vga_mm_init(hwaddr vram_base, + hwaddr ctrl_base, int it_shift, MemoryRegion *address_space) { ISAVGAMMState *s; diff --git a/hw/vga-isa.c b/hw/vga-isa.c index d2904737bc..cbe7b05a7e 100644 --- a/hw/vga-isa.c +++ b/hw/vga-isa.c @@ -1,6 +1,8 @@ /* * QEMU ISA VGA Emulator. * + * see docs/specs/standard-vga.txt for virtual hardware specs. + * * Copyright (c) 2003 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -22,11 +24,11 @@ * THE SOFTWARE. */ #include "hw.h" -#include "console.h" +#include "ui/console.h" #include "pc.h" #include "vga_int.h" -#include "pixel_ops.h" -#include "qemu-timer.h" +#include "ui/pixel_ops.h" +#include "qemu/timer.h" #include "loader.h" typedef struct ISAVGAState { diff --git a/hw/vga-pci.c b/hw/vga-pci.c index 37dc019a61..87c7c0648d 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -1,6 +1,8 @@ /* * QEMU PCI VGA Emulator. * + * see docs/specs/standard-vga.txt for virtual hardware specs. + * * Copyright (c) 2003 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -22,17 +24,30 @@ * THE SOFTWARE. */ #include "hw.h" -#include "console.h" -#include "pc.h" -#include "pci.h" +#include "ui/console.h" +#include "pci/pci.h" #include "vga_int.h" -#include "pixel_ops.h" -#include "qemu-timer.h" +#include "ui/pixel_ops.h" +#include "qemu/timer.h" #include "loader.h" +#define PCI_VGA_IOPORT_OFFSET 0x400 +#define PCI_VGA_IOPORT_SIZE (0x3e0 - 0x3c0) +#define PCI_VGA_BOCHS_OFFSET 0x500 +#define PCI_VGA_BOCHS_SIZE (0x0b * 2) +#define PCI_VGA_MMIO_SIZE 0x1000 + +enum vga_pci_flags { + PCI_VGA_FLAG_ENABLE_MMIO = 1, +}; + typedef struct PCIVGAState { PCIDevice dev; VGACommonState vga; + uint32_t flags; + MemoryRegion mmio; + MemoryRegion ioport; + MemoryRegion bochs; } PCIVGAState; static const VMStateDescription vmstate_vga_pci = { @@ -47,36 +62,126 @@ static const VMStateDescription vmstate_vga_pci = { } }; -static int pci_vga_initfn(PCIDevice *dev) +static uint64_t pci_vga_ioport_read(void *ptr, hwaddr addr, + unsigned size) { - PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev); - VGACommonState *s = &d->vga; + PCIVGAState *d = ptr; + uint64_t ret = 0; + + switch (size) { + case 1: + ret = vga_ioport_read(&d->vga, addr); + break; + case 2: + ret = vga_ioport_read(&d->vga, addr); + ret |= vga_ioport_read(&d->vga, addr+1) << 8; + break; + } + return ret; +} - // vga + console init - vga_common_init(s); - vga_init(s, pci_address_space(dev), pci_address_space_io(dev), true); +static void pci_vga_ioport_write(void *ptr, hwaddr addr, + uint64_t val, unsigned size) +{ + PCIVGAState *d = ptr; - s->ds = graphic_console_init(s->update, s->invalidate, - s->screen_dump, s->text_update, s); + switch (size) { + case 1: + vga_ioport_write(&d->vga, addr + 0x3c0, val); + break; + case 2: + /* + * Update bytes in little endian order. Allows to update + * indexed registers with a single word write because the + * index byte is updated first. + */ + vga_ioport_write(&d->vga, addr + 0x3c0, val & 0xff); + vga_ioport_write(&d->vga, addr + 0x3c1, (val >> 8) & 0xff); + break; + } +} - /* XXX: VGA_RAM_SIZE must be a power of two */ - pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); +static const MemoryRegionOps pci_vga_ioport_ops = { + .read = pci_vga_ioport_read, + .write = pci_vga_ioport_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 2, + .endianness = DEVICE_LITTLE_ENDIAN, +}; - if (!dev->rom_bar) { - /* compatibility with pc-0.13 and older */ - vga_init_vbe(s, pci_address_space(dev)); - } +static uint64_t pci_vga_bochs_read(void *ptr, hwaddr addr, + unsigned size) +{ + PCIVGAState *d = ptr; + int index = addr >> 1; - return 0; + vbe_ioport_write_index(&d->vga, 0, index); + return vbe_ioport_read_data(&d->vga, 0); } -DeviceState *pci_vga_init(PCIBus *bus) +static void pci_vga_bochs_write(void *ptr, hwaddr addr, + uint64_t val, unsigned size) { - return &pci_create_simple(bus, -1, "VGA")->qdev; + PCIVGAState *d = ptr; + int index = addr >> 1; + + vbe_ioport_write_index(&d->vga, 0, index); + vbe_ioport_write_data(&d->vga, 0, val); +} + +static const MemoryRegionOps pci_vga_bochs_ops = { + .read = pci_vga_bochs_read, + .write = pci_vga_bochs_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 2, + .impl.max_access_size = 2, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static int pci_std_vga_initfn(PCIDevice *dev) +{ + PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev); + VGACommonState *s = &d->vga; + + /* vga + console init */ + vga_common_init(s); + vga_init(s, pci_address_space(dev), pci_address_space_io(dev), true); + + s->ds = graphic_console_init(s->update, s->invalidate, + s->screen_dump, s->text_update, s); + + /* XXX: VGA_RAM_SIZE must be a power of two */ + pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); + + /* mmio bar for vga register access */ + if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_MMIO)) { + memory_region_init(&d->mmio, "vga.mmio", 4096); + memory_region_init_io(&d->ioport, &pci_vga_ioport_ops, d, + "vga ioports remapped", PCI_VGA_IOPORT_SIZE); + memory_region_init_io(&d->bochs, &pci_vga_bochs_ops, d, + "bochs dispi interface", PCI_VGA_BOCHS_SIZE); + + memory_region_add_subregion(&d->mmio, PCI_VGA_IOPORT_OFFSET, + &d->ioport); + memory_region_add_subregion(&d->mmio, PCI_VGA_BOCHS_OFFSET, + &d->bochs); + pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio); + } + + if (!dev->rom_bar) { + /* compatibility with pc-0.13 and older */ + vga_init_vbe(s, pci_address_space(dev)); + } + + return 0; } static Property vga_pci_properties[] = { DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16), + DEFINE_PROP_BIT("mmio", PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_MMIO, true), DEFINE_PROP_END_OF_LIST(), }; @@ -86,7 +191,7 @@ static void vga_class_init(ObjectClass *klass, void *data) PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); k->no_hotplug = 1; - k->init = pci_vga_initfn; + k->init = pci_std_vga_initfn; k->romfile = "vgabios-stdvga.bin"; k->vendor_id = PCI_VENDOR_ID_QEMU; k->device_id = PCI_DEVICE_ID_QEMU_VGA; @@ -23,12 +23,12 @@ */ #include "hw.h" #include "vga.h" -#include "console.h" +#include "ui/console.h" #include "pc.h" -#include "pci.h" +#include "pci/pci.h" #include "vga_int.h" -#include "pixel_ops.h" -#include "qemu-timer.h" +#include "ui/pixel_ops.h" +#include "qemu/timer.h" #include "xen.h" #include "trace.h" @@ -166,12 +166,13 @@ static uint32_t expand4[256]; static uint16_t expand2[256]; static uint8_t expand4to8[16]; -static void vga_screen_dump(void *opaque, const char *filename, bool cswitch); +static void vga_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp); static void vga_update_memory_access(VGACommonState *s) { MemoryRegion *region, *old_region = s->chain4_alias; - target_phys_addr_t base, offset, size; + hwaddr base, offset, size; s->chain4_alias = NULL; @@ -360,6 +361,8 @@ uint32_t vga_ioport_read(void *opaque, uint32_t addr) VGACommonState *s = opaque; int val, index; + qemu_flush_coalesced_mmio_buffer(); + if (vga_ioport_invalid(s, addr)) { val = 0xff; } else { @@ -452,6 +455,8 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) VGACommonState *s = opaque; int index; + qemu_flush_coalesced_mmio_buffer(); + /* check port range access depending on color/monochrome mode */ if (vga_ioport_invalid(s, addr)) { return; @@ -577,7 +582,6 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } -#ifdef CONFIG_BOCHS_VBE static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr) { VGACommonState *s = opaque; @@ -586,7 +590,7 @@ static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr) return val; } -static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) +uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) { VGACommonState *s = opaque; uint32_t val; @@ -622,13 +626,13 @@ static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) return val; } -static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val) +void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val) { VGACommonState *s = opaque; s->vbe_index = val; } -static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) +void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) { VGACommonState *s = opaque; @@ -779,10 +783,9 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) } } } -#endif /* called for accesses between 0xa0000 and 0xc0000 */ -uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr) +uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr) { int memory_map_mode, plane; uint32_t ret; @@ -839,7 +842,7 @@ uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr) } /* called for accesses between 0xa0000 and 0xc0000 */ -void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val) +void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) { int memory_map_mode, plane, write_mode, b, func_select, mask; uint32_t write_mask, bit_mask, set_mask; @@ -1124,14 +1127,12 @@ static void vga_get_offsets(VGACommonState *s, uint32_t *pline_compare) { uint32_t start_addr, line_offset, line_compare; -#ifdef CONFIG_BOCHS_VBE + if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { line_offset = s->vbe_line_offset; start_addr = s->vbe_start_addr; line_compare = 65535; - } else -#endif - { + } else { /* compute line_offset in bytes */ line_offset = s->cr[VGA_CRTC_OFFSET]; line_offset <<= 3; @@ -1345,6 +1346,7 @@ static void vga_draw_text(VGACommonState *s, int full_update) s->last_scr_width = width * cw; s->last_scr_height = height * cheight; qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height); + dpy_text_resize(s->ds, width, height); s->last_depth = 0; s->last_width = width; s->last_height = height; @@ -1358,6 +1360,14 @@ static void vga_draw_text(VGACommonState *s, int full_update) palette = s->last_palette; x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); + if (full_update) { + s->full_update_text = 1; + } + if (s->full_update_gfx) { + s->full_update_gfx = 0; + full_update |= 1; + } + cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) | s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr; if (cursor_offset != s->cursor_offset || @@ -1455,8 +1465,8 @@ static void vga_draw_text(VGACommonState *s, int full_update) ch_attr_ptr++; } if (cx_max != -1) { - dpy_update(s->ds, cx_min * cw, cy * cheight, - (cx_max - cx_min + 1) * cw, cheight); + dpy_gfx_update(s->ds, cx_min * cw, cy * cheight, + (cx_max - cx_min + 1) * cw, cheight); } dest += linesize * cheight; line1 = line + cheight; @@ -1567,12 +1577,10 @@ static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_ static int vga_get_bpp(VGACommonState *s) { int ret; -#ifdef CONFIG_BOCHS_VBE + if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { ret = s->vbe_regs[VBE_DISPI_INDEX_BPP]; - } else -#endif - { + } else { ret = 0; } return ret; @@ -1582,13 +1590,10 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight) { int width, height; -#ifdef CONFIG_BOCHS_VBE if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { width = s->vbe_regs[VBE_DISPI_INDEX_XRES]; height = s->vbe_regs[VBE_DISPI_INDEX_YRES]; - } else -#endif - { + } else { width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8; height = s->cr[VGA_CRTC_V_DISP_END] | ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) | @@ -1611,7 +1616,7 @@ void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2) } } -static void vga_sync_dirty_bitmap(VGACommonState *s) +void vga_sync_dirty_bitmap(VGACommonState *s) { memory_region_sync_dirty_bitmap(&s->vram); } @@ -1692,7 +1697,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) s->ds->surface->pf = qemu_different_endianness_pixelformat(depth); #endif - dpy_resize(s->ds); + dpy_gfx_resize(s->ds); } else { qemu_console_resize(s->ds, disp_width, height); } @@ -1704,9 +1709,14 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) s->last_depth = depth; full_update = 1; } else if (is_buffer_shared(s->ds->surface) && - (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) { - s->ds->surface->data = s->vram_ptr + (s->start_addr * 4); - dpy_setdata(s->ds); + (full_update || ds_get_data(s->ds) != s->vram_ptr + + (s->start_addr * 4))) { + qemu_free_displaysurface(s->ds); + s->ds->surface = qemu_create_displaysurface_from(disp_width, + height, depth, + s->line_offset, + s->vram_ptr + (s->start_addr * 4)); + dpy_gfx_setdata(s->ds); } s->rgb_to_pixel = @@ -1811,8 +1821,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) } else { if (y_start >= 0) { /* flush to display */ - dpy_update(s->ds, 0, y_start, - disp_width, y - y_start); + dpy_gfx_update(s->ds, 0, y_start, + disp_width, y - y_start); y_start = -1; } } @@ -1832,8 +1842,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) } if (y_start >= 0) { /* flush to display */ - dpy_update(s->ds, 0, y_start, - disp_width, y - y_start); + dpy_gfx_update(s->ds, 0, y_start, + disp_width, y - y_start); } /* reset modified pages */ if (page_max >= page_min) { @@ -1867,8 +1877,8 @@ static void vga_draw_blank(VGACommonState *s, int full_update) memset(d, val, w); d += ds_get_linesize(s->ds); } - dpy_update(s->ds, 0, 0, - s->last_scr_width, s->last_scr_height); + dpy_gfx_update(s->ds, 0, 0, + s->last_scr_width, s->last_scr_height); } #define GMODE_TEXT 0 @@ -1943,14 +1953,12 @@ void vga_common_reset(VGACommonState *s) s->dac_8bit = 0; memset(s->palette, '\0', sizeof(s->palette)); s->bank_offset = 0; -#ifdef CONFIG_BOCHS_VBE s->vbe_index = 0; memset(s->vbe_regs, '\0', sizeof(s->vbe_regs)); s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5; s->vbe_start_addr = 0; s->vbe_line_offset = 0; s->vbe_bank_mask = (s->vram_size >> 16) - 1; -#endif memset(s->font_offsets, '\0', sizeof(s->font_offsets)); s->graphic_mode = -1; /* force full update */ s->shift_control = 0; @@ -2058,9 +2066,9 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) cw != s->last_cw || cheight != s->last_ch) { s->last_scr_width = width * cw; s->last_scr_height = height * cheight; - s->ds->surface->width = width; - s->ds->surface->height = height; - dpy_resize(s->ds); + qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height); + dpy_text_resize(s->ds, width, height); + s->last_depth = 0; s->last_width = width; s->last_height = height; s->last_ch = cheight; @@ -2068,6 +2076,14 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) full_update = 1; } + if (full_update) { + s->full_update_gfx = 1; + } + if (s->full_update_text) { + s->full_update_text = 0; + full_update |= 1; + } + /* Update "hardware" cursor */ cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) | s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr; @@ -2076,11 +2092,11 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) { cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20); if (cursor_visible && cursor_offset < size && cursor_offset >= 0) - dpy_cursor(s->ds, - TEXTMODE_X(cursor_offset), - TEXTMODE_Y(cursor_offset)); + dpy_text_cursor(s->ds, + TEXTMODE_X(cursor_offset), + TEXTMODE_Y(cursor_offset)); else - dpy_cursor(s->ds, -1, -1); + dpy_text_cursor(s->ds, -1, -1); s->cursor_offset = cursor_offset; s->cursor_start = s->cr[VGA_CRTC_CURSOR_START]; s->cursor_end = s->cr[VGA_CRTC_CURSOR_END]; @@ -2093,7 +2109,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) for (i = 0; i < size; src ++, dst ++, i ++) console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src))); - dpy_update(s->ds, 0, 0, width, height); + dpy_text_update(s->ds, 0, 0, width, height); } else { c_max = 0; @@ -2116,7 +2132,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) if (c_min <= c_max) { i = TEXTMODE_Y(c_min); - dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1); + dpy_text_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1); } } @@ -2141,10 +2157,8 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) /* Display a message */ s->last_width = 60; s->last_height = height = 3; - dpy_cursor(s->ds, -1, -1); - s->ds->surface->width = s->last_width; - s->ds->surface->height = height; - dpy_resize(s->ds); + dpy_text_cursor(s->ds, -1, -1); + dpy_text_resize(s->ds, s->last_width, height); for (dst = chardata, i = 0; i < s->last_width * height; i ++) console_write_ch(dst ++, ' '); @@ -2155,10 +2169,10 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) for (i = 0; i < size; i ++) console_write_ch(dst ++, 0x00200100 | msg_buffer[i]); - dpy_update(s->ds, 0, 0, s->last_width, height); + dpy_text_update(s->ds, 0, 0, s->last_width, height); } -static uint64_t vga_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t vga_mem_read(void *opaque, hwaddr addr, unsigned size) { VGACommonState *s = opaque; @@ -2166,7 +2180,7 @@ static uint64_t vga_mem_read(void *opaque, target_phys_addr_t addr, return vga_mem_readb(s, addr); } -static void vga_mem_write(void *opaque, target_phys_addr_t addr, +static void vga_mem_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { VGACommonState *s = opaque; @@ -2224,13 +2238,11 @@ const VMStateDescription vmstate_vga_common = { VMSTATE_INT32(bank_offset, VGACommonState), VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState), -#ifdef CONFIG_BOCHS_VBE VMSTATE_UINT16(vbe_index, VGACommonState), VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB), VMSTATE_UINT32(vbe_start_addr, VGACommonState), VMSTATE_UINT32(vbe_line_offset, VGACommonState), VMSTATE_UINT32(vbe_bank_mask, VGACommonState), -#endif VMSTATE_END_OF_LIST() } }; @@ -2270,11 +2282,7 @@ void vga_common_init(VGACommonState *s) } s->vram_size_mb = s->vram_size >> 20; -#ifdef CONFIG_BOCHS_VBE s->is_vbe_vmstate = 1; -#else - s->is_vbe_vmstate = 0; -#endif memory_region_init_ram(&s->vram, "vga.vram", s->vram_size); vmstate_register_ram_global(&s->vram); xen_register_framebuffer(&s->vram); @@ -2309,17 +2317,14 @@ static const MemoryRegionPortio vga_portio_list[] = { PORTIO_END_OF_LIST(), }; -#ifdef CONFIG_BOCHS_VBE static const MemoryRegionPortio vbe_portio_list[] = { { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index }, # ifdef TARGET_I386 { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data }, -# else - { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data }, # endif + { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data }, PORTIO_END_OF_LIST(), }; -#endif /* CONFIG_BOCHS_VBE */ /* Used by both ISA and PCI */ MemoryRegion *vga_init_io(VGACommonState *s, @@ -2329,14 +2334,12 @@ MemoryRegion *vga_init_io(VGACommonState *s, MemoryRegion *vga_mem; *vga_ports = vga_portio_list; - *vbe_ports = NULL; -#ifdef CONFIG_BOCHS_VBE *vbe_ports = vbe_portio_list; -#endif vga_mem = g_malloc(sizeof(*vga_mem)); memory_region_init_io(vga_mem, &vga_mem_ops, s, "vga-lowmem", 0x20000); + memory_region_set_flush_coalesced(vga_mem); return vga_mem; } @@ -2373,7 +2376,6 @@ void vga_init(VGACommonState *s, MemoryRegion *address_space, void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory) { -#ifdef CONFIG_BOCHS_VBE /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region, * so use an alias to avoid double-mapping the same region. */ @@ -2384,58 +2386,59 @@ void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory) VBE_DISPI_LFB_PHYSICAL_ADDRESS, &s->vram_vbe); s->vbe_mapped = 1; -#endif } /********************************************************/ /* vga screen dump */ -int ppm_save(const char *filename, struct DisplaySurface *ds) +void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp) { + int width = pixman_image_get_width(ds->image); + int height = pixman_image_get_height(ds->image); FILE *f; - uint8_t *d, *d1; - uint32_t v; - int y, x; - uint8_t r, g, b; + int y; int ret; - char *linebuf, *pbuf; + pixman_image_t *linebuf; trace_ppm_save(filename, ds); f = fopen(filename, "wb"); - if (!f) - return -1; - fprintf(f, "P6\n%d %d\n%d\n", - ds->width, ds->height, 255); - linebuf = g_malloc(ds->width * 3); - d1 = ds->data; - for(y = 0; y < ds->height; y++) { - d = d1; - pbuf = linebuf; - for(x = 0; x < ds->width; x++) { - if (ds->pf.bits_per_pixel == 32) - v = *(uint32_t *)d; - else - v = (uint32_t) (*(uint16_t *)d); - /* Limited to 8 or fewer bits per channel: */ - r = ((v >> ds->pf.rshift) & ds->pf.rmax) << (8 - ds->pf.rbits); - g = ((v >> ds->pf.gshift) & ds->pf.gmax) << (8 - ds->pf.gbits); - b = ((v >> ds->pf.bshift) & ds->pf.bmax) << (8 - ds->pf.bbits); - *pbuf++ = r; - *pbuf++ = g; - *pbuf++ = b; - d += ds->pf.bytes_per_pixel; - } - d1 += ds->linesize; - ret = fwrite(linebuf, 1, pbuf - linebuf, f); + if (!f) { + error_setg(errp, "failed to open file '%s': %s", filename, + strerror(errno)); + return; + } + ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255); + if (ret < 0) { + linebuf = NULL; + goto write_err; + } + linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width); + for (y = 0; y < height; y++) { + qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y); + clearerr(f); + ret = fwrite(pixman_image_get_data(linebuf), 1, + pixman_image_get_stride(linebuf), f); (void)ret; + if (ferror(f)) { + goto write_err; + } } - g_free(linebuf); + +out: + qemu_pixman_image_unref(linebuf); fclose(f); - return 0; + return; + +write_err: + error_setg(errp, "failed to write to file '%s': %s", filename, + strerror(errno)); + unlink(filename); + goto out; } /* save the vga display in a PPM image even if no display is available */ -static void vga_screen_dump(void *opaque, const char *filename, bool cswitch) +static void vga_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp) { VGACommonState *s = opaque; @@ -2443,5 +2446,5 @@ static void vga_screen_dump(void *opaque, const char *filename, bool cswitch) vga_invalidate_display(s); } vga_hw_update(); - ppm_save(filename, s->ds->surface); + ppm_save(filename, s->ds->surface, errp); } diff --git a/hw/vga_int.h b/hw/vga_int.h index 8938093682..8d496ea9bf 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -21,16 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#ifndef HW_VGA_INT_H +#define HW_VGA_INT_H 1 #include <hw/hw.h> -#include "memory.h" +#include "qapi/error.h" +#include "exec/memory.h" #define ST01_V_RETRACE 0x08 #define ST01_DISP_ENABLE 0x01 -/* bochs VBE support */ -#define CONFIG_BOCHS_VBE - #define VBE_DISPI_MAX_XRES 16000 #define VBE_DISPI_MAX_YRES 12000 #define VBE_DISPI_MAX_BPP 32 @@ -64,21 +64,6 @@ #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 -#ifdef CONFIG_BOCHS_VBE - -#define VGA_STATE_COMMON_BOCHS_VBE \ - uint16_t vbe_index; \ - uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; \ - uint32_t vbe_start_addr; \ - uint32_t vbe_line_offset; \ - uint32_t vbe_bank_mask; \ - int vbe_mapped; -#else - -#define VGA_STATE_COMMON_BOCHS_VBE - -#endif /* !CONFIG_BOCHS_VBE */ - #define CH_ATTR_SIZE (160 * 100) #define VGA_MAX_HEIGHT 2048 @@ -139,7 +124,13 @@ typedef struct VGACommonState { void (*get_resolution)(struct VGACommonState *s, int *pwidth, int *pheight); - VGA_STATE_COMMON_BOCHS_VBE + /* bochs vbe state */ + uint16_t vbe_index; + uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; + uint32_t vbe_start_addr; + uint32_t vbe_line_offset; + uint32_t vbe_bank_mask; + int vbe_mapped; /* display refresh support */ DisplayState *ds; uint32_t font_offsets[2]; @@ -165,6 +156,8 @@ typedef struct VGACommonState { vga_hw_invalidate_ptr invalidate; vga_hw_screen_dump_ptr screen_dump; vga_hw_text_update_ptr text_update; + bool full_update_text; + bool full_update_gfx; /* hardware mouse cursor support */ uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32]; void (*cursor_invalidate)(struct VGACommonState *s); @@ -195,19 +188,24 @@ MemoryRegion *vga_init_io(VGACommonState *s, const MemoryRegionPortio **vbe_ports); void vga_common_reset(VGACommonState *s); +void vga_sync_dirty_bitmap(VGACommonState *s); void vga_dirty_log_start(VGACommonState *s); void vga_dirty_log_stop(VGACommonState *s); extern const VMStateDescription vmstate_vga_common; uint32_t vga_ioport_read(void *opaque, uint32_t addr); void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val); -uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr); -void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val); +uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr); +void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val); void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2); -int ppm_save(const char *filename, struct DisplaySurface *ds); +void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp); int vga_ioport_invalid(VGACommonState *s, uint32_t addr); + void vga_init_vbe(VGACommonState *s, MemoryRegion *address_space); +uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr); +void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val); +void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val); extern const uint8_t sr_mask[8]; extern const uint8_t gr_mask[16]; @@ -216,3 +214,5 @@ extern const uint8_t gr_mask[16]; #define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin" extern const MemoryRegionOps vga_mem_ops; + +#endif diff --git a/hw/vhost.c b/hw/vhost.c index 0fd8da84e2..4e1cb47418 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -16,9 +16,9 @@ #include <sys/ioctl.h> #include "vhost.h" #include "hw/hw.h" -#include "range.h" +#include "qemu/range.h" #include <linux/vhost.h> -#include "exec-memory.h" +#include "exec/address-spaces.h" static void vhost_dev_sync_region(struct vhost_dev *dev, MemoryRegionSection *section, @@ -65,8 +65,8 @@ static void vhost_dev_sync_region(struct vhost_dev *dev, static int vhost_sync_dirty_bitmap(struct vhost_dev *dev, MemoryRegionSection *section, - target_phys_addr_t start_addr, - target_phys_addr_t end_addr) + hwaddr start_addr, + hwaddr end_addr) { int i; @@ -93,8 +93,8 @@ static void vhost_log_sync(MemoryListener *listener, { struct vhost_dev *dev = container_of(listener, struct vhost_dev, memory_listener); - target_phys_addr_t start_addr = section->offset_within_address_space; - target_phys_addr_t end_addr = start_addr + section->size; + hwaddr start_addr = section->offset_within_address_space; + hwaddr end_addr = start_addr + section->size; vhost_sync_dirty_bitmap(dev, section, start_addr, end_addr); } @@ -296,7 +296,7 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev, int i; for (i = 0; i < dev->nvqs; ++i) { struct vhost_virtqueue *vq = dev->vqs + i; - target_phys_addr_t l; + hwaddr l; void *p; if (!ranges_overlap(start_addr, size, vq->ring_phys, vq->ring_size)) { @@ -362,7 +362,7 @@ static void vhost_set_memory(MemoryListener *listener, { struct vhost_dev *dev = container_of(listener, struct vhost_dev, memory_listener); - target_phys_addr_t start_addr = section->offset_within_address_space; + hwaddr start_addr = section->offset_within_address_space; ram_addr_t size = section->size; bool log_dirty = memory_region_is_logging(section->mr); int s = offsetof(struct vhost_memory, regions) + @@ -434,8 +434,7 @@ static void vhost_set_memory(MemoryListener *listener, static bool vhost_section(MemoryRegionSection *section) { - return section->address_space == get_system_memory() - && memory_region_is_ram(section->mr); + return memory_region_is_ram(section->mr); } static void vhost_begin(MemoryListener *listener) @@ -618,7 +617,7 @@ static int vhost_virtqueue_init(struct vhost_dev *dev, struct vhost_virtqueue *vq, unsigned idx) { - target_phys_addr_t s, l, a; + hwaddr s, l, a; int r; struct vhost_vring_file file = { .index = idx, @@ -747,14 +746,15 @@ static void vhost_eventfd_del(MemoryListener *listener, { } -int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force) +int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath, + bool force) { uint64_t features; int r; if (devfd >= 0) { hdev->control = devfd; } else { - hdev->control = open("/dev/vhost-net", O_RDWR); + hdev->control = open(devpath, O_RDWR); if (hdev->control < 0) { return -errno; } @@ -792,7 +792,7 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force) hdev->log_size = 0; hdev->log_enabled = false; hdev->started = false; - memory_listener_register(&hdev->memory_listener, NULL); + memory_listener_register(&hdev->memory_listener, &address_space_memory); hdev->force = force; return 0; fail: @@ -948,7 +948,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) } for (i = 0; i < hdev->n_mem_sections; ++i) { vhost_sync_dirty_bitmap(hdev, &hdev->mem_sections[i], - 0, (target_phys_addr_t)~0x0ull); + 0, (hwaddr)~0x0ull); } r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, false); if (r < 0) { diff --git a/hw/vhost.h b/hw/vhost.h index 80e64df860..6f6a906f4f 100644 --- a/hw/vhost.h +++ b/hw/vhost.h @@ -3,7 +3,7 @@ #include "hw/hw.h" #include "hw/virtio.h" -#include "memory.h" +#include "exec/memory.h" /* Generic structures common for any vhost based device. */ struct vhost_virtqueue { @@ -44,7 +44,8 @@ struct vhost_dev { bool force; }; -int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force); +int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath, + bool force); void vhost_dev_cleanup(struct vhost_dev *hdev); bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev); int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev); diff --git a/hw/vhost_net.c b/hw/vhost_net.c index ecaa22dfb4..ae2785d83f 100644 --- a/hw/vhost_net.c +++ b/hw/vhost_net.c @@ -13,12 +13,12 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "net.h" +#include "net/net.h" #include "net/tap.h" #include "virtio-net.h" #include "vhost_net.h" -#include "qemu-error.h" +#include "qemu/error-report.h" #include "config.h" @@ -109,7 +109,7 @@ struct vhost_net *vhost_net_init(NetClientState *backend, int devfd, (1 << VHOST_NET_F_VIRTIO_NET_HDR); net->backend = r; - r = vhost_dev_init(&net->dev, devfd, force); + r = vhost_dev_init(&net->dev, devfd, "/dev/vhost-net", force); if (r < 0) { goto fail; } @@ -150,10 +150,6 @@ int vhost_net_start(struct vhost_net *net, if (r < 0) { goto fail_notifiers; } - if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) { - tap_set_vnet_hdr_len(net->nc, - sizeof(struct virtio_net_hdr_mrg_rxbuf)); - } r = vhost_dev_start(&net->dev, dev); if (r < 0) { @@ -179,9 +175,6 @@ fail: } net->nc->info->poll(net->nc, true); vhost_dev_stop(&net->dev, dev); - if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) { - tap_set_vnet_hdr_len(net->nc, sizeof(struct virtio_net_hdr)); - } fail_start: vhost_dev_disable_notifiers(&net->dev, dev); fail_notifiers: @@ -199,18 +192,12 @@ void vhost_net_stop(struct vhost_net *net, } net->nc->info->poll(net->nc, true); vhost_dev_stop(&net->dev, dev); - if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) { - tap_set_vnet_hdr_len(net->nc, sizeof(struct virtio_net_hdr)); - } vhost_dev_disable_notifiers(&net->dev, dev); } void vhost_net_cleanup(struct vhost_net *net) { vhost_dev_cleanup(&net->dev); - if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) { - tap_set_vnet_hdr_len(net->nc, sizeof(struct virtio_net_hdr)); - } g_free(net); } #else diff --git a/hw/vhost_net.h b/hw/vhost_net.h index a9db23423c..012aba4148 100644 --- a/hw/vhost_net.h +++ b/hw/vhost_net.h @@ -1,7 +1,7 @@ #ifndef VHOST_NET_H #define VHOST_NET_H -#include "net.h" +#include "net/net.h" struct vhost_net; typedef struct vhost_net VHostNetState; diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c index 79bc0d10ee..78450d7c40 100644 --- a/hw/virtex_ml507.c +++ b/hw/virtex_ml507.c @@ -24,23 +24,22 @@ #include "sysbus.h" #include "hw.h" -#include "pc.h" -#include "net.h" +#include "serial.h" #include "flash.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "devices.h" #include "boards.h" -#include "device_tree.h" +#include "sysemu/device_tree.h" #include "loader.h" #include "elf.h" -#include "qemu-log.h" -#include "exec-memory.h" +#include "qemu/log.h" +#include "exec/address-spaces.h" #include "ppc.h" #include "ppc4xx.h" #include "ppc405.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "xilinx.h" #define EPAPR_MAGIC (0x45504150) @@ -58,7 +57,7 @@ static struct boot_info /* Create reset TLB entries for BookE, spanning the 32bit addr space. */ static void mmubooke_create_initial_mapping(CPUPPCState *env, target_ulong va, - target_phys_addr_t pa) + hwaddr pa) { ppcemb_tlb_t *tlb = &env->tlb.tlbe[0]; @@ -94,7 +93,7 @@ static PowerPCCPU *ppc440_init_xilinx(ram_addr_t *ram_size, } env = &cpu->env; - ppc_booke_timers_init(env, sysclk, 0/* no flags */); + ppc_booke_timers_init(cpu, sysclk, 0/* no flags */); ppc_dcr_init(env, NULL, NULL); @@ -134,10 +133,10 @@ static void main_cpu_reset(void *opaque) } #define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb" -static int xilinx_load_device_tree(target_phys_addr_t addr, +static int xilinx_load_device_tree(hwaddr addr, uint32_t ramsize, - target_phys_addr_t initrd_base, - target_phys_addr_t initrd_size, + hwaddr initrd_base, + hwaddr initrd_size, const char *kernel_cmdline) { char *path; @@ -183,17 +182,17 @@ static int xilinx_load_device_tree(target_phys_addr_t addr, return fdt_size; } -static void virtex_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void virtex_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; MemoryRegion *address_space_mem = get_system_memory(); DeviceState *dev; PowerPCCPU *cpu; CPUPPCState *env; - target_phys_addr_t ram_base = 0; + hwaddr ram_base = 0; DriveInfo *dinfo; MemoryRegion *phys_ram = g_new(MemoryRegion, 1); qemu_irq irq[32], *cpu_irq; @@ -233,7 +232,7 @@ static void virtex_init(ram_addr_t ram_size, if (kernel_filename) { uint64_t entry, low, high; - target_phys_addr_t boot_offset; + hwaddr boot_offset; /* Boots a kernel elf binary. */ kernel_size = load_elf(kernel_filename, NULL, NULL, diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index dd1a6506cf..3040bc63ab 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -13,15 +13,15 @@ * */ -#include "iov.h" +#include "qemu/iov.h" #include "qemu-common.h" #include "virtio.h" #include "pc.h" #include "cpu.h" -#include "balloon.h" +#include "sysemu/balloon.h" #include "virtio-balloon.h" -#include "kvm.h" -#include "exec-memory.h" +#include "sysemu/kvm.h" +#include "exec/address-spaces.h" #if defined(__linux__) #include <sys/mman.h> diff --git a/hw/virtio-balloon.h b/hw/virtio-balloon.h index 73300ddc86..b1828f4a48 100644 --- a/hw/virtio-balloon.h +++ b/hw/virtio-balloon.h @@ -16,7 +16,7 @@ #define _QEMU_VIRTIO_BALLOON_H #include "virtio.h" -#include "pci.h" +#include "pci/pci.h" /* from Linux's linux/virtio_balloon.h */ diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index fd8fa90792..df57b35f1b 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -12,11 +12,14 @@ */ #include "qemu-common.h" -#include "qemu-error.h" +#include "qemu/error-report.h" #include "trace.h" #include "hw/block-common.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "virtio-blk.h" +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE +#include "hw/dataplane/virtio-blk.h" +#endif #include "scsi-defs.h" #ifdef __linux__ # include <scsi/sg.h> @@ -33,6 +36,9 @@ typedef struct VirtIOBlock VirtIOBlkConf *blk; unsigned short sector_mask; DeviceState *qdev; +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + VirtIOBlockDataPlane *dataplane; +#endif } VirtIOBlock; static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev) @@ -64,31 +70,22 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, int status) } static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error, - int is_read) + bool is_read) { - BlockErrorAction action = bdrv_get_on_error(req->dev->bs, is_read); + BlockErrorAction action = bdrv_get_error_action(req->dev->bs, is_read, error); VirtIOBlock *s = req->dev; - if (action == BLOCK_ERR_IGNORE) { - bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_IGNORE, is_read); - return 0; - } - - if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) - || action == BLOCK_ERR_STOP_ANY) { + if (action == BDRV_ACTION_STOP) { req->next = s->rq; s->rq = req; - bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_STOP, is_read); - vm_stop(RUN_STATE_IO_ERROR); - bdrv_iostatus_set_err(s->bs, error); - } else { + } else if (action == BDRV_ACTION_REPORT) { virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR); bdrv_acct_done(s->bs, &req->acct); g_free(req); - bdrv_emit_qmp_error_event(s->bs, BDRV_ACTION_REPORT, is_read); } - return 1; + bdrv_error_action(s->bs, action, is_read, error); + return action != BDRV_ACTION_IGNORE; } static void virtio_blk_rw_complete(void *opaque, int ret) @@ -98,7 +95,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret) trace_virtio_blk_rw_complete(req, ret); if (ret) { - int is_read = !(ldl_p(&req->out->type) & VIRTIO_BLK_T_OUT); + bool is_read = !(ldl_p(&req->out->type) & VIRTIO_BLK_T_OUT); if (virtio_blk_handle_rw_error(req, -ret, is_read)) return; } @@ -401,10 +398,14 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req, qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1], req->elem.out_num - 1); virtio_blk_handle_write(req, mrb); - } else { + } else if (type == VIRTIO_BLK_T_IN || type == VIRTIO_BLK_T_BARRIER) { + /* VIRTIO_BLK_T_IN is 0, so we can't just & it. */ qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0], req->elem.in_num - 1); virtio_blk_handle_read(req); + } else { + virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP); + g_free(req); } } @@ -416,6 +417,16 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) .num_writes = 0, }; +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start + * dataplane here instead of waiting for .set_status(). + */ + if (s->dataplane) { + virtio_blk_data_plane_start(s->dataplane); + return; + } +#endif + while ((req = virtio_blk_get_request(s))) { virtio_blk_handle_request(req, &mrb); } @@ -455,8 +466,9 @@ static void virtio_blk_dma_restart_cb(void *opaque, int running, { VirtIOBlock *s = opaque; - if (!running) + if (!running) { return; + } if (!s->bh) { s->bh = qemu_bh_new(virtio_blk_dma_restart_bh, s); @@ -466,6 +478,14 @@ static void virtio_blk_dma_restart_cb(void *opaque, int running, static void virtio_blk_reset(VirtIODevice *vdev) { +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + VirtIOBlock *s = to_virtio_blk(vdev); + + if (s->dataplane) { + virtio_blk_data_plane_stop(s->dataplane); + } +#endif + /* * This should cancel pending requests, but can't do nicely until there * are per-device request lists. @@ -533,7 +553,9 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features) features |= (1 << VIRTIO_BLK_F_BLK_SIZE); features |= (1 << VIRTIO_BLK_F_SCSI); - features |= (1 << VIRTIO_BLK_F_CONFIG_WCE); + if (s->blk->config_wce) { + features |= (1 << VIRTIO_BLK_F_CONFIG_WCE); + } if (bdrv_enable_write_cache(s->bs)) features |= (1 << VIRTIO_BLK_F_WCE); @@ -548,6 +570,12 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) VirtIOBlock *s = to_virtio_blk(vdev); uint32_t features; +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + if (s->dataplane && !(status & VIRTIO_CONFIG_S_DRIVER)) { + virtio_blk_data_plane_stop(s->dataplane); + } +#endif + if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) { return; } @@ -645,6 +673,12 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk) s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1; s->vq = virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output); +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + if (!virtio_blk_data_plane_create(&s->vdev, blk, &s->dataplane)) { + virtio_cleanup(&s->vdev); + return NULL; + } +#endif qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); s->qdev = dev; @@ -662,6 +696,11 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk) void virtio_blk_exit(VirtIODevice *vdev) { VirtIOBlock *s = to_virtio_blk(vdev); + +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + virtio_blk_data_plane_destroy(s->dataplane); + s->dataplane = NULL; +#endif unregister_savevm(s->qdev, "virtio-blk", s); blockdev_mark_auto_del(s->bs); virtio_cleanup(vdev); diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h index 35834cf493..43ca492080 100644 --- a/hw/virtio-blk.h +++ b/hw/virtio-blk.h @@ -104,6 +104,8 @@ struct VirtIOBlkConf BlockConf conf; char *serial; uint32_t scsi; + uint32_t config_wce; + uint32_t data_plane; }; #define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \ diff --git a/hw/virtio-console.c b/hw/virtio-console.c index cffee3d470..002b028b99 100644 --- a/hw/virtio-console.c +++ b/hw/virtio-console.c @@ -10,8 +10,8 @@ * the COPYING file in the top-level directory. */ -#include "qemu-char.h" -#include "qemu-error.h" +#include "char/char.h" +#include "qemu/error-report.h" #include "trace.h" #include "virtio-serial.h" diff --git a/hw/virtio-net.c b/hw/virtio-net.c index b1998b27d3..5d03b31c1b 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -11,13 +11,13 @@ * */ -#include "iov.h" +#include "qemu/iov.h" #include "virtio.h" -#include "net.h" +#include "net/net.h" #include "net/checksum.h" #include "net/tap.h" -#include "qemu-error.h" -#include "qemu-timer.h" +#include "qemu/error-report.h" +#include "qemu/timer.h" #include "virtio-net.h" #include "vhost_net.h" @@ -41,6 +41,8 @@ typedef struct VirtIONet int32_t tx_burst; int tx_waiting; uint32_t has_vnet_hdr; + size_t host_hdr_len; + size_t guest_hdr_len; uint8_t has_ufo; struct { VirtQueueElement elem; @@ -200,16 +202,19 @@ static void virtio_net_reset(VirtIODevice *vdev) memset(n->vlans, 0, MAX_VLAN >> 3); } -static int peer_has_vnet_hdr(VirtIONet *n) +static void peer_test_vnet_hdr(VirtIONet *n) { if (!n->nic->nc.peer) - return 0; + return; if (n->nic->nc.peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) - return 0; + return; n->has_vnet_hdr = tap_has_vnet_hdr(n->nic->nc.peer); +} +static int peer_has_vnet_hdr(VirtIONet *n) +{ return n->has_vnet_hdr; } @@ -223,15 +228,27 @@ static int peer_has_ufo(VirtIONet *n) return n->has_ufo; } +static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs) +{ + n->mergeable_rx_bufs = mergeable_rx_bufs; + + n->guest_hdr_len = n->mergeable_rx_bufs ? + sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr); + + if (peer_has_vnet_hdr(n) && + tap_has_vnet_hdr_len(n->nic->nc.peer, n->guest_hdr_len)) { + tap_set_vnet_hdr_len(n->nic->nc.peer, n->guest_hdr_len); + n->host_hdr_len = n->guest_hdr_len; + } +} + static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features) { VirtIONet *n = to_virtio_net(vdev); features |= (1 << VIRTIO_NET_F_MAC); - if (peer_has_vnet_hdr(n)) { - tap_using_vnet_hdr(n->nic->nc.peer, 1); - } else { + if (!peer_has_vnet_hdr(n)) { features &= ~(0x1 << VIRTIO_NET_F_CSUM); features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO4); features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO6); @@ -277,7 +294,7 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features) { VirtIONet *n = to_virtio_net(vdev); - n->mergeable_rx_bufs = !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF)); + virtio_net_set_mrg_rx_bufs(n, !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF))); if (n->has_vnet_hdr) { tap_set_offload(n->nic->nc.peer, @@ -447,10 +464,6 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) VirtIONet *n = to_virtio_net(vdev); qemu_flush_queued_packets(&n->nic->nc); - - /* We now have RX buffers, signal to the IO thread to break out of the - * select to re-poll the tap file descriptor */ - qemu_notify_event(); } static int virtio_net_can_receive(NetClientState *nc) @@ -503,41 +516,34 @@ static int virtio_net_has_buffers(VirtIONet *n, int bufsize) * cache. */ static void work_around_broken_dhclient(struct virtio_net_hdr *hdr, - const uint8_t *buf, size_t size) + uint8_t *buf, size_t size) { if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */ (size > 27 && size < 1500) && /* normal sized MTU */ (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */ (buf[23] == 17) && /* ip.protocol == UDP */ (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */ - /* FIXME this cast is evil */ - net_checksum_calculate((uint8_t *)buf, size); + net_checksum_calculate(buf, size); hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM; } } -static int receive_header(VirtIONet *n, struct iovec *iov, int iovcnt, - const void *buf, size_t size, size_t hdr_len) +static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt, + const void *buf, size_t size) { - struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)iov[0].iov_base; - int offset = 0; - - hdr->flags = 0; - hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE; - if (n->has_vnet_hdr) { - memcpy(hdr, buf, sizeof(*hdr)); - offset = sizeof(*hdr); - work_around_broken_dhclient(hdr, buf + offset, size - offset); + /* FIXME this cast is evil */ + void *wbuf = (void *)buf; + work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len, + size - n->host_hdr_len); + iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr)); + } else { + struct virtio_net_hdr hdr = { + .flags = 0, + .gso_type = VIRTIO_NET_HDR_GSO_NONE + }; + iov_from_buf(iov, iov_cnt, 0, &hdr, sizeof hdr); } - - /* We only ever receive a struct virtio_net_hdr from the tapfd, - * but we may be passing along a larger header to the guest. - */ - iov[0].iov_base += hdr_len; - iov[0].iov_len -= hdr_len; - - return offset; } static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) @@ -550,9 +556,7 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) if (n->promisc) return 1; - if (n->has_vnet_hdr) { - ptr += sizeof(struct virtio_net_hdr); - } + ptr += n->host_hdr_len; if (!memcmp(&ptr[12], vlan, sizeof(vlan))) { int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff; @@ -596,19 +600,16 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t size) { VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque; - struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL; - size_t guest_hdr_len, offset, i, host_hdr_len; + struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE]; + struct virtio_net_hdr_mrg_rxbuf mhdr; + unsigned mhdr_cnt = 0; + size_t offset, i, guest_offset; if (!virtio_net_can_receive(&n->nic->nc)) return -1; /* hdr_len refers to the header we supply to the guest */ - guest_hdr_len = n->mergeable_rx_bufs ? - sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr); - - - host_hdr_len = n->has_vnet_hdr ? sizeof(struct virtio_net_hdr) : 0; - if (!virtio_net_has_buffers(n, size + guest_hdr_len - host_hdr_len)) + if (!virtio_net_has_buffers(n, size + n->guest_hdr_len - n->host_hdr_len)) return 0; if (!receive_filter(n, buf, size)) @@ -619,7 +620,7 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t while (offset < size) { VirtQueueElement elem; int len, total; - struct iovec sg[VIRTQUEUE_MAX_SIZE]; + const struct iovec *sg = elem.in_sg; total = 0; @@ -630,7 +631,7 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t "i %zd mergeable %d offset %zd, size %zd, " "guest hdr len %zd, host hdr len %zd guest features 0x%x", i, n->mergeable_rx_bufs, offset, size, - guest_hdr_len, host_hdr_len, n->vdev.guest_features); + n->guest_hdr_len, n->host_hdr_len, n->vdev.guest_features); exit(1); } @@ -639,24 +640,25 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t exit(1); } - if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != guest_hdr_len) { - error_report("virtio-net header not in first element"); - exit(1); - } - - memcpy(&sg, &elem.in_sg[0], sizeof(sg[0]) * elem.in_num); - if (i == 0) { - if (n->mergeable_rx_bufs) - mhdr = (struct virtio_net_hdr_mrg_rxbuf *)sg[0].iov_base; + assert(offset == 0); + if (n->mergeable_rx_bufs) { + mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg), + sg, elem.in_num, + offsetof(typeof(mhdr), num_buffers), + sizeof(mhdr.num_buffers)); + } - offset += receive_header(n, sg, elem.in_num, - buf + offset, size - offset, guest_hdr_len); - total += guest_hdr_len; + receive_header(n, sg, elem.in_num, buf, size); + offset = n->host_hdr_len; + total += n->guest_hdr_len; + guest_offset = n->guest_hdr_len; + } else { + guest_offset = 0; } /* copy in packet. ugh */ - len = iov_from_buf(sg, elem.in_num, 0, + len = iov_from_buf(sg, elem.in_num, guest_offset, buf + offset, size - offset); total += len; offset += len; @@ -669,7 +671,7 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t "i %zd mergeable %d offset %zd, size %zd, " "guest hdr len %zd, host hdr len %zd", i, n->mergeable_rx_bufs, - offset, size, guest_hdr_len, host_hdr_len); + offset, size, n->guest_hdr_len, n->host_hdr_len); #endif return size; } @@ -678,8 +680,11 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t virtqueue_fill(n->rx_vq, &elem, total, i++); } - if (mhdr) { - stw_p(&mhdr->num_buffers, i); + if (mhdr_cnt) { + stw_p(&mhdr.num_buffers, i); + iov_from_buf(mhdr_sg, mhdr_cnt, + 0, + &mhdr.num_buffers, sizeof mhdr.num_buffers); } virtqueue_flush(n->rx_vq, i); @@ -694,7 +699,7 @@ static void virtio_net_tx_complete(NetClientState *nc, ssize_t len) { VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque; - virtqueue_push(n->tx_vq, &n->async_tx.elem, n->async_tx.len); + virtqueue_push(n->tx_vq, &n->async_tx.elem, 0); virtio_notify(&n->vdev, n->tx_vq); n->async_tx.elem.out_num = n->async_tx.len = 0; @@ -720,33 +725,35 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq) } while (virtqueue_pop(vq, &elem)) { - ssize_t ret, len = 0; + ssize_t ret, len; unsigned int out_num = elem.out_num; struct iovec *out_sg = &elem.out_sg[0]; - unsigned hdr_len; - - /* hdr_len refers to the header received from the guest */ - hdr_len = n->mergeable_rx_bufs ? - sizeof(struct virtio_net_hdr_mrg_rxbuf) : - sizeof(struct virtio_net_hdr); + struct iovec sg[VIRTQUEUE_MAX_SIZE]; - if (out_num < 1 || out_sg->iov_len != hdr_len) { + if (out_num < 1) { error_report("virtio-net header not in first element"); exit(1); } - /* ignore the header if GSO is not supported */ - if (!n->has_vnet_hdr) { - out_num--; - out_sg++; - len += hdr_len; - } else if (n->mergeable_rx_bufs) { - /* tapfd expects a struct virtio_net_hdr */ - hdr_len -= sizeof(struct virtio_net_hdr); - out_sg->iov_len -= hdr_len; - len += hdr_len; + /* + * If host wants to see the guest header as is, we can + * pass it on unchanged. Otherwise, copy just the parts + * that host is interested in. + */ + assert(n->host_hdr_len <= n->guest_hdr_len); + if (n->host_hdr_len != n->guest_hdr_len) { + unsigned sg_num = iov_copy(sg, ARRAY_SIZE(sg), + out_sg, out_num, + 0, n->host_hdr_len); + sg_num += iov_copy(sg + sg_num, ARRAY_SIZE(sg) - sg_num, + out_sg, out_num, + n->guest_hdr_len, -1); + out_num = sg_num; + out_sg = sg; } + len = n->guest_hdr_len; + ret = qemu_sendv_packet_async(&n->nic->nc, out_sg, out_num, virtio_net_tx_complete); if (ret == 0) { @@ -758,7 +765,7 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq) len += ret; - virtqueue_push(vq, &elem, len); + virtqueue_push(vq, &elem, 0); virtio_notify(&n->vdev, vq); if (++num_packets >= n->tx_burst) { @@ -903,7 +910,8 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) qemu_get_buffer(f, n->mac, ETH_ALEN); n->tx_waiting = qemu_get_be32(f); - n->mergeable_rx_bufs = qemu_get_be32(f); + + virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f)); if (version_id >= 3) n->status = qemu_get_be16(f); @@ -925,7 +933,9 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) qemu_get_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN); } else if (n->mac_table.in_use) { - qemu_fseek(f, n->mac_table.in_use * ETH_ALEN, SEEK_CUR); + uint8_t *buf = g_malloc0(n->mac_table.in_use); + qemu_get_buffer(f, buf, n->mac_table.in_use * ETH_ALEN); + g_free(buf); n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1; n->mac_table.in_use = 0; } @@ -941,7 +951,6 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) } if (n->has_vnet_hdr) { - tap_using_vnet_hdr(n->nic->nc.peer, 1); tap_set_offload(n->nic->nc.peer, (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_CSUM) & 1, (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_TSO4) & 1, @@ -977,6 +986,11 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) } } n->mac_table.first_multi = i; + + /* nc.link_down can't be migrated, so infer link_down according + * to link status bit in n->status */ + n->nic->nc.link_down = (n->status & VIRTIO_NET_S_LINK_UP) == 0; + return 0; } @@ -1035,12 +1049,19 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, n->status = VIRTIO_NET_S_LINK_UP; n->nic = qemu_new_nic(&net_virtio_info, conf, object_get_typename(OBJECT(dev)), dev->id, n); + peer_test_vnet_hdr(n); + if (peer_has_vnet_hdr(n)) { + tap_using_vnet_hdr(n->nic->nc.peer, 1); + n->host_hdr_len = sizeof(struct virtio_net_hdr); + } else { + n->host_hdr_len = 0; + } qemu_format_nic_info_str(&n->nic->nc, conf->macaddr.a); n->tx_waiting = 0; n->tx_burst = net->txburst; - n->mergeable_rx_bufs = 0; + virtio_net_set_mrg_rx_bufs(n, 0); n->promisc = 1; /* for compatibility */ n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN); diff --git a/hw/virtio-net.h b/hw/virtio-net.h index 36aa463812..d46fb9840f 100644 --- a/hw/virtio-net.h +++ b/hw/virtio-net.h @@ -15,8 +15,7 @@ #define _QEMU_VIRTIO_NET_H #include "virtio.h" -#include "net.h" -#include "pci.h" +#include "pci/pci.h" #define ETH_ALEN 6 @@ -74,33 +73,6 @@ struct virtio_net_config uint16_t status; } QEMU_PACKED; -/* This is the first element of the scatter-gather list. If you don't - * specify GSO or CSUM features, you can simply ignore the header. */ -struct virtio_net_hdr -{ -#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 // Use csum_start, csum_offset -#define VIRTIO_NET_HDR_F_DATA_VALID 2 // Csum is valid - uint8_t flags; -#define VIRTIO_NET_HDR_GSO_NONE 0 // Not a GSO frame -#define VIRTIO_NET_HDR_GSO_TCPV4 1 // GSO frame, IPv4 TCP (TSO) -#define VIRTIO_NET_HDR_GSO_UDP 3 // GSO frame, IPv4 UDP (UFO) -#define VIRTIO_NET_HDR_GSO_TCPV6 4 // GSO frame, IPv6 TCP -#define VIRTIO_NET_HDR_GSO_ECN 0x80 // TCP has ECN set - uint8_t gso_type; - uint16_t hdr_len; - uint16_t gso_size; - uint16_t csum_start; - uint16_t csum_offset; -}; - -/* This is the version of the header to use when the MRG_RXBUF - * feature has been negotiated. */ -struct virtio_net_hdr_mrg_rxbuf -{ - struct virtio_net_hdr hdr; - uint16_t num_buffers; /* Number of merged rx buffers */ -}; - /* * Control virtqueue data structures * diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 5e6e09efb7..c7f0c4d4ed 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -22,16 +22,15 @@ #include "virtio-net.h" #include "virtio-serial.h" #include "virtio-scsi.h" -#include "pci.h" -#include "qemu-error.h" -#include "msi.h" -#include "msix.h" -#include "net.h" +#include "pci/pci.h" +#include "qemu/error-report.h" +#include "pci/msi.h" +#include "pci/msix.h" #include "loader.h" -#include "kvm.h" -#include "blockdev.h" +#include "sysemu/kvm.h" +#include "sysemu/blockdev.h" #include "virtio-pci.h" -#include "range.h" +#include "qemu/range.h" /* from Linux's linux/virtio_pci.h */ @@ -97,40 +96,54 @@ bool virtio_is_big_endian(void); /* virtio device */ +/* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */ +static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d) +{ + return container_of(d, VirtIOPCIProxy, pci_dev.qdev); +} -static void virtio_pci_notify(void *opaque, uint16_t vector) +/* DeviceState to VirtIOPCIProxy. Note: used on datapath, + * be careful and test performance if you change this. + */ +static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d) { - VirtIOPCIProxy *proxy = opaque; + return container_of(d, VirtIOPCIProxy, pci_dev.qdev); +} + +static void virtio_pci_notify(DeviceState *d, uint16_t vector) +{ + VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d); if (msix_enabled(&proxy->pci_dev)) msix_notify(&proxy->pci_dev, vector); else qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1); } -static void virtio_pci_save_config(void * opaque, QEMUFile *f) +static void virtio_pci_save_config(DeviceState *d, QEMUFile *f) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); pci_device_save(&proxy->pci_dev, f); msix_save(&proxy->pci_dev, f); if (msix_present(&proxy->pci_dev)) qemu_put_be16(f, proxy->vdev->config_vector); } -static void virtio_pci_save_queue(void * opaque, int n, QEMUFile *f) +static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); if (msix_present(&proxy->pci_dev)) qemu_put_be16(f, virtio_queue_vector(proxy->vdev, n)); } -static int virtio_pci_load_config(void * opaque, QEMUFile *f) +static int virtio_pci_load_config(DeviceState *d, QEMUFile *f) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); int ret; ret = pci_device_load(&proxy->pci_dev, f); if (ret) { return ret; } + msix_unuse_all_vectors(&proxy->pci_dev); msix_load(&proxy->pci_dev, f); if (msix_present(&proxy->pci_dev)) { qemu_get_be16s(f, &proxy->vdev->config_vector); @@ -143,9 +156,9 @@ static int virtio_pci_load_config(void * opaque, QEMUFile *f) return 0; } -static int virtio_pci_load_queue(void * opaque, int n, QEMUFile *f) +static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); uint16_t vector; if (msix_present(&proxy->pci_dev)) { qemu_get_be16s(f, &vector); @@ -243,9 +256,10 @@ static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy) void virtio_pci_reset(DeviceState *d) { - VirtIOPCIProxy *proxy = container_of(d, VirtIOPCIProxy, pci_dev.qdev); + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); virtio_pci_stop_ioeventfd(proxy); virtio_reset(proxy->vdev); + msix_unuse_all_vectors(&proxy->pci_dev); proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG; } @@ -253,7 +267,7 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) { VirtIOPCIProxy *proxy = opaque; VirtIODevice *vdev = proxy->vdev; - target_phys_addr_t pa; + hwaddr pa; switch (addr) { case VIRTIO_PCI_GUEST_FEATURES: @@ -264,7 +278,7 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) virtio_set_features(vdev, val); break; case VIRTIO_PCI_QUEUE_PFN: - pa = (target_phys_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; + pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; if (pa == 0) { virtio_pci_stop_ioeventfd(proxy); virtio_reset(proxy->vdev); @@ -372,79 +386,39 @@ static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr) return ret; } -static uint32_t virtio_pci_config_readb(void *opaque, uint32_t addr) -{ - VirtIOPCIProxy *proxy = opaque; - uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); - if (addr < config) - return virtio_ioport_read(proxy, addr); - addr -= config; - return virtio_config_readb(proxy->vdev, addr); -} - -static uint32_t virtio_pci_config_readw(void *opaque, uint32_t addr) -{ - VirtIOPCIProxy *proxy = opaque; - uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); - uint16_t val; - if (addr < config) - return virtio_ioport_read(proxy, addr); - addr -= config; - val = virtio_config_readw(proxy->vdev, addr); - if (virtio_is_big_endian()) { - /* - * virtio is odd, ioports are LE but config space is target native - * endian. However, in qemu, all PIO is LE, so we need to re-swap - * on BE targets - */ - val = bswap16(val); - } - return val; -} - -static uint32_t virtio_pci_config_readl(void *opaque, uint32_t addr) -{ - VirtIOPCIProxy *proxy = opaque; - uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); - uint32_t val; - if (addr < config) - return virtio_ioport_read(proxy, addr); - addr -= config; - val = virtio_config_readl(proxy->vdev, addr); - if (virtio_is_big_endian()) { - val = bswap32(val); - } - return val; -} - -static void virtio_pci_config_writeb(void *opaque, uint32_t addr, uint32_t val) +static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr, + unsigned size) { VirtIOPCIProxy *proxy = opaque; uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); + uint64_t val = 0; if (addr < config) { - virtio_ioport_write(proxy, addr, val); - return; + return virtio_ioport_read(proxy, addr); } addr -= config; - virtio_config_writeb(proxy->vdev, addr, val); -} -static void virtio_pci_config_writew(void *opaque, uint32_t addr, uint32_t val) -{ - VirtIOPCIProxy *proxy = opaque; - uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); - if (addr < config) { - virtio_ioport_write(proxy, addr, val); - return; - } - addr -= config; - if (virtio_is_big_endian()) { - val = bswap16(val); + switch (size) { + case 1: + val = virtio_config_readb(proxy->vdev, addr); + break; + case 2: + val = virtio_config_readw(proxy->vdev, addr); + if (virtio_is_big_endian()) { + val = bswap16(val); + } + break; + case 4: + val = virtio_config_readl(proxy->vdev, addr); + if (virtio_is_big_endian()) { + val = bswap32(val); + } + break; } - virtio_config_writew(proxy->vdev, addr, val); + return val; } -static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val) +static void virtio_pci_config_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { VirtIOPCIProxy *proxy = opaque; uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); @@ -453,24 +427,36 @@ static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val) return; } addr -= config; - if (virtio_is_big_endian()) { - val = bswap32(val); + /* + * Virtio-PCI is odd. Ioports are LE but config space is target native + * endian. + */ + switch (size) { + case 1: + virtio_config_writeb(proxy->vdev, addr, val); + break; + case 2: + if (virtio_is_big_endian()) { + val = bswap16(val); + } + virtio_config_writew(proxy->vdev, addr, val); + break; + case 4: + if (virtio_is_big_endian()) { + val = bswap32(val); + } + virtio_config_writel(proxy->vdev, addr, val); + break; } - virtio_config_writel(proxy->vdev, addr, val); } -static const MemoryRegionPortio virtio_portio[] = { - { 0, 0x10000, 1, .write = virtio_pci_config_writeb, }, - { 0, 0x10000, 2, .write = virtio_pci_config_writew, }, - { 0, 0x10000, 4, .write = virtio_pci_config_writel, }, - { 0, 0x10000, 1, .read = virtio_pci_config_readb, }, - { 0, 0x10000, 2, .read = virtio_pci_config_readw, }, - { 0, 0x10000, 4, .read = virtio_pci_config_readl, }, - PORTIO_END_OF_LIST() -}; - static const MemoryRegionOps virtio_pci_config_ops = { - .old_portio = virtio_portio, + .read = virtio_pci_config_read, + .write = virtio_pci_config_write, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, .endianness = DEVICE_LITTLE_ENDIAN, }; @@ -490,9 +476,9 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, } } -static unsigned virtio_pci_get_features(void *opaque) +static unsigned virtio_pci_get_features(DeviceState *d) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); return proxy->host_features; } @@ -515,15 +501,13 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, } irqfd->users++; - ret = kvm_irqchip_add_irq_notifier(kvm_state, n, irqfd->virq); + ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq); if (ret < 0) { if (--irqfd->users == 0) { kvm_irqchip_release_virq(kvm_state, irqfd->virq); } return ret; } - - virtio_queue_set_guest_notifier_fd_handler(vq, true, true); return 0; } @@ -536,14 +520,12 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; int ret; - ret = kvm_irqchip_remove_irq_notifier(kvm_state, n, irqfd->virq); + ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq); assert(ret == 0); if (--irqfd->users == 0) { kvm_irqchip_release_virq(kvm_state, irqfd->virq); } - - virtio_queue_set_guest_notifier_fd_handler(vq, true, false); } static int kvm_virtio_pci_vector_use(PCIDevice *dev, unsigned vector, @@ -594,9 +576,38 @@ static void kvm_virtio_pci_vector_release(PCIDevice *dev, unsigned vector) } } -static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign) +static void kvm_virtio_pci_vector_poll(PCIDevice *dev, + unsigned int vector_start, + unsigned int vector_end) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); + VirtIODevice *vdev = proxy->vdev; + int queue_no; + unsigned int vector; + EventNotifier *notifier; + VirtQueue *vq; + + for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } + vector = virtio_queue_vector(vdev, queue_no); + if (vector < vector_start || vector >= vector_end || + !msix_is_masked(dev, vector)) { + continue; + } + vq = virtio_get_queue(vdev, queue_no); + notifier = virtio_queue_get_guest_notifier(vq); + if (event_notifier_test_and_clear(notifier)) { + msix_set_pending(dev, vector); + } + } +} + +static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, + bool with_irqfd) +{ + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); VirtQueue *vq = virtio_get_queue(proxy->vdev, n); EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); @@ -605,29 +616,31 @@ static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign) if (r < 0) { return r; } - virtio_queue_set_guest_notifier_fd_handler(vq, true, false); + virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); } else { - virtio_queue_set_guest_notifier_fd_handler(vq, false, false); + virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); event_notifier_cleanup(notifier); } return 0; } -static bool virtio_pci_query_guest_notifiers(void *opaque) +static bool virtio_pci_query_guest_notifiers(DeviceState *d) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); return msix_enabled(&proxy->pci_dev); } -static int virtio_pci_set_guest_notifiers(void *opaque, bool assign) +static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); VirtIODevice *vdev = proxy->vdev; int r, n; + bool with_irqfd = msix_enabled(&proxy->pci_dev) && + kvm_msi_via_irqfd_enabled(); /* Must unset vector notifier while guest notifier is still assigned */ - if (kvm_msi_via_irqfd_enabled() && !assign) { + if (proxy->vector_irqfd && !assign) { msix_unset_vector_notifiers(&proxy->pci_dev); g_free(proxy->vector_irqfd); proxy->vector_irqfd = NULL; @@ -638,20 +651,22 @@ static int virtio_pci_set_guest_notifiers(void *opaque, bool assign) break; } - r = virtio_pci_set_guest_notifier(opaque, n, assign); + r = virtio_pci_set_guest_notifier(d, n, assign, + kvm_msi_via_irqfd_enabled()); if (r < 0) { goto assign_error; } } /* Must set vector notifier after guest notifier has been assigned */ - if (kvm_msi_via_irqfd_enabled() && assign) { + if (with_irqfd && assign) { proxy->vector_irqfd = g_malloc0(sizeof(*proxy->vector_irqfd) * msix_nr_vectors_allocated(&proxy->pci_dev)); r = msix_set_vector_notifiers(&proxy->pci_dev, kvm_virtio_pci_vector_use, - kvm_virtio_pci_vector_release); + kvm_virtio_pci_vector_release, + kvm_virtio_pci_vector_poll); if (r < 0) { goto assign_error; } @@ -663,14 +678,14 @@ assign_error: /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ assert(assign); while (--n >= 0) { - virtio_pci_set_guest_notifier(opaque, n, !assign); + virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd); } return r; } -static int virtio_pci_set_host_notifier(void *opaque, int n, bool assign) +static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); /* Stop using ioeventfd for virtqueue kick if the device starts using host * notifiers. This makes it easy to avoid stepping on each others' toes. @@ -686,9 +701,9 @@ static int virtio_pci_set_host_notifier(void *opaque, int n, bool assign) return virtio_pci_set_host_notifier_internal(proxy, n, assign, false); } -static void virtio_pci_vmstate_change(void *opaque, bool running) +static void virtio_pci_vmstate_change(DeviceState *d, bool running) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); if (running) { /* Try to find out if the guest has bus master disabled, but is @@ -753,7 +768,7 @@ void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev) proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD; } - virtio_bind_device(vdev, &virtio_pci_bindings, proxy); + virtio_bind_device(vdev, &virtio_pci_bindings, DEVICE(proxy)); proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY; proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE; proxy->host_features = vdev->get_features(vdev, proxy->host_features); @@ -878,6 +893,41 @@ static void virtio_balloon_exit_pci(PCIDevice *pci_dev) virtio_exit_pci(pci_dev); } +static int virtio_rng_init_pci(PCIDevice *pci_dev) +{ + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); + VirtIODevice *vdev; + + if (proxy->rng.rng == NULL) { + proxy->rng.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM)); + + object_property_add_child(OBJECT(pci_dev), + "default-backend", + OBJECT(proxy->rng.default_backend), + NULL); + + object_property_set_link(OBJECT(pci_dev), + OBJECT(proxy->rng.default_backend), + "rng", NULL); + } + + vdev = virtio_rng_init(&pci_dev->qdev, &proxy->rng); + if (!vdev) { + return -1; + } + virtio_init_pci(proxy, vdev); + return 0; +} + +static void virtio_rng_exit_pci(PCIDevice *pci_dev) +{ + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); + + virtio_pci_stop_ioeventfd(proxy); + virtio_rng_exit(proxy->vdev); + virtio_exit_pci(pci_dev); +} + static Property virtio_blk_properties[] = { DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, blk.conf), @@ -886,7 +936,11 @@ static Property virtio_blk_properties[] = { #ifdef __linux__ DEFINE_PROP_BIT("scsi", VirtIOPCIProxy, blk.scsi, 0, true), #endif + DEFINE_PROP_BIT("config-wce", VirtIOPCIProxy, blk.config_wce, 0, true), DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + DEFINE_PROP_BIT("x-data-plane", VirtIOPCIProxy, blk.data_plane, 0, false), +#endif DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features), DEFINE_PROP_END_OF_LIST(), @@ -1007,6 +1061,50 @@ static TypeInfo virtio_balloon_info = { .class_init = virtio_balloon_class_init, }; +static void virtio_rng_initfn(Object *obj) +{ + PCIDevice *pci_dev = PCI_DEVICE(obj); + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); + + object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, + (Object **)&proxy->rng.rng, NULL); +} + +static Property virtio_rng_properties[] = { + DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), + /* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s. If + you have an entropy source capable of generating more entropy than this + and you can pass it through via virtio-rng, then hats off to you. Until + then, this is unlimited for all practical purposes. + */ + DEFINE_PROP_UINT64("max-bytes", VirtIOPCIProxy, rng.max_bytes, INT64_MAX), + DEFINE_PROP_UINT32("period", VirtIOPCIProxy, rng.period_ms, 1 << 16), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_rng_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = virtio_rng_init_pci; + k->exit = virtio_rng_exit_pci; + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + k->device_id = PCI_DEVICE_ID_VIRTIO_RNG; + k->revision = VIRTIO_PCI_ABI_VERSION; + k->class_id = PCI_CLASS_OTHERS; + dc->reset = virtio_pci_reset; + dc->props = virtio_rng_properties; +} + +static TypeInfo virtio_rng_info = { + .name = "virtio-rng-pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VirtIOPCIProxy), + .instance_init = virtio_rng_initfn, + .class_init = virtio_rng_class_init, +}; + static int virtio_scsi_init_pci(PCIDevice *pci_dev) { VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); @@ -1071,6 +1169,7 @@ static void virtio_pci_register_types(void) type_register_static(&virtio_serial_info); type_register_static(&virtio_balloon_info); type_register_static(&virtio_scsi_info); + type_register_static(&virtio_rng_info); } type_init(virtio_pci_register_types) diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index ac9d522f37..b58d9a2d19 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -17,6 +17,7 @@ #include "virtio-blk.h" #include "virtio-net.h" +#include "virtio-rng.h" #include "virtio-serial.h" #include "virtio-scsi.h" @@ -46,6 +47,7 @@ typedef struct { virtio_serial_conf serial; virtio_net_conf net; VirtIOSCSIConf scsi; + VirtIORNGConf rng; bool ioeventfd_disabled; bool ioeventfd_started; VirtIOIRQFD *vector_irqfd; diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c new file mode 100644 index 0000000000..e063127df6 --- /dev/null +++ b/hw/virtio-rng.c @@ -0,0 +1,205 @@ +/* + * A virtio device implementing a hardware random number generator. + * + * Copyright 2012 Red Hat, Inc. + * Copyright 2012 Amit Shah <amit.shah@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/iov.h" +#include "qdev.h" +#include "virtio.h" +#include "virtio-rng.h" +#include "qemu/rng.h" + +typedef struct VirtIORNG { + VirtIODevice vdev; + + DeviceState *qdev; + + /* Only one vq - guest puts buffer(s) on it when it needs entropy */ + VirtQueue *vq; + + VirtIORNGConf *conf; + + RngBackend *rng; + + /* We purposefully don't migrate this state. The quota will reset on the + * destination as a result. Rate limiting is host state, not guest state. + */ + QEMUTimer *rate_limit_timer; + int64_t quota_remaining; +} VirtIORNG; + +static bool is_guest_ready(VirtIORNG *vrng) +{ + if (virtio_queue_ready(vrng->vq) + && (vrng->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) { + return true; + } + return false; +} + +static size_t get_request_size(VirtQueue *vq, unsigned quota) +{ + unsigned int in, out; + + virtqueue_get_avail_bytes(vq, &in, &out, quota, 0); + return in; +} + +static void virtio_rng_process(VirtIORNG *vrng); + +/* Send data from a char device over to the guest */ +static void chr_read(void *opaque, const void *buf, size_t size) +{ + VirtIORNG *vrng = opaque; + VirtQueueElement elem; + size_t len; + int offset; + + if (!is_guest_ready(vrng)) { + return; + } + + vrng->quota_remaining -= size; + + offset = 0; + while (offset < size) { + if (!virtqueue_pop(vrng->vq, &elem)) { + break; + } + len = iov_from_buf(elem.in_sg, elem.in_num, + 0, buf + offset, size - offset); + offset += len; + + virtqueue_push(vrng->vq, &elem, len); + } + virtio_notify(&vrng->vdev, vrng->vq); +} + +static void virtio_rng_process(VirtIORNG *vrng) +{ + size_t size; + unsigned quota; + + if (!is_guest_ready(vrng)) { + return; + } + + if (vrng->quota_remaining < 0) { + quota = 0; + } else { + quota = MIN((uint64_t)vrng->quota_remaining, (uint64_t)UINT32_MAX); + } + size = get_request_size(vrng->vq, quota); + size = MIN(vrng->quota_remaining, size); + if (size) { + rng_backend_request_entropy(vrng->rng, size, chr_read, vrng); + } +} + +static void handle_input(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev); + virtio_rng_process(vrng); +} + +static uint32_t get_features(VirtIODevice *vdev, uint32_t f) +{ + return f; +} + +static void virtio_rng_save(QEMUFile *f, void *opaque) +{ + VirtIORNG *vrng = opaque; + + virtio_save(&vrng->vdev, f); +} + +static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id) +{ + VirtIORNG *vrng = opaque; + + if (version_id != 1) { + return -EINVAL; + } + virtio_load(&vrng->vdev, f); + + /* We may have an element ready but couldn't process it due to a quota + * limit. Make sure to try again after live migration when the quota may + * have been reset. + */ + virtio_rng_process(vrng); + + return 0; +} + +static void check_rate_limit(void *opaque) +{ + VirtIORNG *s = opaque; + + s->quota_remaining = s->conf->max_bytes; + virtio_rng_process(s); + qemu_mod_timer(s->rate_limit_timer, + qemu_get_clock_ms(vm_clock) + s->conf->period_ms); +} + + +VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf) +{ + VirtIORNG *vrng; + VirtIODevice *vdev; + Error *local_err = NULL; + + vdev = virtio_common_init("virtio-rng", VIRTIO_ID_RNG, 0, + sizeof(VirtIORNG)); + + vrng = DO_UPCAST(VirtIORNG, vdev, vdev); + + vrng->rng = conf->rng; + if (vrng->rng == NULL) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object"); + return NULL; + } + + rng_backend_open(vrng->rng, &local_err); + if (local_err) { + qerror_report_err(local_err); + error_free(local_err); + return NULL; + } + + vrng->vq = virtio_add_queue(vdev, 8, handle_input); + vrng->vdev.get_features = get_features; + + vrng->qdev = dev; + vrng->conf = conf; + + assert(vrng->conf->max_bytes <= INT64_MAX); + vrng->quota_remaining = vrng->conf->max_bytes; + + vrng->rate_limit_timer = qemu_new_timer_ms(vm_clock, + check_rate_limit, vrng); + + qemu_mod_timer(vrng->rate_limit_timer, + qemu_get_clock_ms(vm_clock) + vrng->conf->period_ms); + + register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save, + virtio_rng_load, vrng); + + return vdev; +} + +void virtio_rng_exit(VirtIODevice *vdev) +{ + VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev); + + qemu_del_timer(vrng->rate_limit_timer); + qemu_free_timer(vrng->rate_limit_timer); + unregister_savevm(vrng->qdev, "virtio-rng", vrng); + virtio_cleanup(vdev); +} diff --git a/hw/virtio-rng.h b/hw/virtio-rng.h new file mode 100644 index 0000000000..f42d748eba --- /dev/null +++ b/hw/virtio-rng.h @@ -0,0 +1,28 @@ +/* + * Virtio RNG Support + * + * Copyright Red Hat, Inc. 2012 + * Copyright Amit Shah <amit.shah@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#ifndef _QEMU_VIRTIO_RNG_H +#define _QEMU_VIRTIO_RNG_H + +#include "qemu/rng.h" +#include "qemu/rng-random.h" + +/* The Virtio ID for the virtio rng device */ +#define VIRTIO_ID_RNG 4 + +struct VirtIORNGConf { + RngBackend *rng; + uint64_t max_bytes; + uint32_t period_ms; + RndRandom *default_backend; +}; + +#endif diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index 5f737acd97..bfe1860505 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -24,11 +24,6 @@ #define VIRTIO_SCSI_MAX_TARGET 255 #define VIRTIO_SCSI_MAX_LUN 16383 -/* Feature Bits */ -#define VIRTIO_SCSI_F_INOUT 0 -#define VIRTIO_SCSI_F_HOTPLUG 1 -#define VIRTIO_SCSI_F_CHANGE 2 - /* Response codes */ #define VIRTIO_SCSI_S_OK 0 #define VIRTIO_SCSI_S_OVERRUN 1 @@ -207,9 +202,9 @@ static void virtio_scsi_bad_req(void) } static void qemu_sgl_init_external(QEMUSGList *qsgl, struct iovec *sg, - target_phys_addr_t *addr, int num) + hwaddr *addr, int num) { - memset(qsgl, 0, sizeof(*qsgl)); + qemu_sglist_init(qsgl, num, &dma_context_memory); while (num--) { qemu_sglist_add(qsgl, *(addr++), (sg++)->iov_len); } @@ -429,15 +424,17 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, size_t resid) { VirtIOSCSIReq *req = r->hba_private; + uint32_t sense_len; req->resp.cmd->response = VIRTIO_SCSI_S_OK; req->resp.cmd->status = status; if (req->resp.cmd->status == GOOD) { - req->resp.cmd->resid = resid; + req->resp.cmd->resid = tswap32(resid); } else { req->resp.cmd->resid = 0; - req->resp.cmd->sense_len = - scsi_req_get_sense(r, req->resp.cmd->sense, VIRTIO_SCSI_SENSE_SIZE); + sense_len = scsi_req_get_sense(r, req->resp.cmd->sense, + VIRTIO_SCSI_SENSE_SIZE); + req->resp.cmd->sense_len = tswap32(sense_len); } virtio_scsi_complete_req(req); } @@ -537,8 +534,8 @@ static void virtio_scsi_get_config(VirtIODevice *vdev, stl_raw(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent)); stl_raw(&scsiconf->sense_size, s->sense_size); stl_raw(&scsiconf->cdb_size, s->cdb_size); - stl_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL); - stl_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET); + stw_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL); + stw_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET); stl_raw(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN); } @@ -561,8 +558,6 @@ static void virtio_scsi_set_config(VirtIODevice *vdev, static uint32_t virtio_scsi_get_features(VirtIODevice *vdev, uint32_t requested_features) { - requested_features |= (1UL << VIRTIO_SCSI_F_HOTPLUG); - requested_features |= (1UL << VIRTIO_SCSI_F_CHANGE); return requested_features; } @@ -603,6 +598,10 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, VirtIOSCSIEvent *evt; int in_size; + if (!(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) { + return; + } + if (!req) { s->events_dropped = true; return; @@ -655,7 +654,6 @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense) VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); if (((s->vdev.guest_features >> VIRTIO_SCSI_F_CHANGE) & 1) && - (s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) && dev->type != TYPE_ROM) { virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE, sense.asc | (sense.ascq << 8)); @@ -666,8 +664,7 @@ static void virtio_scsi_hotplug(SCSIBus *bus, SCSIDevice *dev) { VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); - if (((s->vdev.guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) && - (s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) { + if ((s->vdev.guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) { virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_RESCAN); } diff --git a/hw/virtio-scsi.h b/hw/virtio-scsi.h index 4bc889de02..8d9d15f093 100644 --- a/hw/virtio-scsi.h +++ b/hw/virtio-scsi.h @@ -15,12 +15,16 @@ #define _QEMU_VIRTIO_SCSI_H #include "virtio.h" -#include "net.h" -#include "pci.h" +#include "pci/pci.h" /* The ID for virtio_scsi */ #define VIRTIO_ID_SCSI 8 +/* Feature Bits */ +#define VIRTIO_SCSI_F_INOUT 0 +#define VIRTIO_SCSI_F_HOTPLUG 1 +#define VIRTIO_SCSI_F_CHANGE 2 + struct VirtIOSCSIConf { uint32_t num_queues; uint32_t max_sectors; @@ -31,6 +35,8 @@ struct VirtIOSCSIConf { DEFINE_VIRTIO_COMMON_FEATURES(_state, _features_field), \ DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1), \ DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 0xFFFF), \ - DEFINE_PROP_UINT32("cmd_per_lun", _state, _conf_field.cmd_per_lun, 128) + DEFINE_PROP_UINT32("cmd_per_lun", _state, _conf_field.cmd_per_lun, 128), \ + DEFINE_PROP_BIT("hotplug", _state, _features_field, VIRTIO_SCSI_F_HOTPLUG, true), \ + DEFINE_PROP_BIT("param_change", _state, _features_field, VIRTIO_SCSI_F_CHANGE, true) #endif /* _QEMU_VIRTIO_SCSI_H */ diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index 82073f5dc2..7272bfd5fe 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -18,9 +18,9 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "iov.h" -#include "monitor.h" -#include "qemu-queue.h" +#include "qemu/iov.h" +#include "monitor/monitor.h" +#include "qemu/queue.h" #include "sysbus.h" #include "trace.h" #include "virtio-serial.h" @@ -36,6 +36,15 @@ struct VirtIOSerialBus { uint32_t max_nr_ports; }; +typedef struct VirtIOSerialPostLoad { + QEMUTimer *timer; + uint32_t nr_active_ports; + struct { + VirtIOSerialPort *port; + uint8_t host_connected; + } *connected; +} VirtIOSerialPostLoad; + struct VirtIOSerial { VirtIODevice vdev; @@ -53,6 +62,8 @@ struct VirtIOSerial { uint32_t *ports_map; struct virtio_console_config config; + + struct VirtIOSerialPostLoad *post_load; }; static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id) @@ -206,13 +217,12 @@ static void flush_queued_data(VirtIOSerialPort *port) do_flush_queued_data(port, port->ovq, &port->vser->vdev); } -static size_t send_control_msg(VirtIOSerialPort *port, void *buf, size_t len) +static size_t send_control_msg(VirtIOSerial *vser, void *buf, size_t len) { VirtQueueElement elem; VirtQueue *vq; - struct virtio_console_control *cpkt; - vq = port->vser->c_ivq; + vq = vser->c_ivq; if (!virtio_queue_ready(vq)) { return 0; } @@ -220,25 +230,24 @@ static size_t send_control_msg(VirtIOSerialPort *port, void *buf, size_t len) return 0; } - cpkt = (struct virtio_console_control *)buf; - stl_p(&cpkt->id, port->id); memcpy(elem.in_sg[0].iov_base, buf, len); virtqueue_push(vq, &elem, len); - virtio_notify(&port->vser->vdev, vq); + virtio_notify(&vser->vdev, vq); return len; } -static size_t send_control_event(VirtIOSerialPort *port, uint16_t event, - uint16_t value) +static size_t send_control_event(VirtIOSerial *vser, uint32_t port_id, + uint16_t event, uint16_t value) { struct virtio_console_control cpkt; + stl_p(&cpkt.id, port_id); stw_p(&cpkt.event, event); stw_p(&cpkt.value, value); - trace_virtio_serial_send_control_event(port->id, event, value); - return send_control_msg(port, &cpkt, sizeof(cpkt)); + trace_virtio_serial_send_control_event(port_id, event, value); + return send_control_msg(vser, &cpkt, sizeof(cpkt)); } /* Functions for use inside qemu to open and read from/write to ports */ @@ -250,7 +259,7 @@ int virtio_serial_open(VirtIOSerialPort *port) } /* Send port open notification to the guest */ port->host_connected = true; - send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1); + send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 1); return 0; } @@ -265,7 +274,7 @@ int virtio_serial_close(VirtIOSerialPort *port) port->throttled = false; discard_vq_data(port->ovq, &port->vser->vdev); - send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 0); + send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 0); return 0; } @@ -287,6 +296,7 @@ ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf, size_t virtio_serial_guest_ready(VirtIOSerialPort *port) { VirtQueue *vq = port->ivq; + unsigned int bytes; if (!virtio_queue_ready(vq) || !(port->vser->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) || @@ -296,14 +306,8 @@ size_t virtio_serial_guest_ready(VirtIOSerialPort *port) if (use_multiport(port->vser) && !port->guest_connected) { return 0; } - - if (virtqueue_avail_bytes(vq, 4096, 0)) { - return 4096; - } - if (virtqueue_avail_bytes(vq, 1, 0)) { - return 1; - } - return 0; + virtqueue_get_avail_bytes(vq, &bytes, NULL, 4096, 0); + return bytes; } static void flush_queued_data_bh(void *opaque) @@ -359,7 +363,7 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) * ports we have here. */ QTAILQ_FOREACH(port, &vser->ports, next) { - send_control_event(port, VIRTIO_CONSOLE_PORT_ADD, 1); + send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_ADD, 1); } return; } @@ -390,10 +394,11 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) * up to hvc. */ if (vsc->is_console) { - send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1); + send_control_event(vser, port->id, VIRTIO_CONSOLE_CONSOLE_PORT, 1); } if (port->name) { + stl_p(&cpkt.id, port->id); stw_p(&cpkt.event, VIRTIO_CONSOLE_PORT_NAME); stw_p(&cpkt.value, 1); @@ -404,12 +409,12 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) memcpy(buffer + sizeof(cpkt), port->name, strlen(port->name)); buffer[buffer_len - 1] = 0; - send_control_msg(port, buffer, buffer_len); + send_control_msg(vser, buffer, buffer_len); g_free(buffer); } if (port->host_connected) { - send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1); + send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 1); } /* @@ -631,10 +636,93 @@ static void virtio_serial_save(QEMUFile *f, void *opaque) } } -static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) +static void virtio_serial_post_load_timer_cb(void *opaque) { + uint32_t i; VirtIOSerial *s = opaque; VirtIOSerialPort *port; + uint8_t host_connected; + + if (!s->post_load) { + return; + } + for (i = 0 ; i < s->post_load->nr_active_ports; ++i) { + port = s->post_load->connected[i].port; + host_connected = s->post_load->connected[i].host_connected; + if (host_connected != port->host_connected) { + /* + * We have to let the guest know of the host connection + * status change + */ + send_control_event(s, port->id, VIRTIO_CONSOLE_PORT_OPEN, + port->host_connected); + } + } + g_free(s->post_load->connected); + qemu_free_timer(s->post_load->timer); + g_free(s->post_load); + s->post_load = NULL; +} + +static int fetch_active_ports_list(QEMUFile *f, int version_id, + VirtIOSerial *s, uint32_t nr_active_ports) +{ + uint32_t i; + + s->post_load = g_malloc0(sizeof(*s->post_load)); + s->post_load->nr_active_ports = nr_active_ports; + s->post_load->connected = + g_malloc0(sizeof(*s->post_load->connected) * nr_active_ports); + + s->post_load->timer = qemu_new_timer_ns(vm_clock, + virtio_serial_post_load_timer_cb, + s); + + /* Items in struct VirtIOSerialPort */ + for (i = 0; i < nr_active_ports; i++) { + VirtIOSerialPort *port; + uint32_t id; + + id = qemu_get_be32(f); + port = find_port_by_id(s, id); + if (!port) { + return -EINVAL; + } + + port->guest_connected = qemu_get_byte(f); + s->post_load->connected[i].port = port; + s->post_load->connected[i].host_connected = qemu_get_byte(f); + + if (version_id > 2) { + uint32_t elem_popped; + + qemu_get_be32s(f, &elem_popped); + if (elem_popped) { + qemu_get_be32s(f, &port->iov_idx); + qemu_get_be64s(f, &port->iov_offset); + + qemu_get_buffer(f, (unsigned char *)&port->elem, + sizeof(port->elem)); + virtqueue_map_sg(port->elem.in_sg, port->elem.in_addr, + port->elem.in_num, 1); + virtqueue_map_sg(port->elem.out_sg, port->elem.out_addr, + port->elem.out_num, 1); + + /* + * Port was throttled on source machine. Let's + * unthrottle it here so data starts flowing again. + */ + virtio_serial_throttle_port(port, false); + } + } + } + qemu_mod_timer(s->post_load->timer, 1); + return 0; +} + +static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) +{ + VirtIOSerial *s = opaque; uint32_t max_nr_ports, nr_active_ports, ports_map; unsigned int i; int ret; @@ -678,49 +766,10 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &nr_active_ports); - /* Items in struct VirtIOSerialPort */ - for (i = 0; i < nr_active_ports; i++) { - uint32_t id; - bool host_connected; - - id = qemu_get_be32(f); - port = find_port_by_id(s, id); - if (!port) { - return -EINVAL; - } - - port->guest_connected = qemu_get_byte(f); - host_connected = qemu_get_byte(f); - if (host_connected != port->host_connected) { - /* - * We have to let the guest know of the host connection - * status change - */ - send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, - port->host_connected); - } - - if (version_id > 2) { - uint32_t elem_popped; - - qemu_get_be32s(f, &elem_popped); - if (elem_popped) { - qemu_get_be32s(f, &port->iov_idx); - qemu_get_be64s(f, &port->iov_offset); - - qemu_get_buffer(f, (unsigned char *)&port->elem, - sizeof(port->elem)); - virtqueue_map_sg(port->elem.in_sg, port->elem.in_addr, - port->elem.in_num, 1); - virtqueue_map_sg(port->elem.out_sg, port->elem.out_addr, - port->elem.out_num, 1); - - /* - * Port was throttled on source machine. Let's - * unthrottle it here so data starts flowing again. - */ - virtio_serial_throttle_port(port, false); - } + if (nr_active_ports) { + ret = fetch_active_ports_list(f, version_id, s, nr_active_ports); + if (ret) { + return ret; } } return 0; @@ -791,9 +840,7 @@ static void mark_port_added(VirtIOSerial *vser, uint32_t port_id) static void add_port(VirtIOSerial *vser, uint32_t port_id) { mark_port_added(vser, port_id); - - send_control_event(find_port_by_id(vser, port_id), - VIRTIO_CONSOLE_PORT_ADD, 1); + send_control_event(vser, port_id, VIRTIO_CONSOLE_PORT_ADD, 1); } static void remove_port(VirtIOSerial *vser, uint32_t port_id) @@ -805,10 +852,16 @@ static void remove_port(VirtIOSerial *vser, uint32_t port_id) vser->ports_map[i] &= ~(1U << (port_id % 32)); port = find_port_by_id(vser, port_id); + /* + * This function is only called from qdev's unplug callback; if we + * get a NULL port here, we're in trouble. + */ + assert(port); + /* Flush out any unconsumed buffers first */ discard_vq_data(port->ovq, &port->vser->vdev); - send_control_event(port, VIRTIO_CONSOLE_PORT_REMOVE, 1); + send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_REMOVE, 1); } static int virtser_port_qdev_init(DeviceState *qdev) @@ -965,6 +1018,8 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf) vser->qdev = dev; + vser->post_load = NULL; + /* * Register for the savevm section with the virtio-console name * to preserve backward compat @@ -984,7 +1039,12 @@ void virtio_serial_exit(VirtIODevice *vdev) g_free(vser->ivqs); g_free(vser->ovqs); g_free(vser->ports_map); - + if (vser->post_load) { + g_free(vser->post_load->connected); + qemu_del_timer(vser->post_load->timer); + qemu_free_timer(vser->post_load->timer); + g_free(vser->post_load); + } virtio_cleanup(vdev); } diff --git a/hw/virtio.c b/hw/virtio.c index 209c763751..77b53a9c21 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -14,9 +14,9 @@ #include <inttypes.h> #include "trace.h" -#include "qemu-error.h" +#include "qemu/error-report.h" #include "virtio.h" -#include "qemu-barrier.h" +#include "qemu/atomic.h" /* The alignment to use between consumer and producer parts of vring. * x86 pagesize again. */ @@ -53,15 +53,15 @@ typedef struct VRingUsed typedef struct VRing { unsigned int num; - target_phys_addr_t desc; - target_phys_addr_t avail; - target_phys_addr_t used; + hwaddr desc; + hwaddr avail; + hwaddr used; } VRing; struct VirtQueue { VRing vring; - target_phys_addr_t pa; + hwaddr pa; uint16_t last_avail_idx; /* Last used index value we have signalled on */ uint16_t signalled_used; @@ -84,7 +84,7 @@ struct VirtQueue /* virt queue functions */ static void virtqueue_init(VirtQueue *vq) { - target_phys_addr_t pa = vq->pa; + hwaddr pa = vq->pa; vq->vring.desc = pa; vq->vring.avail = pa + vq->vring.num * sizeof(VRingDesc); @@ -93,51 +93,51 @@ static void virtqueue_init(VirtQueue *vq) VIRTIO_PCI_VRING_ALIGN); } -static inline uint64_t vring_desc_addr(target_phys_addr_t desc_pa, int i) +static inline uint64_t vring_desc_addr(hwaddr desc_pa, int i) { - target_phys_addr_t pa; + hwaddr pa; pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr); return ldq_phys(pa); } -static inline uint32_t vring_desc_len(target_phys_addr_t desc_pa, int i) +static inline uint32_t vring_desc_len(hwaddr desc_pa, int i) { - target_phys_addr_t pa; + hwaddr pa; pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, len); return ldl_phys(pa); } -static inline uint16_t vring_desc_flags(target_phys_addr_t desc_pa, int i) +static inline uint16_t vring_desc_flags(hwaddr desc_pa, int i) { - target_phys_addr_t pa; + hwaddr pa; pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags); return lduw_phys(pa); } -static inline uint16_t vring_desc_next(target_phys_addr_t desc_pa, int i) +static inline uint16_t vring_desc_next(hwaddr desc_pa, int i) { - target_phys_addr_t pa; + hwaddr pa; pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, next); return lduw_phys(pa); } static inline uint16_t vring_avail_flags(VirtQueue *vq) { - target_phys_addr_t pa; + hwaddr pa; pa = vq->vring.avail + offsetof(VRingAvail, flags); return lduw_phys(pa); } static inline uint16_t vring_avail_idx(VirtQueue *vq) { - target_phys_addr_t pa; + hwaddr pa; pa = vq->vring.avail + offsetof(VRingAvail, idx); return lduw_phys(pa); } static inline uint16_t vring_avail_ring(VirtQueue *vq, int i) { - target_phys_addr_t pa; + hwaddr pa; pa = vq->vring.avail + offsetof(VRingAvail, ring[i]); return lduw_phys(pa); } @@ -149,49 +149,49 @@ static inline uint16_t vring_used_event(VirtQueue *vq) static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val) { - target_phys_addr_t pa; + hwaddr pa; pa = vq->vring.used + offsetof(VRingUsed, ring[i].id); stl_phys(pa, val); } static inline void vring_used_ring_len(VirtQueue *vq, int i, uint32_t val) { - target_phys_addr_t pa; + hwaddr pa; pa = vq->vring.used + offsetof(VRingUsed, ring[i].len); stl_phys(pa, val); } static uint16_t vring_used_idx(VirtQueue *vq) { - target_phys_addr_t pa; + hwaddr pa; pa = vq->vring.used + offsetof(VRingUsed, idx); return lduw_phys(pa); } static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val) { - target_phys_addr_t pa; + hwaddr pa; pa = vq->vring.used + offsetof(VRingUsed, idx); stw_phys(pa, val); } static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask) { - target_phys_addr_t pa; + hwaddr pa; pa = vq->vring.used + offsetof(VRingUsed, flags); stw_phys(pa, lduw_phys(pa) | mask); } static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask) { - target_phys_addr_t pa; + hwaddr pa; pa = vq->vring.used + offsetof(VRingUsed, flags); stw_phys(pa, lduw_phys(pa) & ~mask); } static inline void vring_avail_event(VirtQueue *vq, uint16_t val) { - target_phys_addr_t pa; + hwaddr pa; if (!vq->notification) { return; } @@ -241,7 +241,7 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, elem->in_sg[i].iov_len, 1, size); - offset += elem->in_sg[i].iov_len; + offset += size; } for (i = 0; i < elem->out_num; i++) @@ -313,7 +313,7 @@ static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx) return head; } -static unsigned virtqueue_next_desc(target_phys_addr_t desc_pa, +static unsigned virtqueue_next_desc(hwaddr desc_pa, unsigned int i, unsigned int max) { unsigned int next; @@ -335,17 +335,19 @@ static unsigned virtqueue_next_desc(target_phys_addr_t desc_pa, return next; } -int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes) +void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, + unsigned int *out_bytes, + unsigned max_in_bytes, unsigned max_out_bytes) { unsigned int idx; - int total_bufs, in_total, out_total; + unsigned int total_bufs, in_total, out_total; idx = vq->last_avail_idx; total_bufs = in_total = out_total = 0; while (virtqueue_num_heads(vq, idx)) { unsigned int max, num_bufs, indirect = 0; - target_phys_addr_t desc_pa; + hwaddr desc_pa; int i; max = vq->vring.num; @@ -380,13 +382,12 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes) } if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) { - if (in_bytes > 0 && - (in_total += vring_desc_len(desc_pa, i)) >= in_bytes) - return 1; + in_total += vring_desc_len(desc_pa, i); } else { - if (out_bytes > 0 && - (out_total += vring_desc_len(desc_pa, i)) >= out_bytes) - return 1; + out_total += vring_desc_len(desc_pa, i); + } + if (in_total >= max_in_bytes && out_total >= max_out_bytes) { + goto done; } } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max); @@ -395,15 +396,29 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes) else total_bufs++; } +done: + if (in_bytes) { + *in_bytes = in_total; + } + if (out_bytes) { + *out_bytes = out_total; + } +} - return 0; +int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, + unsigned int out_bytes) +{ + unsigned int in_total, out_total; + + virtqueue_get_avail_bytes(vq, &in_total, &out_total, in_bytes, out_bytes); + return in_bytes <= in_total && out_bytes <= out_total; } -void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr, +void virtqueue_map_sg(struct iovec *sg, hwaddr *addr, size_t num_sg, int is_write) { unsigned int i; - target_phys_addr_t len; + hwaddr len; for (i = 0; i < num_sg; i++) { len = sg[i].iov_len; @@ -418,7 +433,7 @@ void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr, int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) { unsigned int i, head, max; - target_phys_addr_t desc_pa = vq->vring.desc; + hwaddr desc_pa = vq->vring.desc; if (!virtqueue_num_heads(vq, vq->last_avail_idx)) return 0; @@ -617,13 +632,13 @@ void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data) vdev->set_config(vdev, vdev->config); } -void virtio_queue_set_addr(VirtIODevice *vdev, int n, target_phys_addr_t addr) +void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr) { vdev->vq[n].pa = addr; virtqueue_init(&vdev->vq[n]); } -target_phys_addr_t virtio_queue_get_addr(VirtIODevice *vdev, int n) +hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n) { return vdev->vq[n].pa; } @@ -920,50 +935,50 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, } void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding, - void *opaque) + DeviceState *opaque) { vdev->binding = binding; vdev->binding_opaque = opaque; } -target_phys_addr_t virtio_queue_get_desc_addr(VirtIODevice *vdev, int n) +hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n) { return vdev->vq[n].vring.desc; } -target_phys_addr_t virtio_queue_get_avail_addr(VirtIODevice *vdev, int n) +hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n) { return vdev->vq[n].vring.avail; } -target_phys_addr_t virtio_queue_get_used_addr(VirtIODevice *vdev, int n) +hwaddr virtio_queue_get_used_addr(VirtIODevice *vdev, int n) { return vdev->vq[n].vring.used; } -target_phys_addr_t virtio_queue_get_ring_addr(VirtIODevice *vdev, int n) +hwaddr virtio_queue_get_ring_addr(VirtIODevice *vdev, int n) { return vdev->vq[n].vring.desc; } -target_phys_addr_t virtio_queue_get_desc_size(VirtIODevice *vdev, int n) +hwaddr virtio_queue_get_desc_size(VirtIODevice *vdev, int n) { return sizeof(VRingDesc) * vdev->vq[n].vring.num; } -target_phys_addr_t virtio_queue_get_avail_size(VirtIODevice *vdev, int n) +hwaddr virtio_queue_get_avail_size(VirtIODevice *vdev, int n) { return offsetof(VRingAvail, ring) + sizeof(uint64_t) * vdev->vq[n].vring.num; } -target_phys_addr_t virtio_queue_get_used_size(VirtIODevice *vdev, int n) +hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n) { return offsetof(VRingUsed, ring) + sizeof(VRingUsedElem) * vdev->vq[n].vring.num; } -target_phys_addr_t virtio_queue_get_ring_size(VirtIODevice *vdev, int n) +hwaddr virtio_queue_get_ring_size(VirtIODevice *vdev, int n) { return vdev->vq[n].vring.used - vdev->vq[n].vring.desc + virtio_queue_get_used_size(vdev, n); diff --git a/hw/virtio.h b/hw/virtio.h index 7a4f564529..1dec9dce07 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -15,10 +15,10 @@ #define _QEMU_VIRTIO_H #include "hw.h" -#include "net.h" +#include "net/net.h" #include "qdev.h" -#include "sysemu.h" -#include "event_notifier.h" +#include "sysemu/sysemu.h" +#include "qemu/event_notifier.h" #ifdef CONFIG_LINUX #include "9p.h" #endif @@ -69,7 +69,7 @@ struct VirtQueue; -static inline target_phys_addr_t vring_align(target_phys_addr_t addr, +static inline hwaddr vring_align(hwaddr addr, unsigned long align) { return (addr + align - 1) & ~(align - 1); @@ -84,24 +84,24 @@ typedef struct VirtQueueElement unsigned int index; unsigned int out_num; unsigned int in_num; - target_phys_addr_t in_addr[VIRTQUEUE_MAX_SIZE]; - target_phys_addr_t out_addr[VIRTQUEUE_MAX_SIZE]; + hwaddr in_addr[VIRTQUEUE_MAX_SIZE]; + hwaddr out_addr[VIRTQUEUE_MAX_SIZE]; struct iovec in_sg[VIRTQUEUE_MAX_SIZE]; struct iovec out_sg[VIRTQUEUE_MAX_SIZE]; } VirtQueueElement; typedef struct { - void (*notify)(void * opaque, uint16_t vector); - void (*save_config)(void * opaque, QEMUFile *f); - void (*save_queue)(void * opaque, int n, QEMUFile *f); - int (*load_config)(void * opaque, QEMUFile *f); - int (*load_queue)(void * opaque, int n, QEMUFile *f); - int (*load_done)(void * opaque, QEMUFile *f); - unsigned (*get_features)(void * opaque); - bool (*query_guest_notifiers)(void * opaque); - int (*set_guest_notifiers)(void * opaque, bool assigned); - int (*set_host_notifier)(void * opaque, int n, bool assigned); - void (*vmstate_change)(void * opaque, bool running); + void (*notify)(DeviceState *d, uint16_t vector); + void (*save_config)(DeviceState *d, QEMUFile *f); + void (*save_queue)(DeviceState *d, int n, QEMUFile *f); + int (*load_config)(DeviceState *d, QEMUFile *f); + int (*load_queue)(DeviceState *d, int n, QEMUFile *f); + int (*load_done)(DeviceState *d, QEMUFile *f); + unsigned (*get_features)(DeviceState *d); + bool (*query_guest_notifiers)(DeviceState *d); + int (*set_guest_notifiers)(DeviceState *d, bool assigned); + int (*set_host_notifier)(DeviceState *d, int n, bool assigned); + void (*vmstate_change)(DeviceState *d, bool running); } VirtIOBindings; #define VIRTIO_PCI_QUEUE_MAX 64 @@ -128,7 +128,7 @@ struct VirtIODevice void (*set_status)(VirtIODevice *vdev, uint8_t val); VirtQueue *vq; const VirtIOBindings *binding; - void *binding_opaque; + DeviceState *binding_opaque; uint16_t device_id; bool vm_running; VMChangeStateEntry *vmstate; @@ -144,10 +144,14 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count); void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len, unsigned int idx); -void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr, +void virtqueue_map_sg(struct iovec *sg, hwaddr *addr, size_t num_sg, int is_write); int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem); -int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes); +int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, + unsigned int out_bytes); +void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, + unsigned int *out_bytes, + unsigned max_in_bytes, unsigned max_out_bytes); void virtio_notify(VirtIODevice *vdev, VirtQueue *vq); @@ -175,8 +179,8 @@ uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr); void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data); void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data); void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data); -void virtio_queue_set_addr(VirtIODevice *vdev, int n, target_phys_addr_t addr); -target_phys_addr_t virtio_queue_get_addr(VirtIODevice *vdev, int n); +void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr); +hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n); int virtio_queue_get_num(VirtIODevice *vdev, int n); void virtio_queue_notify(VirtIODevice *vdev, int n); uint16_t virtio_queue_vector(VirtIODevice *vdev, int n); @@ -187,7 +191,7 @@ void virtio_update_irq(VirtIODevice *vdev); int virtio_set_features(VirtIODevice *vdev, uint32_t val); void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding, - void *opaque); + DeviceState *opaque); /* Base devices. */ typedef struct VirtIOBlkConf VirtIOBlkConf; @@ -200,6 +204,8 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial); VirtIODevice *virtio_balloon_init(DeviceState *dev); typedef struct VirtIOSCSIConf VirtIOSCSIConf; VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf); +typedef struct VirtIORNGConf VirtIORNGConf; +VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf); #ifdef CONFIG_LINUX VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf); #endif @@ -210,6 +216,7 @@ void virtio_blk_exit(VirtIODevice *vdev); void virtio_serial_exit(VirtIODevice *vdev); void virtio_balloon_exit(VirtIODevice *vdev); void virtio_scsi_exit(VirtIODevice *vdev); +void virtio_rng_exit(VirtIODevice *vdev); #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \ DEFINE_PROP_BIT("indirect_desc", _state, _field, \ @@ -217,14 +224,14 @@ void virtio_scsi_exit(VirtIODevice *vdev); DEFINE_PROP_BIT("event_idx", _state, _field, \ VIRTIO_RING_F_EVENT_IDX, true) -target_phys_addr_t virtio_queue_get_desc_addr(VirtIODevice *vdev, int n); -target_phys_addr_t virtio_queue_get_avail_addr(VirtIODevice *vdev, int n); -target_phys_addr_t virtio_queue_get_used_addr(VirtIODevice *vdev, int n); -target_phys_addr_t virtio_queue_get_ring_addr(VirtIODevice *vdev, int n); -target_phys_addr_t virtio_queue_get_desc_size(VirtIODevice *vdev, int n); -target_phys_addr_t virtio_queue_get_avail_size(VirtIODevice *vdev, int n); -target_phys_addr_t virtio_queue_get_used_size(VirtIODevice *vdev, int n); -target_phys_addr_t virtio_queue_get_ring_size(VirtIODevice *vdev, int n); +hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n); +hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n); +hwaddr virtio_queue_get_used_addr(VirtIODevice *vdev, int n); +hwaddr virtio_queue_get_ring_addr(VirtIODevice *vdev, int n); +hwaddr virtio_queue_get_desc_size(VirtIODevice *vdev, int n); +hwaddr virtio_queue_get_avail_size(VirtIODevice *vdev, int n); +hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n); +hwaddr virtio_queue_get_ring_size(VirtIODevice *vdev, int n); uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n); void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx); VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n); diff --git a/hw/vmmouse.c b/hw/vmmouse.c index 6338efa1c3..004d09851c 100644 --- a/hw/vmmouse.c +++ b/hw/vmmouse.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #include "hw.h" -#include "console.h" +#include "ui/console.h" #include "ps2.h" #include "pc.h" #include "qdev.h" @@ -252,7 +252,6 @@ static void vmmouse_reset(DeviceState *d) { VMMouseState *s = container_of(d, VMMouseState, dev.qdev); - s->status = 0xffff; s->queue_size = VMMOUSE_QUEUE_SIZE; vmmouse_disable(s); diff --git a/hw/vmport.c b/hw/vmport.c index a4f52ee5bb..7d425237ac 100644 --- a/hw/vmport.c +++ b/hw/vmport.c @@ -24,7 +24,7 @@ #include "hw.h" #include "isa.h" #include "pc.h" -#include "kvm.h" +#include "sysemu/kvm.h" #include "qdev.h" //#define VMPORT_DEBUG @@ -54,7 +54,8 @@ void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque) port_state->opaque[command] = opaque; } -static uint32_t vmport_ioport_read(void *opaque, uint32_t addr) +static uint64_t vmport_ioport_read(void *opaque, hwaddr addr, + unsigned size) { VMPortState *s = opaque; CPUX86State *env = cpu_single_env; @@ -81,11 +82,12 @@ static uint32_t vmport_ioport_read(void *opaque, uint32_t addr) return s->func[command](s->opaque[command], addr); } -static void vmport_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void vmport_ioport_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { CPUX86State *env = cpu_single_env; - env->regs[R_EAX] = vmport_ioport_read(opaque, addr); + env->regs[R_EAX] = vmport_ioport_read(opaque, addr, 4); } static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr) @@ -121,13 +123,14 @@ void vmmouse_set_data(const uint32_t *data) env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5]; } -static const MemoryRegionPortio vmport_portio[] = { - {0, 1, 4, .read = vmport_ioport_read, .write = vmport_ioport_write }, - PORTIO_END_OF_LIST(), -}; - static const MemoryRegionOps vmport_ops = { - .old_portio = vmport_portio + .read = vmport_ioport_read, + .write = vmport_ioport_write, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static int vmport_initfn(ISADevice *dev) diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index f5e4f440d5..b0e772f863 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -23,22 +23,21 @@ */ #include "hw.h" #include "loader.h" -#include "console.h" -#include "pci.h" -#include "vmware_vga.h" +#include "ui/console.h" +#include "pci/pci.h" #undef VERBOSE #define HW_RECT_ACCEL #define HW_FILL_ACCEL #define HW_MOUSE_ACCEL -# include "vga_int.h" +#include "vga_int.h" + +/* See http://vmware-svga.sf.net/ for some documentation on VMWare SVGA */ struct vmsvga_state_s { VGACommonState vga; - int width; - int height; int invalidated; int depth; int bypp; @@ -62,7 +61,6 @@ struct vmsvga_state_s { uint32_t wgreen; uint32_t wblue; int syncing; - int fb_size; MemoryRegion fifo_ram; uint8_t *fifo_ptr; @@ -80,7 +78,7 @@ struct vmsvga_state_s { } *cmd; }; -#define REDRAW_FIFO_LEN 512 +#define REDRAW_FIFO_LEN 512 struct vmsvga_rect_s { int x, y, w, h; } redraw_fifo[REDRAW_FIFO_LEN]; @@ -93,31 +91,31 @@ struct pci_vmsvga_state_s { MemoryRegion io_bar; }; -#define SVGA_MAGIC 0x900000UL -#define SVGA_MAKE_ID(ver) (SVGA_MAGIC << 8 | (ver)) -#define SVGA_ID_0 SVGA_MAKE_ID(0) -#define SVGA_ID_1 SVGA_MAKE_ID(1) -#define SVGA_ID_2 SVGA_MAKE_ID(2) +#define SVGA_MAGIC 0x900000UL +#define SVGA_MAKE_ID(ver) (SVGA_MAGIC << 8 | (ver)) +#define SVGA_ID_0 SVGA_MAKE_ID(0) +#define SVGA_ID_1 SVGA_MAKE_ID(1) +#define SVGA_ID_2 SVGA_MAKE_ID(2) -#define SVGA_LEGACY_BASE_PORT 0x4560 -#define SVGA_INDEX_PORT 0x0 -#define SVGA_VALUE_PORT 0x1 -#define SVGA_BIOS_PORT 0x2 +#define SVGA_LEGACY_BASE_PORT 0x4560 +#define SVGA_INDEX_PORT 0x0 +#define SVGA_VALUE_PORT 0x1 +#define SVGA_BIOS_PORT 0x2 #define SVGA_VERSION_2 #ifdef SVGA_VERSION_2 -# define SVGA_ID SVGA_ID_2 -# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT -# define SVGA_IO_MUL 1 -# define SVGA_FIFO_SIZE 0x10000 -# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA2 +# define SVGA_ID SVGA_ID_2 +# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT +# define SVGA_IO_MUL 1 +# define SVGA_FIFO_SIZE 0x10000 +# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA2 #else -# define SVGA_ID SVGA_ID_1 -# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT -# define SVGA_IO_MUL 4 -# define SVGA_FIFO_SIZE 0x10000 -# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA +# define SVGA_ID SVGA_ID_1 +# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT +# define SVGA_IO_MUL 4 +# define SVGA_FIFO_SIZE 0x10000 +# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA #endif enum { @@ -129,7 +127,7 @@ enum { SVGA_REG_MAX_WIDTH = 4, SVGA_REG_MAX_HEIGHT = 5, SVGA_REG_DEPTH = 6, - SVGA_REG_BITS_PER_PIXEL = 7, /* Current bpp in the guest */ + SVGA_REG_BITS_PER_PIXEL = 7, /* Current bpp in the guest */ SVGA_REG_PSEUDOCOLOR = 8, SVGA_REG_RED_MASK = 9, SVGA_REG_GREEN_MASK = 10, @@ -142,46 +140,46 @@ enum { /* ID 1 and 2 registers */ SVGA_REG_CAPABILITIES = 17, - SVGA_REG_MEM_START = 18, /* Memory for command FIFO */ + SVGA_REG_MEM_START = 18, /* Memory for command FIFO */ SVGA_REG_MEM_SIZE = 19, - SVGA_REG_CONFIG_DONE = 20, /* Set when memory area configured */ - SVGA_REG_SYNC = 21, /* Write to force synchronization */ - SVGA_REG_BUSY = 22, /* Read to check if sync is done */ - SVGA_REG_GUEST_ID = 23, /* Set guest OS identifier */ - SVGA_REG_CURSOR_ID = 24, /* ID of cursor */ - SVGA_REG_CURSOR_X = 25, /* Set cursor X position */ - SVGA_REG_CURSOR_Y = 26, /* Set cursor Y position */ - SVGA_REG_CURSOR_ON = 27, /* Turn cursor on/off */ - SVGA_REG_HOST_BITS_PER_PIXEL = 28, /* Current bpp in the host */ - SVGA_REG_SCRATCH_SIZE = 29, /* Number of scratch registers */ - SVGA_REG_MEM_REGS = 30, /* Number of FIFO registers */ - SVGA_REG_NUM_DISPLAYS = 31, /* Number of guest displays */ - SVGA_REG_PITCHLOCK = 32, /* Fixed pitch for all modes */ - - SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */ + SVGA_REG_CONFIG_DONE = 20, /* Set when memory area configured */ + SVGA_REG_SYNC = 21, /* Write to force synchronization */ + SVGA_REG_BUSY = 22, /* Read to check if sync is done */ + SVGA_REG_GUEST_ID = 23, /* Set guest OS identifier */ + SVGA_REG_CURSOR_ID = 24, /* ID of cursor */ + SVGA_REG_CURSOR_X = 25, /* Set cursor X position */ + SVGA_REG_CURSOR_Y = 26, /* Set cursor Y position */ + SVGA_REG_CURSOR_ON = 27, /* Turn cursor on/off */ + SVGA_REG_HOST_BITS_PER_PIXEL = 28, /* Current bpp in the host */ + SVGA_REG_SCRATCH_SIZE = 29, /* Number of scratch registers */ + SVGA_REG_MEM_REGS = 30, /* Number of FIFO registers */ + SVGA_REG_NUM_DISPLAYS = 31, /* Number of guest displays */ + SVGA_REG_PITCHLOCK = 32, /* Fixed pitch for all modes */ + + SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */ SVGA_PALETTE_END = SVGA_PALETTE_BASE + 767, SVGA_SCRATCH_BASE = SVGA_PALETTE_BASE + 768, }; -#define SVGA_CAP_NONE 0 -#define SVGA_CAP_RECT_FILL (1 << 0) -#define SVGA_CAP_RECT_COPY (1 << 1) -#define SVGA_CAP_RECT_PAT_FILL (1 << 2) -#define SVGA_CAP_LEGACY_OFFSCREEN (1 << 3) -#define SVGA_CAP_RASTER_OP (1 << 4) -#define SVGA_CAP_CURSOR (1 << 5) -#define SVGA_CAP_CURSOR_BYPASS (1 << 6) -#define SVGA_CAP_CURSOR_BYPASS_2 (1 << 7) -#define SVGA_CAP_8BIT_EMULATION (1 << 8) -#define SVGA_CAP_ALPHA_CURSOR (1 << 9) -#define SVGA_CAP_GLYPH (1 << 10) -#define SVGA_CAP_GLYPH_CLIPPING (1 << 11) -#define SVGA_CAP_OFFSCREEN_1 (1 << 12) -#define SVGA_CAP_ALPHA_BLEND (1 << 13) -#define SVGA_CAP_3D (1 << 14) -#define SVGA_CAP_EXTENDED_FIFO (1 << 15) -#define SVGA_CAP_MULTIMON (1 << 16) -#define SVGA_CAP_PITCHLOCK (1 << 17) +#define SVGA_CAP_NONE 0 +#define SVGA_CAP_RECT_FILL (1 << 0) +#define SVGA_CAP_RECT_COPY (1 << 1) +#define SVGA_CAP_RECT_PAT_FILL (1 << 2) +#define SVGA_CAP_LEGACY_OFFSCREEN (1 << 3) +#define SVGA_CAP_RASTER_OP (1 << 4) +#define SVGA_CAP_CURSOR (1 << 5) +#define SVGA_CAP_CURSOR_BYPASS (1 << 6) +#define SVGA_CAP_CURSOR_BYPASS_2 (1 << 7) +#define SVGA_CAP_8BIT_EMULATION (1 << 8) +#define SVGA_CAP_ALPHA_CURSOR (1 << 9) +#define SVGA_CAP_GLYPH (1 << 10) +#define SVGA_CAP_GLYPH_CLIPPING (1 << 11) +#define SVGA_CAP_OFFSCREEN_1 (1 << 12) +#define SVGA_CAP_ALPHA_BLEND (1 << 13) +#define SVGA_CAP_3D (1 << 14) +#define SVGA_CAP_EXTENDED_FIFO (1 << 15) +#define SVGA_CAP_MULTIMON (1 << 16) +#define SVGA_CAP_PITCHLOCK (1 << 17) /* * FIFO offsets (seen as an array of 32-bit words) @@ -191,7 +189,7 @@ enum { * The original defined FIFO offsets */ SVGA_FIFO_MIN = 0, - SVGA_FIFO_MAX, /* The distance from MIN to MAX must be at least 10K */ + SVGA_FIFO_MAX, /* The distance from MIN to MAX must be at least 10K */ SVGA_FIFO_NEXT_CMD, SVGA_FIFO_STOP, @@ -205,21 +203,21 @@ enum { SVGA_FIFO_PITCHLOCK, }; -#define SVGA_FIFO_CAP_NONE 0 -#define SVGA_FIFO_CAP_FENCE (1 << 0) -#define SVGA_FIFO_CAP_ACCELFRONT (1 << 1) -#define SVGA_FIFO_CAP_PITCHLOCK (1 << 2) +#define SVGA_FIFO_CAP_NONE 0 +#define SVGA_FIFO_CAP_FENCE (1 << 0) +#define SVGA_FIFO_CAP_ACCELFRONT (1 << 1) +#define SVGA_FIFO_CAP_PITCHLOCK (1 << 2) -#define SVGA_FIFO_FLAG_NONE 0 -#define SVGA_FIFO_FLAG_ACCELFRONT (1 << 0) +#define SVGA_FIFO_FLAG_NONE 0 +#define SVGA_FIFO_FLAG_ACCELFRONT (1 << 0) /* These values can probably be changed arbitrarily. */ -#define SVGA_SCRATCH_SIZE 0x8000 -#define SVGA_MAX_WIDTH 2360 -#define SVGA_MAX_HEIGHT 1770 +#define SVGA_SCRATCH_SIZE 0x8000 +#define SVGA_MAX_WIDTH 2360 +#define SVGA_MAX_HEIGHT 1770 #ifdef VERBOSE -# define GUEST_OS_BASE 0x5001 +# define GUEST_OS_BASE 0x5001 static const char *vmsvga_guest_id[] = { [0x00] = "Dos", [0x01] = "Windows 3.1", @@ -298,44 +296,37 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s, uint8_t *src; uint8_t *dst; - if (x + w > s->width) { + if (x + w > ds_get_width(s->vga.ds)) { fprintf(stderr, "%s: update width too large x: %d, w: %d\n", - __FUNCTION__, x, w); - x = MIN(x, s->width); - w = s->width - x; + __func__, x, w); + x = MIN(x, ds_get_width(s->vga.ds)); + w = ds_get_width(s->vga.ds) - x; } - if (y + h > s->height) { + if (y + h > ds_get_height(s->vga.ds)) { fprintf(stderr, "%s: update height too large y: %d, h: %d\n", - __FUNCTION__, y, h); - y = MIN(y, s->height); - h = s->height - y; + __func__, y, h); + y = MIN(y, ds_get_height(s->vga.ds)); + h = ds_get_height(s->vga.ds) - y; } - line = h; - bypl = s->bypp * s->width; - width = s->bypp * w; - start = s->bypp * x + bypl * y; + bypl = ds_get_linesize(s->vga.ds); + width = ds_get_bytes_per_pixel(s->vga.ds) * w; + start = ds_get_bytes_per_pixel(s->vga.ds) * x + bypl * y; src = s->vga.vram_ptr + start; dst = ds_get_data(s->vga.ds) + start; - for (; line > 0; line --, src += bypl, dst += bypl) + for (line = h; line > 0; line--, src += bypl, dst += bypl) { memcpy(dst, src, width); - - dpy_update(s->vga.ds, x, y, w, h); -} - -static inline void vmsvga_update_screen(struct vmsvga_state_s *s) -{ - memcpy(ds_get_data(s->vga.ds), s->vga.vram_ptr, - s->bypp * s->width * s->height); - dpy_update(s->vga.ds, 0, 0, s->width, s->height); + } + dpy_gfx_update(s->vga.ds, x, y, w, h); } static inline void vmsvga_update_rect_delayed(struct vmsvga_state_s *s, int x, int y, int w, int h) { - struct vmsvga_rect_s *rect = &s->redraw_fifo[s->redraw_fifo_last ++]; + struct vmsvga_rect_s *rect = &s->redraw_fifo[s->redraw_fifo_last++]; + s->redraw_fifo_last &= REDRAW_FIFO_LEN - 1; rect->x = x; rect->y = y; @@ -346,6 +337,7 @@ static inline void vmsvga_update_rect_delayed(struct vmsvga_state_s *s, static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s) { struct vmsvga_rect_s *rect; + if (s->invalidated) { s->redraw_fifo_first = s->redraw_fifo_last; return; @@ -353,7 +345,7 @@ static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s) /* Overlapping region updates can be optimised out here - if someone * knows a smart algorithm to do that, please share. */ while (s->redraw_fifo_first != s->redraw_fifo_last) { - rect = &s->redraw_fifo[s->redraw_fifo_first ++]; + rect = &s->redraw_fifo[s->redraw_fifo_first++]; s->redraw_fifo_first &= REDRAW_FIFO_LEN - 1; vmsvga_update_rect(s, rect->x, rect->y, rect->w, rect->h); } @@ -364,20 +356,21 @@ static inline void vmsvga_copy_rect(struct vmsvga_state_s *s, int x0, int y0, int x1, int y1, int w, int h) { uint8_t *vram = s->vga.vram_ptr; - int bypl = s->bypp * s->width; - int width = s->bypp * w; + int bypl = ds_get_linesize(s->vga.ds); + int bypp = ds_get_bytes_per_pixel(s->vga.ds); + int width = bypp * w; int line = h; uint8_t *ptr[2]; if (y1 > y0) { - ptr[0] = vram + s->bypp * x0 + bypl * (y0 + h - 1); - ptr[1] = vram + s->bypp * x1 + bypl * (y1 + h - 1); + ptr[0] = vram + bypp * x0 + bypl * (y0 + h - 1); + ptr[1] = vram + bypp * x1 + bypl * (y1 + h - 1); for (; line > 0; line --, ptr[0] -= bypl, ptr[1] -= bypl) { memmove(ptr[1], ptr[0], width); } } else { - ptr[0] = vram + s->bypp * x0 + bypl * y0; - ptr[1] = vram + s->bypp * x1 + bypl * y1; + ptr[0] = vram + bypp * x0 + bypl * y0; + ptr[1] = vram + bypp * x1 + bypl * y1; for (; line > 0; line --, ptr[0] += bypl, ptr[1] += bypl) { memmove(ptr[1], ptr[0], width); } @@ -391,13 +384,11 @@ static inline void vmsvga_copy_rect(struct vmsvga_state_s *s, static inline void vmsvga_fill_rect(struct vmsvga_state_s *s, uint32_t c, int x, int y, int w, int h) { - uint8_t *vram = s->vga.vram_ptr; - int bypp = s->bypp; - int bypl = bypp * s->width; - int width = bypp * w; + int bypl = ds_get_linesize(s->vga.ds); + int width = ds_get_bytes_per_pixel(s->vga.ds) * w; int line = h; int column; - uint8_t *fst = vram + bypp * x + bypl * y; + uint8_t *fst; uint8_t *dst; uint8_t *src; uint8_t col[4]; @@ -407,12 +398,14 @@ static inline void vmsvga_fill_rect(struct vmsvga_state_s *s, col[2] = c >> 16; col[3] = c >> 24; + fst = s->vga.vram_ptr + ds_get_bytes_per_pixel(s->vga.ds) * x + bypl * y; + if (line--) { dst = fst; src = col; for (column = width; column > 0; column--) { *(dst++) = *(src++); - if (src - col == bypp) { + if (src - col == ds_get_bytes_per_pixel(s->vga.ds)) { src = col; } } @@ -438,8 +431,8 @@ struct vmsvga_cursor_definition_s { uint32_t image[4096]; }; -#define SVGA_BITMAP_SIZE(w, h) ((((w) + 31) >> 5) * (h)) -#define SVGA_PIXMAP_SIZE(w, h, bpp) (((((w) * (bpp)) + 31) >> 5) * (h)) +#define SVGA_BITMAP_SIZE(w, h) ((((w) + 31) >> 5) * (h)) +#define SVGA_PIXMAP_SIZE(w, h, bpp) (((((w) * (bpp)) + 31) >> 5) * (h)) #ifdef HW_MOUSE_ACCEL static inline void vmsvga_cursor_define(struct vmsvga_state_s *s, @@ -453,16 +446,16 @@ static inline void vmsvga_cursor_define(struct vmsvga_state_s *s, qc->hot_y = c->hot_y; switch (c->bpp) { case 1: - cursor_set_mono(qc, 0xffffff, 0x000000, (void*)c->image, - 1, (void*)c->mask); + cursor_set_mono(qc, 0xffffff, 0x000000, (void *)c->image, + 1, (void *)c->mask); #ifdef DEBUG cursor_print_ascii_art(qc, "vmware/mono"); #endif break; case 32: /* fill alpha channel from mask, set color to zero */ - cursor_set_mono(qc, 0x000000, 0x000000, (void*)c->mask, - 1, (void*)c->mask); + cursor_set_mono(qc, 0x000000, 0x000000, (void *)c->mask, + 1, (void *)c->mask); /* add in rgb values */ pixels = c->width * c->height; for (i = 0; i < pixels; i++) { @@ -474,36 +467,40 @@ static inline void vmsvga_cursor_define(struct vmsvga_state_s *s, break; default: fprintf(stderr, "%s: unhandled bpp %d, using fallback cursor\n", - __FUNCTION__, c->bpp); + __func__, c->bpp); cursor_put(qc); qc = cursor_builtin_left_ptr(); } - if (s->vga.ds->cursor_define) - s->vga.ds->cursor_define(qc); + dpy_cursor_define(s->vga.ds, qc); cursor_put(qc); } #endif -#define CMD(f) le32_to_cpu(s->cmd->f) +#define CMD(f) le32_to_cpu(s->cmd->f) static inline int vmsvga_fifo_length(struct vmsvga_state_s *s) { int num; - if (!s->config || !s->enable) + + if (!s->config || !s->enable) { return 0; + } num = CMD(next_cmd) - CMD(stop); - if (num < 0) + if (num < 0) { num += CMD(max) - CMD(min); + } return num >> 2; } static inline uint32_t vmsvga_fifo_read_raw(struct vmsvga_state_s *s) { uint32_t cmd = s->fifo[CMD(stop) >> 2]; + s->cmd->stop = cpu_to_le32(CMD(stop) + 4); - if (CMD(stop) >= CMD(max)) + if (CMD(stop) >= CMD(max)) { s->cmd->stop = s->cmd->min; + } return cmd; } @@ -529,8 +526,9 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s) case SVGA_CMD_UPDATE: case SVGA_CMD_UPDATE_VERBOSE: len -= 5; - if (len < 0) + if (len < 0) { goto rewind; + } x = vmsvga_fifo_read(s); y = vmsvga_fifo_read(s); @@ -541,8 +539,9 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s) case SVGA_CMD_RECT_FILL: len -= 6; - if (len < 0) + if (len < 0) { goto rewind; + } colour = vmsvga_fifo_read(s); x = vmsvga_fifo_read(s); @@ -559,8 +558,9 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s) case SVGA_CMD_RECT_COPY: len -= 7; - if (len < 0) + if (len < 0) { goto rewind; + } x = vmsvga_fifo_read(s); y = vmsvga_fifo_read(s); @@ -578,8 +578,9 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s) case SVGA_CMD_DEFINE_CURSOR: len -= 8; - if (len < 0) + if (len < 0) { goto rewind; + } cursor.id = vmsvga_fifo_read(s); cursor.hot_x = vmsvga_fifo_read(s); @@ -591,17 +592,21 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s) args = SVGA_BITMAP_SIZE(x, y) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp); if (SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask || - SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image) { goto badcmd; + } len -= args; - if (len < 0) + if (len < 0) { goto rewind; + } - for (args = 0; args < SVGA_BITMAP_SIZE(x, y); args ++) + for (args = 0; args < SVGA_BITMAP_SIZE(x, y); args++) { cursor.mask[args] = vmsvga_fifo_read_raw(s); - for (args = 0; args < SVGA_PIXMAP_SIZE(x, y, cursor.bpp); args ++) + } + for (args = 0; args < SVGA_PIXMAP_SIZE(x, y, cursor.bpp); args++) { cursor.image[args] = vmsvga_fifo_read_raw(s); + } #ifdef HW_MOUSE_ACCEL vmsvga_cursor_define(s, &cursor); break; @@ -616,9 +621,9 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s) */ case SVGA_CMD_DEFINE_ALPHA_CURSOR: len -= 6; - if (len < 0) + if (len < 0) { goto rewind; - + } vmsvga_fifo_read(s); vmsvga_fifo_read(s); vmsvga_fifo_read(s); @@ -634,9 +639,9 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s) goto badcmd; case SVGA_CMD_DRAW_GLYPH_CLIPPED: len -= 4; - if (len < 0) + if (len < 0) { goto rewind; - + } vmsvga_fifo_read(s); vmsvga_fifo_read(s); args = 7 + (vmsvga_fifo_read(s) >> 2); @@ -660,12 +665,14 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s) args = 0; badcmd: len -= args; - if (len < 0) + if (len < 0) { goto rewind; - while (args --) + } + while (args--) { vmsvga_fifo_read(s); + } printf("%s: Unknown command 0x%02x in SVGA command FIFO\n", - __FUNCTION__, cmd); + __func__, cmd); break; rewind: @@ -680,12 +687,14 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s) static uint32_t vmsvga_index_read(void *opaque, uint32_t address) { struct vmsvga_state_s *s = opaque; + return s->index; } static void vmsvga_index_write(void *opaque, uint32_t address, uint32_t index) { struct vmsvga_state_s *s = opaque; + s->index = index; } @@ -693,6 +702,7 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) { uint32_t caps; struct vmsvga_state_s *s = opaque; + switch (s->index) { case SVGA_REG_ID: return s->svgaid; @@ -701,10 +711,10 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) return s->enable; case SVGA_REG_WIDTH: - return s->width; + return ds_get_width(s->vga.ds); case SVGA_REG_HEIGHT: - return s->height; + return ds_get_height(s->vga.ds); case SVGA_REG_MAX_WIDTH: return SVGA_MAX_WIDTH; @@ -723,13 +733,15 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) case SVGA_REG_RED_MASK: return s->wred; + case SVGA_REG_GREEN_MASK: return s->wgreen; + case SVGA_REG_BLUE_MASK: return s->wblue; case SVGA_REG_BYTES_PER_LINE: - return ((s->depth + 7) >> 3) * s->new_width; + return s->bypp * s->new_width; case SVGA_REG_FB_START: { struct pci_vmsvga_state_s *pci_vmsvga @@ -741,10 +753,10 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) return 0x0; case SVGA_REG_VRAM_SIZE: - return s->vga.vram_size; + return s->vga.vram_size; /* No physical VRAM besides the framebuffer */ case SVGA_REG_FB_SIZE: - return s->fb_size; + return s->vga.vram_size; case SVGA_REG_CAPABILITIES: caps = SVGA_CAP_NONE; @@ -755,9 +767,10 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) caps |= SVGA_CAP_RECT_FILL; #endif #ifdef HW_MOUSE_ACCEL - if (s->vga.ds->mouse_set) + if (dpy_cursor_define_supported(s->vga.ds)) { caps |= SVGA_CAP_CURSOR | SVGA_CAP_CURSOR_BYPASS_2 | SVGA_CAP_CURSOR_BYPASS; + } #endif return caps; @@ -806,9 +819,10 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) default: if (s->index >= SVGA_SCRATCH_BASE && - s->index < SVGA_SCRATCH_BASE + s->scratch_size) + s->index < SVGA_SCRATCH_BASE + s->scratch_size) { return s->scratch[s->index - SVGA_SCRATCH_BASE]; - printf("%s: Bad register %02x\n", __FUNCTION__, s->index); + } + printf("%s: Bad register %02x\n", __func__, s->index); } return 0; @@ -817,21 +831,19 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) { struct vmsvga_state_s *s = opaque; + switch (s->index) { case SVGA_REG_ID: - if (value == SVGA_ID_2 || value == SVGA_ID_1 || value == SVGA_ID_0) + if (value == SVGA_ID_2 || value == SVGA_ID_1 || value == SVGA_ID_0) { s->svgaid = value; + } break; case SVGA_REG_ENABLE: - s->enable = value; - s->config &= !!value; - s->width = -1; - s->height = -1; + s->enable = !!value; s->invalidated = 1; s->vga.invalidate(&s->vga); - if (s->enable) { - s->fb_size = ((s->depth + 7) >> 3) * s->new_width * s->new_height; + if (s->enable && s->config) { vga_dirty_log_stop(&s->vga); } else { vga_dirty_log_start(&s->vga); @@ -839,19 +851,26 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) break; case SVGA_REG_WIDTH: - s->new_width = value; - s->invalidated = 1; + if (value <= SVGA_MAX_WIDTH) { + s->new_width = value; + s->invalidated = 1; + } else { + printf("%s: Bad width: %i\n", __func__, value); + } break; case SVGA_REG_HEIGHT: - s->new_height = value; - s->invalidated = 1; + if (value <= SVGA_MAX_HEIGHT) { + s->new_height = value; + s->invalidated = 1; + } else { + printf("%s: Bad height: %i\n", __func__, value); + } break; - case SVGA_REG_DEPTH: case SVGA_REG_BITS_PER_PIXEL: if (value != s->depth) { - printf("%s: Bad colour depth: %i bits\n", __FUNCTION__, value); + printf("%s: Bad bits per pixel: %i bits\n", __func__, value); s->config = 0; } break; @@ -860,15 +879,19 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) if (value) { s->fifo = (uint32_t *) s->fifo_ptr; /* Check range and alignment. */ - if ((CMD(min) | CMD(max) | - CMD(next_cmd) | CMD(stop)) & 3) + if ((CMD(min) | CMD(max) | CMD(next_cmd) | CMD(stop)) & 3) { break; - if (CMD(min) < (uint8_t *) s->cmd->fifo - (uint8_t *) s->fifo) + } + if (CMD(min) < (uint8_t *) s->cmd->fifo - (uint8_t *) s->fifo) { break; - if (CMD(max) > SVGA_FIFO_SIZE) + } + if (CMD(max) > SVGA_FIFO_SIZE) { break; - if (CMD(max) < CMD(min) + 10 * 1024) + } + if (CMD(max) < CMD(min) + 10 * 1024) { break; + } + vga_dirty_log_stop(&s->vga); } s->config = !!value; break; @@ -882,9 +905,10 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) s->guest = value; #ifdef VERBOSE if (value >= GUEST_OS_BASE && value < GUEST_OS_BASE + - ARRAY_SIZE(vmsvga_guest_id)) - printf("%s: guest runs %s.\n", __FUNCTION__, - vmsvga_guest_id[value - GUEST_OS_BASE]); + ARRAY_SIZE(vmsvga_guest_id)) { + printf("%s: guest runs %s.\n", __func__, + vmsvga_guest_id[value - GUEST_OS_BASE]); + } #endif break; @@ -904,11 +928,13 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) s->cursor.on |= (value == SVGA_CURSOR_ON_SHOW); s->cursor.on &= (value != SVGA_CURSOR_ON_HIDE); #ifdef HW_MOUSE_ACCEL - if (s->vga.ds->mouse_set && value <= SVGA_CURSOR_ON_SHOW) - s->vga.ds->mouse_set(s->cursor.x, s->cursor.y, s->cursor.on); + if (value <= SVGA_CURSOR_ON_SHOW) { + dpy_mouse_set(s->vga.ds, s->cursor.x, s->cursor.y, s->cursor.on); + } #endif break; + case SVGA_REG_DEPTH: case SVGA_REG_MEM_REGS: case SVGA_REG_NUM_DISPLAYS: case SVGA_REG_PITCHLOCK: @@ -921,28 +947,26 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) s->scratch[s->index - SVGA_SCRATCH_BASE] = value; break; } - printf("%s: Bad register %02x\n", __FUNCTION__, s->index); + printf("%s: Bad register %02x\n", __func__, s->index); } } static uint32_t vmsvga_bios_read(void *opaque, uint32_t address) { - printf("%s: what are we supposed to return?\n", __FUNCTION__); + printf("%s: what are we supposed to return?\n", __func__); return 0xcafe; } static void vmsvga_bios_write(void *opaque, uint32_t address, uint32_t data) { - printf("%s: what are we supposed to do with (%08x)?\n", - __FUNCTION__, data); + printf("%s: what are we supposed to do with (%08x)?\n", __func__, data); } -static inline void vmsvga_size(struct vmsvga_state_s *s) +static inline void vmsvga_check_size(struct vmsvga_state_s *s) { - if (s->new_width != s->width || s->new_height != s->height) { - s->width = s->new_width; - s->height = s->new_height; - qemu_console_resize(s->vga.ds, s->width, s->height); + if (s->new_width != ds_get_width(s->vga.ds) || + s->new_height != ds_get_height(s->vga.ds)) { + qemu_console_resize(s->vga.ds, s->new_width, s->new_height); s->invalidated = 1; } } @@ -950,12 +974,14 @@ static inline void vmsvga_size(struct vmsvga_state_s *s) static void vmsvga_update_display(void *opaque) { struct vmsvga_state_s *s = opaque; + bool dirty = false; + if (!s->enable) { s->vga.update(&s->vga); return; } - vmsvga_size(s); + vmsvga_check_size(s); vmsvga_fifo_run(s); vmsvga_update_rect_flush(s); @@ -964,9 +990,23 @@ static void vmsvga_update_display(void *opaque) * Is it more efficient to look at vram VGA-dirty bits or wait * for the driver to issue SVGA_CMD_UPDATE? */ - if (s->invalidated) { + if (memory_region_is_logging(&s->vga.vram)) { + vga_sync_dirty_bitmap(&s->vga); + dirty = memory_region_get_dirty(&s->vga.vram, 0, + ds_get_linesize(s->vga.ds) * ds_get_height(s->vga.ds), + DIRTY_MEMORY_VGA); + } + if (s->invalidated || dirty) { s->invalidated = 0; - vmsvga_update_screen(s); + memcpy(ds_get_data(s->vga.ds), s->vga.vram_ptr, + ds_get_linesize(s->vga.ds) * ds_get_height(s->vga.ds)); + dpy_gfx_update(s->vga.ds, 0, 0, + ds_get_width(s->vga.ds), ds_get_height(s->vga.ds)); + } + if (dirty) { + memory_region_reset_dirty(&s->vga.vram, 0, + ds_get_linesize(s->vga.ds) * ds_get_height(s->vga.ds), + DIRTY_MEMORY_VGA); } } @@ -979,8 +1019,6 @@ static void vmsvga_reset(DeviceState *dev) s->index = 0; s->enable = 0; s->config = 0; - s->width = -1; - s->height = -1; s->svgaid = SVGA_ID; s->cursor.on = 0; s->redraw_fifo_first = 0; @@ -1003,18 +1041,23 @@ static void vmsvga_invalidate_display(void *opaque) /* save the vga display in a PPM image even if no display is available */ -static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch) +static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch, + Error **errp) { struct vmsvga_state_s *s = opaque; if (!s->enable) { - s->vga.screen_dump(&s->vga, filename, cswitch); + s->vga.screen_dump(&s->vga, filename, cswitch, errp); return; } - if (s->depth == 32) { - DisplaySurface *ds = qemu_create_displaysurface_from(s->width, - s->height, 32, ds_get_linesize(s->vga.ds), s->vga.vram_ptr); - ppm_save(filename, ds); + if (ds_get_bits_per_pixel(s->vga.ds) == 32) { + DisplaySurface *ds = qemu_create_displaysurface_from( + ds_get_width(s->vga.ds), + ds_get_height(s->vga.ds), + 32, + ds_get_linesize(s->vga.ds), + s->vga.vram_ptr); + ppm_save(filename, ds, errp); g_free(ds); } } @@ -1023,8 +1066,9 @@ static void vmsvga_text_update(void *opaque, console_ch_t *chardata) { struct vmsvga_state_s *s = opaque; - if (s->vga.text_update) + if (s->vga.text_update) { s->vga.text_update(&s->vga, chardata); + } } static int vmsvga_post_load(void *opaque, int version_id) @@ -1032,9 +1076,9 @@ static int vmsvga_post_load(void *opaque, int version_id) struct vmsvga_state_s *s = opaque; s->invalidated = 1; - if (s->config) + if (s->config) { s->fifo = (uint32_t *) s->fifo_ptr; - + } return 0; } @@ -1044,7 +1088,7 @@ static const VMStateDescription vmstate_vmware_vga_internal = { .minimum_version_id = 0, .minimum_version_id_old = 0, .post_load = vmsvga_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32_EQUAL(depth, struct vmsvga_state_s), VMSTATE_INT32(enable, struct vmsvga_state_s), VMSTATE_INT32(config, struct vmsvga_state_s), @@ -1060,7 +1104,7 @@ static const VMStateDescription vmstate_vmware_vga_internal = { VMSTATE_UINT32(guest, struct vmsvga_state_s), VMSTATE_UINT32(svgaid, struct vmsvga_state_s), VMSTATE_INT32(syncing, struct vmsvga_state_s), - VMSTATE_INT32(fb_size, struct vmsvga_state_s), + VMSTATE_UNUSED(4), /* was fb_size */ VMSTATE_END_OF_LIST() } }; @@ -1070,7 +1114,7 @@ static const VMStateDescription vmstate_vmware_vga = { .version_id = 0, .minimum_version_id = 0, .minimum_version_id_old = 0, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(card, struct pci_vmsvga_state_s), VMSTATE_STRUCT(chip, struct pci_vmsvga_state_s, 0, vmstate_vmware_vga_internal, struct vmsvga_state_s), @@ -1098,40 +1142,16 @@ static void vmsvga_init(struct vmsvga_state_s *s, vga_common_init(&s->vga); vga_init(&s->vga, address_space, io, true); vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga); - + /* Save some values here in case they are changed later. + * This is suspicious and needs more though why it is needed. */ s->depth = ds_get_bits_per_pixel(s->vga.ds); s->bypp = ds_get_bytes_per_pixel(s->vga.ds); - switch (s->depth) { - case 8: - s->wred = 0x00000007; - s->wgreen = 0x00000038; - s->wblue = 0x000000c0; - break; - case 15: - s->wred = 0x0000001f; - s->wgreen = 0x000003e0; - s->wblue = 0x00007c00; - break; - case 16: - s->wred = 0x0000001f; - s->wgreen = 0x000007e0; - s->wblue = 0x0000f800; - break; - case 24: - s->wred = 0x00ff0000; - s->wgreen = 0x0000ff00; - s->wblue = 0x000000ff; - break; - case 32: - s->wred = 0x00ff0000; - s->wgreen = 0x0000ff00; - s->wblue = 0x000000ff; - break; - } + s->wred = ds_get_rmask(s->vga.ds); + s->wgreen = ds_get_gmask(s->vga.ds); + s->wblue = ds_get_bmask(s->vga.ds); } -static uint64_t vmsvga_io_read(void *opaque, target_phys_addr_t addr, - unsigned size) +static uint64_t vmsvga_io_read(void *opaque, hwaddr addr, unsigned size) { struct vmsvga_state_s *s = opaque; @@ -1143,7 +1163,7 @@ static uint64_t vmsvga_io_read(void *opaque, target_phys_addr_t addr, } } -static void vmsvga_io_write(void *opaque, target_phys_addr_t addr, +static void vmsvga_io_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { struct vmsvga_state_s *s = opaque; @@ -1175,22 +1195,20 @@ static int pci_vmsvga_initfn(PCIDevice *dev) { struct pci_vmsvga_state_s *s = DO_UPCAST(struct pci_vmsvga_state_s, card, dev); - MemoryRegion *iomem; - - iomem = &s->chip.vga.vram; - s->card.config[PCI_CACHE_LINE_SIZE] = 0x08; /* Cache line size */ - s->card.config[PCI_LATENCY_TIMER] = 0x40; /* Latency timer */ - s->card.config[PCI_INTERRUPT_LINE] = 0xff; /* End */ + s->card.config[PCI_CACHE_LINE_SIZE] = 0x08; /* Cache line size */ + s->card.config[PCI_LATENCY_TIMER] = 0x40; /* Latency timer */ + s->card.config[PCI_INTERRUPT_LINE] = 0xff; /* End */ memory_region_init_io(&s->io_bar, &vmsvga_io_ops, &s->chip, "vmsvga-io", 0x10); + memory_region_set_flush_coalesced(&s->io_bar); pci_register_bar(&s->card, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar); - vmsvga_init(&s->chip, pci_address_space(dev), - pci_address_space_io(dev)); + vmsvga_init(&s->chip, pci_address_space(dev), pci_address_space_io(dev)); - pci_register_bar(&s->card, 1, PCI_BASE_ADDRESS_MEM_PREFETCH, iomem); + pci_register_bar(&s->card, 1, PCI_BASE_ADDRESS_MEM_PREFETCH, + &s->chip.vga.vram); pci_register_bar(&s->card, 2, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->chip.fifo_ram); diff --git a/hw/vmware_vga.h b/hw/vmware_vga.h deleted file mode 100644 index 000fbddc0f..0000000000 --- a/hw/vmware_vga.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef QEMU_VMWARE_VGA_H -#define QEMU_VMWARE_VGA_H - -#include "qemu-common.h" - -/* vmware_vga.c */ -static inline DeviceState *pci_vmsvga_init(PCIBus *bus) -{ - PCIDevice *dev; - - dev = pci_create_simple(bus, -1, "vmware-svga"); - return &dev->qdev; -} - -#endif diff --git a/hw/vt82c686.c b/hw/vt82c686.c index 5d7c00cf4b..d3469d49f1 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -15,18 +15,19 @@ #include "vt82c686.h" #include "i2c.h" #include "smbus.h" -#include "pci.h" +#include "pci/pci.h" #include "isa.h" #include "sysbus.h" #include "mips.h" #include "apm.h" #include "acpi.h" #include "pm_smbus.h" -#include "sysemu.h" -#include "qemu-timer.h" +#include "sysemu/sysemu.h" +#include "qemu/timer.h" +#include "exec/address-spaces.h" typedef uint32_t pci_addr_t; -#include "pci_host.h" +#include "pci/pci_host.h" //#define DEBUG_VT82C686B #ifdef DEBUG_VT82C686B @@ -159,6 +160,7 @@ static void vt82c686b_write_config(PCIDevice * d, uint32_t address, typedef struct VT686PMState { PCIDevice dev; + MemoryRegion io; ACPIREGS ar; APMState apm; PMSMBus smb; @@ -195,92 +197,17 @@ static void pm_tmr_timer(ACPIREGS *ar) pm_update_sci(s); } -static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val) -{ - VT686PMState *s = opaque; - - addr &= 0x0f; - switch (addr) { - case 0x00: - acpi_pm1_evt_write_sts(&s->ar, val); - pm_update_sci(s); - break; - case 0x02: - acpi_pm1_evt_write_en(&s->ar, val); - pm_update_sci(s); - break; - case 0x04: - acpi_pm1_cnt_write(&s->ar, val, 0); - break; - default: - break; - } - DPRINTF("PM writew port=0x%04x val=0x%02x\n", addr, val); -} - -static uint32_t pm_ioport_readw(void *opaque, uint32_t addr) -{ - VT686PMState *s = opaque; - uint32_t val; - - addr &= 0x0f; - switch (addr) { - case 0x00: - val = acpi_pm1_evt_get_sts(&s->ar); - break; - case 0x02: - val = s->ar.pm1.evt.en; - break; - case 0x04: - val = s->ar.pm1.cnt.cnt; - break; - default: - val = 0; - break; - } - DPRINTF("PM readw port=0x%04x val=0x%02x\n", addr, val); - return val; -} - -static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val) -{ - addr &= 0x0f; - DPRINTF("PM writel port=0x%04x val=0x%08x\n", addr, val); -} - -static uint32_t pm_ioport_readl(void *opaque, uint32_t addr) -{ - VT686PMState *s = opaque; - uint32_t val; - - addr &= 0x0f; - switch (addr) { - case 0x08: - val = acpi_pm_tmr_get(&s->ar); - break; - default: - val = 0; - break; - } - DPRINTF("PM readl port=0x%04x val=0x%08x\n", addr, val); - return val; -} - static void pm_io_space_update(VT686PMState *s) { uint32_t pm_io_base; - if (s->dev.config[0x80] & 1) { - pm_io_base = pci_get_long(s->dev.config + 0x40); - pm_io_base &= 0xffc0; + pm_io_base = pci_get_long(s->dev.config + 0x40); + pm_io_base &= 0xffc0; - /* XXX: need to improve memory and ioport allocation */ - DPRINTF("PM: mapping to 0x%x\n", pm_io_base); - register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s); - register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s); - register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s); - register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s); - } + memory_region_transaction_begin(); + memory_region_set_enabled(&s->io, s->dev.config[0x80] & 1); + memory_region_set_address(&s->io, pm_io_base); + memory_region_transaction_commit(); } static void pm_write_config(PCIDevice *d, @@ -424,15 +351,18 @@ static int vt82c686b_pm_initfn(PCIDevice *dev) pci_conf[0x90] = s->smb_io_base | 1; pci_conf[0x91] = s->smb_io_base >> 8; pci_conf[0xd2] = 0x90; - register_ioport_write(s->smb_io_base, 0xf, 1, smb_ioport_writeb, &s->smb); - register_ioport_read(s->smb_io_base, 0xf, 1, smb_ioport_readb, &s->smb); + pm_smbus_init(&s->dev.qdev, &s->smb); + memory_region_add_subregion(get_system_io(), s->smb_io_base, &s->smb.io); - apm_init(&s->apm, NULL, s); + apm_init(dev, &s->apm, NULL, s); - acpi_pm_tmr_init(&s->ar, pm_tmr_timer); - acpi_pm1_cnt_init(&s->ar); + memory_region_init(&s->io, "vt82c686-pm", 64); + memory_region_set_enabled(&s->io, false); + memory_region_add_subregion(get_system_io(), 0, &s->io); - pm_smbus_init(&s->dev.qdev, &s->smb); + acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io); + acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io); + acpi_pm1_cnt_init(&s->ar, &s->io); return 0; } diff --git a/hw/watchdog.c b/hw/watchdog.c index b52acedd98..072d256882 100644 --- a/hw/watchdog.c +++ b/hw/watchdog.c @@ -20,12 +20,12 @@ */ #include "qemu-common.h" -#include "qemu-option.h" -#include "qemu-config.h" -#include "qemu-queue.h" -#include "qemu-objects.h" -#include "monitor.h" -#include "sysemu.h" +#include "qemu/option.h" +#include "qemu/config-file.h" +#include "qemu/queue.h" +#include "qapi/qmp/types.h" +#include "monitor/monitor.h" +#include "sysemu/sysemu.h" #include "hw/watchdog.h" /* Possible values for action parameter. */ @@ -66,7 +66,7 @@ int select_watchdog(const char *p) QLIST_FOREACH(model, &watchdog_list, entry) { if (strcasecmp(model->wdt_name, p) == 0) { /* add the device */ - opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0, NULL); + opts = qemu_opts_create_nofail(qemu_find_opts("device")); qemu_opt_set(opts, "driver", p); return 0; } diff --git a/hw/watchdog.h b/hw/watchdog.h index c12a29311a..3e9a970686 100644 --- a/hw/watchdog.h +++ b/hw/watchdog.h @@ -22,7 +22,7 @@ #ifndef QEMU_WATCHDOG_H #define QEMU_WATCHDOG_H -#include "qemu-queue.h" +#include "qemu/queue.h" struct WatchdogTimerModel { QLIST_ENTRY(WatchdogTimerModel) entry; diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c index 4a83474906..54f0665135 100644 --- a/hw/wdt_i6300esb.c +++ b/hw/wdt_i6300esb.c @@ -22,10 +22,10 @@ #include <inttypes.h> #include "qemu-common.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "watchdog.h" #include "hw.h" -#include "pci.h" +#include "pci/pci.h" /*#define I6300ESB_DEBUG 1*/ @@ -257,14 +257,14 @@ static uint32_t i6300esb_config_read(PCIDevice *dev, uint32_t addr, int len) } } -static uint32_t i6300esb_mem_readb(void *vp, target_phys_addr_t addr) +static uint32_t i6300esb_mem_readb(void *vp, hwaddr addr) { i6300esb_debug ("addr = %x\n", (int) addr); return 0; } -static uint32_t i6300esb_mem_readw(void *vp, target_phys_addr_t addr) +static uint32_t i6300esb_mem_readw(void *vp, hwaddr addr) { uint32_t data = 0; I6300State *d = vp; @@ -282,14 +282,14 @@ static uint32_t i6300esb_mem_readw(void *vp, target_phys_addr_t addr) return data; } -static uint32_t i6300esb_mem_readl(void *vp, target_phys_addr_t addr) +static uint32_t i6300esb_mem_readl(void *vp, hwaddr addr) { i6300esb_debug("addr = %x\n", (int) addr); return 0; } -static void i6300esb_mem_writeb(void *vp, target_phys_addr_t addr, uint32_t val) +static void i6300esb_mem_writeb(void *vp, hwaddr addr, uint32_t val) { I6300State *d = vp; @@ -301,7 +301,7 @@ static void i6300esb_mem_writeb(void *vp, target_phys_addr_t addr, uint32_t val) d->unlock_state = 2; } -static void i6300esb_mem_writew(void *vp, target_phys_addr_t addr, uint32_t val) +static void i6300esb_mem_writew(void *vp, hwaddr addr, uint32_t val) { I6300State *d = vp; @@ -334,7 +334,7 @@ static void i6300esb_mem_writew(void *vp, target_phys_addr_t addr, uint32_t val) } } -static void i6300esb_mem_writel(void *vp, target_phys_addr_t addr, uint32_t val) +static void i6300esb_mem_writel(void *vp, hwaddr addr, uint32_t val) { I6300State *d = vp; diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c index 7f6c21d809..4475f7b862 100644 --- a/hw/wdt_ib700.c +++ b/hw/wdt_ib700.c @@ -20,7 +20,7 @@ */ #include "qemu-common.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "watchdog.h" #include "hw.h" #include "isa.h" diff --git a/hw/wm8750.c b/hw/wm8750.c index 11bcec3410..44f138fd51 100644 --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -361,10 +361,10 @@ static int wm8750_tx(I2CSlave *i2c, uint8_t data) uint16_t value; if (s->i2c_len >= 2) { - printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len); #ifdef VERBOSE - return 1; + printf("%s: long message (%i bytes)\n", __func__, s->i2c_len); #endif + return 1; } s->i2c_data[s->i2c_len ++] = data; if (s->i2c_len != 2) diff --git a/hw/xen-host-pci-device.c b/hw/xen-host-pci-device.c index e7ff680ef2..743b37b991 100644 --- a/hw/xen-host-pci-device.c +++ b/hw/xen-host-pci-device.c @@ -47,13 +47,13 @@ static int xen_host_pci_sysfs_path(const XenHostPCIDevice *d, } -/* This size should be enough to read the first 7 lines of a ressource file */ -#define XEN_HOST_PCI_RESSOURCE_BUFFER_SIZE 400 +/* This size should be enough to read the first 7 lines of a resource file */ +#define XEN_HOST_PCI_RESOURCE_BUFFER_SIZE 400 static int xen_host_pci_get_resource(XenHostPCIDevice *d) { int i, rc, fd; char path[PATH_MAX]; - char buf[XEN_HOST_PCI_RESSOURCE_BUFFER_SIZE]; + char buf[XEN_HOST_PCI_RESOURCE_BUFFER_SIZE]; unsigned long long start, end, flags, size; char *endptr, *s; uint8_t type; diff --git a/hw/xen-host-pci-device.h b/hw/xen-host-pci-device.h index 0079daca51..942b24dccc 100644 --- a/hw/xen-host-pci-device.h +++ b/hw/xen-host-pci-device.h @@ -1,7 +1,7 @@ #ifndef XEN_HOST_PCI_DEVICE_H #define XEN_HOST_PCI_DEVICE_H -#include "pci.h" +#include "pci/pci.h" enum { XEN_HOST_PCI_REGION_TYPE_IO = 1 << 1, @@ -8,6 +8,7 @@ */ #include <inttypes.h> +#include "hw/irq.h" #include "qemu-common.h" /* xen-machine.c */ @@ -48,6 +49,7 @@ void xenstore_store_pv_console_info(int i, struct CharDriverState *chr); struct MemoryRegion; void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, struct MemoryRegion *mr); +void xen_modified_memory(ram_addr_t start, ram_addr_t length); #endif struct MemoryRegion; diff --git a/hw/xen_apic.c b/hw/xen_apic.c index a9e101f315..a6632fe798 100644 --- a/hw/xen_apic.c +++ b/hw/xen_apic.c @@ -10,16 +10,16 @@ * later. See the COPYING file in the top-level directory. */ #include "hw/apic_internal.h" -#include "hw/msi.h" +#include "hw/pci/msi.h" #include "xen.h" -static uint64_t xen_apic_mem_read(void *opaque, target_phys_addr_t addr, +static uint64_t xen_apic_mem_read(void *opaque, hwaddr addr, unsigned size) { return ~(uint64_t)0; } -static void xen_apic_mem_write(void *opaque, target_phys_addr_t addr, +static void xen_apic_mem_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { if (size != sizeof(uint32_t)) { diff --git a/hw/xen_backend.c b/hw/xen_backend.c index f83a1e1d09..3fa30098ca 100644 --- a/hw/xen_backend.c +++ b/hw/xen_backend.c @@ -35,8 +35,8 @@ #include <sys/signal.h> #include "hw.h" -#include "qemu-char.h" -#include "qemu-log.h" +#include "char/char.h" +#include "qemu/log.h" #include "xen_backend.h" #include <xen/grant_table.h> diff --git a/hw/xen_backend.h b/hw/xen_backend.h index fea86dd78b..f37afb1f05 100644 --- a/hw/xen_backend.h +++ b/hw/xen_backend.h @@ -2,9 +2,8 @@ #define QEMU_HW_XEN_BACKEND_H 1 #include "xen_common.h" -#include "sysemu.h" -#include "net.h" -#include "net/hub.h" +#include "sysemu/sysemu.h" +#include "net/net.h" /* ------------------------------------------------------------- */ diff --git a/hw/xen_common.h b/hw/xen_common.h index 727757afb4..95bc9a7825 100644 --- a/hw/xen_common.h +++ b/hw/xen_common.h @@ -16,7 +16,7 @@ #include "hw.h" #include "xen.h" -#include "qemu-queue.h" +#include "qemu/queue.h" /* * We don't support Xen prior to 3.3.0. diff --git a/hw/xen_console.c b/hw/xen_console.c index 9426d7374f..44141f8692 100644 --- a/hw/xen_console.c +++ b/hw/xen_console.c @@ -30,7 +30,7 @@ #include <sys/mman.h> #include "hw.h" -#include "qemu-char.h" +#include "char/char.h" #include "xen_backend.h" #include <xen/io/console.h> @@ -184,7 +184,11 @@ static int con_init(struct XenDevice *xendev) /* setup */ dom = xs_get_domain_path(xenstore, con->xendev.dom); - snprintf(con->console, sizeof(con->console), "%s/console", dom); + if (!xendev->dev) { + snprintf(con->console, sizeof(con->console), "%s/console", dom); + } else { + snprintf(con->console, sizeof(con->console), "%s/device/console/%d", dom, xendev->dev); + } free(dom); type = xenstore_read_str(con->console, "type"); @@ -223,10 +227,16 @@ static int con_initialise(struct XenDevice *xendev) if (xenstore_read_int(con->console, "limit", &limit) == 0) con->buffer.max_capacity = limit; - con->sring = xc_map_foreign_range(xen_xc, con->xendev.dom, - XC_PAGE_SIZE, - PROT_READ|PROT_WRITE, - con->ring_ref); + if (!xendev->dev) { + con->sring = xc_map_foreign_range(xen_xc, con->xendev.dom, + XC_PAGE_SIZE, + PROT_READ|PROT_WRITE, + con->ring_ref); + } else { + con->sring = xc_gnttab_map_grant_ref(xendev->gnttabdev, con->xendev.dom, + con->ring_ref, + PROT_READ|PROT_WRITE); + } if (!con->sring) return -1; @@ -255,7 +265,11 @@ static void con_disconnect(struct XenDevice *xendev) xen_be_unbind_evtchn(&con->xendev); if (con->sring) { - munmap(con->sring, XC_PAGE_SIZE); + if (!xendev->gnttabdev) { + munmap(con->sring, XC_PAGE_SIZE); + } else { + xc_gnttab_munmap(xendev->gnttabdev, con->sring, 1); + } con->sring = NULL; } } @@ -273,7 +287,7 @@ static void con_event(struct XenDevice *xendev) struct XenDevOps xen_console_ops = { .size = sizeof(struct XenConsole), - .flags = DEVOPS_FLAG_IGNORE_STATE, + .flags = DEVOPS_FLAG_IGNORE_STATE|DEVOPS_FLAG_NEED_GNTDEV, .init = con_init, .initialise = con_initialise, .event = con_event, diff --git a/hw/xen_devconfig.c b/hw/xen_devconfig.c index d83e8d0f64..e2ba741d54 100644 --- a/hw/xen_devconfig.c +++ b/hw/xen_devconfig.c @@ -1,5 +1,5 @@ #include "xen_backend.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" /* ------------------------------------------------------------- */ diff --git a/hw/xen_disk.c b/hw/xen_disk.c index e6bb2f20b9..a6a64a2455 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -36,10 +36,9 @@ #include <sys/uio.h> #include "hw.h" -#include "qemu-char.h" #include "xen_backend.h" #include "xen_blkif.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" /* ------------------------------------------------------------- */ diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c index a6a12e5930..a4272f0680 100644 --- a/hw/xen_domainbuild.c +++ b/hw/xen_domainbuild.c @@ -1,8 +1,8 @@ #include <signal.h> #include "xen_backend.h" #include "xen_domainbuild.h" -#include "qemu-timer.h" -#include "qemu-log.h" +#include "qemu/timer.h" +#include "qemu/log.h" #include <xenguest.h> @@ -153,7 +153,6 @@ static void xen_domain_poll(void *opaque) quit: qemu_system_shutdown_request(); - return; } static int xen_domain_watcher(void) diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c index 4b72aa7557..9feecd5a27 100644 --- a/hw/xen_machine_pv.c +++ b/hw/xen_machine_pv.c @@ -27,15 +27,14 @@ #include "boards.h" #include "xen_backend.h" #include "xen_domainbuild.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" -static void xen_init_pv(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void xen_init_pv(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; X86CPU *cpu; CPUX86State *env; DriveInfo *dinfo; diff --git a/hw/xen_nic.c b/hw/xen_nic.c index 8b79bfb73e..dc12110dba 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -36,10 +36,9 @@ #include <sys/wait.h> #include "hw.h" -#include "net.h" +#include "net/net.h" #include "net/checksum.h" #include "net/util.h" -#include "qemu-char.h" #include "xen_backend.h" #include <xen/io/netif.h> @@ -415,6 +414,7 @@ static void net_event(struct XenDevice *xendev) { struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev); net_tx_packets(netdev); + qemu_flush_queued_packets(&netdev->nic->nc); } static int net_free(struct XenDevice *xendev) diff --git a/hw/xen_platform.c b/hw/xen_platform.c index c1fe984f07..e7611bb353 100644 --- a/hw/xen_platform.c +++ b/hw/xen_platform.c @@ -27,13 +27,12 @@ #include "hw.h" #include "pc.h" -#include "pci.h" +#include "pci/pci.h" #include "irq.h" #include "xen_common.h" -#include "net.h" #include "xen_backend.h" #include "trace.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #include <xenguest.h> @@ -85,11 +84,10 @@ static void log_writeb(PCIXenPlatformState *s, char val) static void unplug_nic(PCIBus *b, PCIDevice *d, void *o) { + /* We have to ignore passthrough devices */ if (pci_get_word(d->config + PCI_CLASS_DEVICE) == - PCI_CLASS_NETWORK_ETHERNET) { - /* Until qdev_free includes a call to object_unparent, we call it here - */ - object_unparent(&d->qdev.parent_obj); + PCI_CLASS_NETWORK_ETHERNET + && strcmp(d->name, "xen-pci-passthrough") != 0) { qdev_free(&d->qdev); } } @@ -101,8 +99,10 @@ static void pci_unplug_nics(PCIBus *bus) static void unplug_disks(PCIBus *b, PCIDevice *d, void *o) { + /* We have to ignore passthrough devices */ if (pci_get_word(d->config + PCI_CLASS_DEVICE) == - PCI_CLASS_STORAGE_IDE) { + PCI_CLASS_STORAGE_IDE + && strcmp(d->name, "xen-pci-passthrough") != 0) { qdev_unplug(&(d->qdev), NULL); } } @@ -227,18 +227,46 @@ static void platform_fixed_ioport_reset(void *opaque) platform_fixed_ioport_writeb(s, 0, 0); } -const MemoryRegionPortio xen_platform_ioport[] = { - { 0, 16, 4, .write = platform_fixed_ioport_writel, }, - { 0, 16, 2, .write = platform_fixed_ioport_writew, }, - { 0, 16, 1, .write = platform_fixed_ioport_writeb, }, - { 0, 16, 2, .read = platform_fixed_ioport_readw, }, - { 0, 16, 1, .read = platform_fixed_ioport_readb, }, - PORTIO_END_OF_LIST() -}; +static uint64_t platform_fixed_ioport_read(void *opaque, + hwaddr addr, + unsigned size) +{ + switch (size) { + case 1: + return platform_fixed_ioport_readb(opaque, addr); + case 2: + return platform_fixed_ioport_readw(opaque, addr); + default: + return -1; + } +} + +static void platform_fixed_ioport_write(void *opaque, hwaddr addr, + + uint64_t val, unsigned size) +{ + switch (size) { + case 1: + platform_fixed_ioport_writeb(opaque, addr, val); + break; + case 2: + platform_fixed_ioport_writew(opaque, addr, val); + break; + case 4: + platform_fixed_ioport_writel(opaque, addr, val); + break; + } +} + static const MemoryRegionOps platform_fixed_io_ops = { - .old_portio = xen_platform_ioport, - .endianness = DEVICE_NATIVE_ENDIAN, + .read = platform_fixed_ioport_read, + .write = platform_fixed_ioport_write, + .impl = { + .min_access_size = 1, + .max_access_size = 4, + }, + .endianness = DEVICE_LITTLE_ENDIAN, }; static void platform_fixed_ioport_init(PCIXenPlatformState* s) @@ -291,7 +319,7 @@ static void platform_ioport_bar_setup(PCIXenPlatformState *d) memory_region_init_io(&d->bar, &xen_pci_io_ops, d, "xen-pci", 0x100); } -static uint64_t platform_mmio_read(void *opaque, target_phys_addr_t addr, +static uint64_t platform_mmio_read(void *opaque, hwaddr addr, unsigned size) { DPRINTF("Warning: attempted read from physical address " @@ -300,7 +328,7 @@ static uint64_t platform_mmio_read(void *opaque, target_phys_addr_t addr, return 0; } -static void platform_mmio_write(void *opaque, target_phys_addr_t addr, +static void platform_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { DPRINTF("Warning: attempted write of 0x%"PRIx64" to physical " diff --git a/hw/xen_pt.c b/hw/xen_pt.c index 307119a12f..6fd8433a2d 100644 --- a/hw/xen_pt.c +++ b/hw/xen_pt.c @@ -54,11 +54,12 @@ #include <sys/ioctl.h> -#include "pci.h" +#include "pci/pci.h" #include "xen.h" #include "xen_backend.h" #include "xen_pt.h" -#include "range.h" +#include "qemu/range.h" +#include "exec/address-spaces.h" #define XEN_PT_NR_IRQS (256) static uint8_t xen_pt_mapped_machine_irq[XEN_PT_NR_IRQS] = {0}; @@ -362,7 +363,7 @@ out: /* register regions */ -static uint64_t xen_pt_bar_read(void *o, target_phys_addr_t addr, +static uint64_t xen_pt_bar_read(void *o, hwaddr addr, unsigned size) { PCIDevice *d = o; @@ -372,7 +373,7 @@ static uint64_t xen_pt_bar_read(void *o, target_phys_addr_t addr, addr); return 0; } -static void xen_pt_bar_write(void *o, target_phys_addr_t addr, uint64_t val, +static void xen_pt_bar_write(void *o, hwaddr addr, uint64_t val, unsigned size) { PCIDevice *d = o; @@ -410,14 +411,17 @@ static int xen_pt_register_regions(XenPCIPassthroughState *s) if (r->type & XEN_HOST_PCI_REGION_TYPE_PREFETCH) { type |= PCI_BASE_ADDRESS_MEM_PREFETCH; } + if (r->type & XEN_HOST_PCI_REGION_TYPE_MEM_64) { + type |= PCI_BASE_ADDRESS_MEM_TYPE_64; + } } memory_region_init_io(&s->bar[i], &ops, &s->dev, "xen-pci-pt-bar", r->size); pci_register_bar(&s->dev, i, type, &s->bar[i]); - XEN_PT_LOG(&s->dev, "IO region %i registered (size=0x%08"PRIx64 - " base_addr=0x%08"PRIx64" type: %#x)\n", + XEN_PT_LOG(&s->dev, "IO region %i registered (size=0x%lx"PRIx64 + " base_addr=0x%lx"PRIx64" type: %#x)\n", i, r->size, r->base_addr, type); } @@ -597,14 +601,6 @@ static void xen_pt_region_update(XenPCIPassthroughState *s, } } -static void xen_pt_begin(MemoryListener *l) -{ -} - -static void xen_pt_commit(MemoryListener *l) -{ -} - static void xen_pt_region_add(MemoryListener *l, MemoryRegionSection *sec) { XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState, @@ -621,36 +617,31 @@ static void xen_pt_region_del(MemoryListener *l, MemoryRegionSection *sec) xen_pt_region_update(s, sec, false); } -static void xen_pt_region_nop(MemoryListener *l, MemoryRegionSection *s) +static void xen_pt_io_region_add(MemoryListener *l, MemoryRegionSection *sec) { -} + XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState, + io_listener); -static void xen_pt_log_fns(MemoryListener *l, MemoryRegionSection *s) -{ + xen_pt_region_update(s, sec, true); } -static void xen_pt_log_global_fns(MemoryListener *l) +static void xen_pt_io_region_del(MemoryListener *l, MemoryRegionSection *sec) { -} + XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState, + io_listener); -static void xen_pt_eventfd_fns(MemoryListener *l, MemoryRegionSection *s, - bool match_data, uint64_t data, EventNotifier *n) -{ + xen_pt_region_update(s, sec, false); } static const MemoryListener xen_pt_memory_listener = { - .begin = xen_pt_begin, - .commit = xen_pt_commit, .region_add = xen_pt_region_add, - .region_nop = xen_pt_region_nop, .region_del = xen_pt_region_del, - .log_start = xen_pt_log_fns, - .log_stop = xen_pt_log_fns, - .log_sync = xen_pt_log_fns, - .log_global_start = xen_pt_log_global_fns, - .log_global_stop = xen_pt_log_global_fns, - .eventfd_add = xen_pt_eventfd_fns, - .eventfd_del = xen_pt_eventfd_fns, + .priority = 10, +}; + +static const MemoryListener xen_pt_io_listener = { + .region_add = xen_pt_io_region_add, + .region_del = xen_pt_io_region_del, .priority = 10, }; @@ -680,7 +671,8 @@ static int xen_pt_initfn(PCIDevice *d) s->is_virtfn = s->real_device.is_virtfn; if (s->is_virtfn) { XEN_PT_LOG(d, "%04x:%02x:%02x.%d is a SR-IOV Virtual Function\n", - s->real_device.domain, bus, slot, func); + s->real_device.domain, s->real_device.bus, + s->real_device.dev, s->real_device.func); } /* Initialize virtualized PCI configuration (Extended 256 Bytes) */ @@ -691,6 +683,7 @@ static int xen_pt_initfn(PCIDevice *d) } s->memory_listener = xen_pt_memory_listener; + s->io_listener = xen_pt_io_listener; /* Handle real device's MMIO/PIO BARs */ xen_pt_register_regions(s); @@ -757,9 +750,10 @@ static int xen_pt_initfn(PCIDevice *d) } out: - memory_listener_register(&s->memory_listener, NULL); + memory_listener_register(&s->memory_listener, &address_space_memory); + memory_listener_register(&s->io_listener, &address_space_io); XEN_PT_LOG(d, "Real physical device %02x:%02x.%d registered successfuly!\n", - bus, slot, func); + s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function); return 0; } @@ -812,6 +806,7 @@ static void xen_pt_unregister_device(PCIDevice *d) xen_pt_unregister_regions(s); memory_listener_unregister(&s->memory_listener); + memory_listener_unregister(&s->io_listener); xen_host_pci_device_put(&s->real_device); } diff --git a/hw/xen_pt.h b/hw/xen_pt.h index 41904ece93..e3497302cf 100644 --- a/hw/xen_pt.h +++ b/hw/xen_pt.h @@ -3,7 +3,7 @@ #include "qemu-common.h" #include "xen_common.h" -#include "pci.h" +#include "pci/pci.h" #include "xen-host-pci-device.h" void xen_pt_log(const PCIDevice *d, const char *f, ...) GCC_FMT_ATTR(2, 3); @@ -96,7 +96,7 @@ typedef struct XenPTRegion { * - do NOT use ALL F for init_val, otherwise the tbl will not be registered. */ -/* emulated register infomation */ +/* emulated register information */ struct XenPTRegInfo { uint32_t offset; uint32_t size; @@ -140,7 +140,7 @@ typedef int (*xen_pt_reg_size_init_fn) (XenPCIPassthroughState *, const XenPTRegGroupInfo *, uint32_t base_offset, uint8_t *size); -/* emulated register group infomation */ +/* emulated register group information */ struct XenPTRegGroupInfo { uint8_t grp_id; XenPTRegisterGroupType grp_type; @@ -209,6 +209,7 @@ struct XenPCIPassthroughState { MemoryRegion rom; MemoryListener memory_listener; + MemoryListener io_listener; }; int xen_pt_config_init(XenPCIPassthroughState *s); diff --git a/hw/xen_pt_config_init.c b/hw/xen_pt_config_init.c index 00eb3d997d..54a179af90 100644 --- a/hw/xen_pt_config_init.c +++ b/hw/xen_pt_config_init.c @@ -12,7 +12,7 @@ * This file implements direct PCI assignment to a HVM guest */ -#include "qemu-timer.h" +#include "qemu/timer.h" #include "xen_backend.h" #include "xen_pt.h" @@ -342,6 +342,23 @@ static int xen_pt_cmd_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, #define XEN_PT_BAR_IO_RO_MASK 0x00000003 /* BAR ReadOnly mask(I/O) */ #define XEN_PT_BAR_IO_EMU_MASK 0xFFFFFFFC /* BAR emul mask(I/O) */ +static bool is_64bit_bar(PCIIORegion *r) +{ + return !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64); +} + +static uint64_t xen_pt_get_bar_size(PCIIORegion *r) +{ + if (is_64bit_bar(r)) { + uint64_t size64; + size64 = (r + 1)->size; + size64 <<= 32; + size64 += r->size; + return size64; + } + return r->size; +} + static XenPTBarFlag xen_pt_bar_reg_parse(XenPCIPassthroughState *s, XenPTRegInfo *reg) { @@ -366,7 +383,7 @@ static XenPTBarFlag xen_pt_bar_reg_parse(XenPCIPassthroughState *s, /* check unused BAR */ r = &d->io_regions[index]; - if (r->size == 0) { + if (!xen_pt_get_bar_size(r)) { return XEN_PT_BAR_FLAG_UNUSED; } @@ -481,7 +498,12 @@ static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, switch (s->bases[index].bar_flag) { case XEN_PT_BAR_FLAG_MEM: bar_emu_mask = XEN_PT_BAR_MEM_EMU_MASK; - bar_ro_mask = XEN_PT_BAR_MEM_RO_MASK | (r_size - 1); + if (!r_size) { + /* low 32 bits mask for 64 bit bars */ + bar_ro_mask = XEN_PT_BAR_ALLF; + } else { + bar_ro_mask = XEN_PT_BAR_MEM_RO_MASK | (r_size - 1); + } break; case XEN_PT_BAR_FLAG_IO: bar_emu_mask = XEN_PT_BAR_IO_EMU_MASK; @@ -489,7 +511,7 @@ static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, break; case XEN_PT_BAR_FLAG_UPPER: bar_emu_mask = XEN_PT_BAR_ALLF; - bar_ro_mask = 0; /* all upper 32bit are R/W */ + bar_ro_mask = r_size ? r_size - 1 : 0; break; default: break; @@ -501,22 +523,13 @@ static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, /* check whether we need to update the virtual region address or not */ switch (s->bases[index].bar_flag) { + case XEN_PT_BAR_FLAG_UPPER: case XEN_PT_BAR_FLAG_MEM: /* nothing to do */ break; case XEN_PT_BAR_FLAG_IO: /* nothing to do */ break; - case XEN_PT_BAR_FLAG_UPPER: - if (cfg_entry->data) { - if (cfg_entry->data != (XEN_PT_BAR_ALLF & ~bar_ro_mask)) { - XEN_PT_WARN(d, "Guest attempt to set high MMIO Base Address. " - "Ignore mapping. " - "(offset: 0x%02x, high address: 0x%08x)\n", - reg->offset, cfg_entry->data); - } - } - break; default: break; } @@ -562,7 +575,7 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s, return 0; } -/* Header Type0 reg static infomation table */ +/* Header Type0 reg static information table */ static XenPTRegInfo xen_pt_emu_reg_header0[] = { /* Vendor ID reg */ { @@ -753,7 +766,7 @@ static XenPTRegInfo xen_pt_emu_reg_header0[] = { * Vital Product Data Capability */ -/* Vital Product Data Capability Structure reg static infomation table */ +/* Vital Product Data Capability Structure reg static information table */ static XenPTRegInfo xen_pt_emu_reg_vpd[] = { { .offset = PCI_CAP_LIST_NEXT, @@ -775,7 +788,7 @@ static XenPTRegInfo xen_pt_emu_reg_vpd[] = { * Vendor Specific Capability */ -/* Vendor Specific Capability Structure reg static infomation table */ +/* Vendor Specific Capability Structure reg static information table */ static XenPTRegInfo xen_pt_emu_reg_vendor[] = { { .offset = PCI_CAP_LIST_NEXT, @@ -866,7 +879,7 @@ static int xen_pt_linkctrl2_reg_init(XenPCIPassthroughState *s, return 0; } -/* PCI Express Capability Structure reg static infomation table */ +/* PCI Express Capability Structure reg static information table */ static XenPTRegInfo xen_pt_emu_reg_pcie[] = { /* Next Pointer reg */ { @@ -981,7 +994,7 @@ static int xen_pt_pmcsr_reg_write(XenPCIPassthroughState *s, return 0; } -/* Power Management Capability reg static infomation table */ +/* Power Management Capability reg static information table */ static XenPTRegInfo xen_pt_emu_reg_pm[] = { /* Next Pointer reg */ { @@ -1259,7 +1272,7 @@ static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s, return 0; } -/* MSI Capability Structure reg static infomation table */ +/* MSI Capability Structure reg static information table */ static XenPTRegInfo xen_pt_emu_reg_msi[] = { /* Next Pointer reg */ { @@ -1396,7 +1409,7 @@ static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s, return 0; } -/* MSI-X Capability Structure reg static infomation table */ +/* MSI-X Capability Structure reg static information table */ static XenPTRegInfo xen_pt_emu_reg_msix[] = { /* Next Pointer reg */ { diff --git a/hw/xen_pt_msi.c b/hw/xen_pt_msi.c index 2299cc7772..db757cd1f1 100644 --- a/hw/xen_pt_msi.c +++ b/hw/xen_pt_msi.c @@ -321,7 +321,7 @@ static int xen_pt_msix_update_one(XenPCIPassthroughState *s, int entry_nr) pirq = entry->pirq; - rc = msi_msix_setup(s, entry->data, entry->data, &pirq, true, entry_nr, + rc = msi_msix_setup(s, entry->addr, entry->data, &pirq, true, entry_nr, entry->pirq == XEN_PT_UNASSIGNED_PIRQ); if (rc) { return rc; @@ -427,7 +427,7 @@ static void set_entry_value(XenPTMSIXEntry *e, int offset, uint32_t val) } } -static void pci_msix_write(void *opaque, target_phys_addr_t addr, +static void pci_msix_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { XenPCIPassthroughState *s = opaque; @@ -475,7 +475,7 @@ static void pci_msix_write(void *opaque, target_phys_addr_t addr, } } -static uint64_t pci_msix_read(void *opaque, target_phys_addr_t addr, +static uint64_t pci_msix_read(void *opaque, hwaddr addr, unsigned size) { XenPCIPassthroughState *s = opaque; diff --git a/hw/xenfb.c b/hw/xenfb.c index 338800a4d9..903efd3073 100644 --- a/hw/xenfb.c +++ b/hw/xenfb.c @@ -36,8 +36,8 @@ #include <time.h> #include "hw.h" -#include "console.h" -#include "qemu-char.h" +#include "ui/console.h" +#include "char/char.h" #include "xen_backend.h" #include <xen/event_channel.h> @@ -648,7 +648,7 @@ static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h) xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n", __FUNCTION__, xenfb->depth, bpp); - dpy_update(xenfb->c.ds, x, y, w, h); + dpy_gfx_update(xenfb->c.ds, x, y, w, h); } #ifdef XENFB_TYPE_REFRESH_PERIOD @@ -717,7 +717,7 @@ static void xenfb_update(void *opaque) if (xenfb_queue_full(xenfb)) return; - for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) { + QLIST_FOREACH(l, &xenfb->c.ds->listeners, next) { if (l->idle) continue; idle = 0; @@ -766,7 +766,7 @@ static void xenfb_update(void *opaque) xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n", xenfb->width, xenfb->height, xenfb->depth, is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : ""); - dpy_resize(xenfb->c.ds); + dpy_gfx_resize(xenfb->c.ds); xenfb->up_fullscreen = 1; } diff --git a/hw/xgmac.c b/hw/xgmac.c index a91ef608f1..9639b6141b 100644 --- a/hw/xgmac.c +++ b/hw/xgmac.c @@ -25,9 +25,9 @@ */ #include "sysbus.h" -#include "qemu-char.h" -#include "qemu-log.h" -#include "net.h" +#include "char/char.h" +#include "qemu/log.h" +#include "net/net.h" #include "net/checksum.h" #ifdef DEBUG_XGMAC @@ -252,7 +252,7 @@ static void enet_update_irq(struct XgmacState *s) qemu_set_irq(s->sbd_irq, !!stat); } -static uint64_t enet_read(void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size) { struct XgmacState *s = opaque; uint64_t r = 0; @@ -271,7 +271,7 @@ static uint64_t enet_read(void *opaque, target_phys_addr_t addr, unsigned size) return r; } -static void enet_write(void *opaque, target_phys_addr_t addr, +static void enet_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct XgmacState *s = opaque; @@ -26,6 +26,7 @@ */ #include "hw.h" +#include "trace.h" #include "hw/spapr.h" #include "hw/xics.h" @@ -66,6 +67,8 @@ static void icp_check_ipi(struct icp_state *icp, int server) return; } + trace_xics_icp_check_ipi(server, ss->mfrr); + if (XISR(ss)) { ics_reject(icp->ics, XISR(ss)); } @@ -108,23 +111,25 @@ static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr) } } -static void icp_set_mfrr(struct icp_state *icp, int nr, uint8_t mfrr) +static void icp_set_mfrr(struct icp_state *icp, int server, uint8_t mfrr) { - struct icp_server_state *ss = icp->ss + nr; + struct icp_server_state *ss = icp->ss + server; ss->mfrr = mfrr; if (mfrr < CPPR(ss)) { - icp_check_ipi(icp, nr); + icp_check_ipi(icp, server); } } static uint32_t icp_accept(struct icp_server_state *ss) { - uint32_t xirr; + uint32_t xirr = ss->xirr; qemu_irq_lower(ss->output); - xirr = ss->xirr; ss->xirr = ss->pending_priority << 24; + + trace_xics_icp_accept(xirr, ss->xirr); + return xirr; } @@ -134,6 +139,7 @@ static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr) /* Send EOI -> ICS */ ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); + trace_xics_icp_eoi(server, xirr, ss->xirr); ics_eoi(icp->ics, xirr & XISR_MASK); if (!XISR(ss)) { icp_resend(icp, server); @@ -144,6 +150,8 @@ static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority) { struct icp_server_state *ss = icp->ss + server; + trace_xics_icp_irq(server, nr, priority); + if ((priority >= CPPR(ss)) || (XISR(ss) && (ss->pending_priority <= priority))) { ics_reject(icp->ics, nr); @@ -153,6 +161,7 @@ static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority) } ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK); ss->pending_priority = priority; + trace_xics_icp_raise(ss->xirr, ss->pending_priority); qemu_irq_raise(ss->output); } } @@ -165,17 +174,18 @@ struct ics_irq_state { int server; uint8_t priority; uint8_t saved_priority; - enum xics_irq_type type; - int asserted:1; - int sent:1; - int rejected:1; - int masked_pending:1; +#define XICS_STATUS_ASSERTED 0x1 +#define XICS_STATUS_SENT 0x2 +#define XICS_STATUS_REJECTED 0x4 +#define XICS_STATUS_MASKED_PENDING 0x8 + uint8_t status; }; struct ics_state { int nr_irqs; int offset; qemu_irq *qirqs; + bool *islsi; struct ics_irq_state *irqs; struct icp_state *icp; }; @@ -191,8 +201,8 @@ static void resend_msi(struct ics_state *ics, int srcno) struct ics_irq_state *irq = ics->irqs + srcno; /* FIXME: filter by server#? */ - if (irq->rejected) { - irq->rejected = 0; + if (irq->status & XICS_STATUS_REJECTED) { + irq->status &= ~XICS_STATUS_REJECTED; if (irq->priority != 0xff) { icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); @@ -204,8 +214,10 @@ static void resend_lsi(struct ics_state *ics, int srcno) { struct ics_irq_state *irq = ics->irqs + srcno; - if ((irq->priority != 0xff) && irq->asserted && !irq->sent) { - irq->sent = 1; + if ((irq->priority != 0xff) + && (irq->status & XICS_STATUS_ASSERTED) + && !(irq->status & XICS_STATUS_SENT)) { + irq->status |= XICS_STATUS_SENT; icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); } } @@ -214,10 +226,12 @@ static void set_irq_msi(struct ics_state *ics, int srcno, int val) { struct ics_irq_state *irq = ics->irqs + srcno; + trace_xics_set_irq_msi(srcno, srcno + ics->offset); + if (val) { if (irq->priority == 0xff) { - irq->masked_pending = 1; - /* masked pending */ ; + irq->status |= XICS_STATUS_MASKED_PENDING; + trace_xics_masked_pending(); } else { icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); } @@ -228,16 +242,20 @@ static void set_irq_lsi(struct ics_state *ics, int srcno, int val) { struct ics_irq_state *irq = ics->irqs + srcno; - irq->asserted = val; + trace_xics_set_irq_lsi(srcno, srcno + ics->offset); + if (val) { + irq->status |= XICS_STATUS_ASSERTED; + } else { + irq->status &= ~XICS_STATUS_ASSERTED; + } resend_lsi(ics, srcno); } static void ics_set_irq(void *opaque, int srcno, int val) { struct ics_state *ics = (struct ics_state *)opaque; - struct ics_irq_state *irq = ics->irqs + srcno; - if (irq->type == XICS_LSI) { + if (ics->islsi[srcno]) { set_irq_lsi(ics, srcno, val); } else { set_irq_msi(ics, srcno, val); @@ -248,11 +266,12 @@ static void write_xive_msi(struct ics_state *ics, int srcno) { struct ics_irq_state *irq = ics->irqs + srcno; - if (!irq->masked_pending || (irq->priority == 0xff)) { + if (!(irq->status & XICS_STATUS_MASKED_PENDING) + || (irq->priority == 0xff)) { return; } - irq->masked_pending = 0; + irq->status &= ~XICS_STATUS_MASKED_PENDING; icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); } @@ -262,15 +281,18 @@ static void write_xive_lsi(struct ics_state *ics, int srcno) } static void ics_write_xive(struct ics_state *ics, int nr, int server, - uint8_t priority) + uint8_t priority, uint8_t saved_priority) { int srcno = nr - ics->offset; struct ics_irq_state *irq = ics->irqs + srcno; irq->server = server; irq->priority = priority; + irq->saved_priority = saved_priority; - if (irq->type == XICS_LSI) { + trace_xics_ics_write_xive(nr, srcno, server, priority); + + if (ics->islsi[srcno]) { write_xive_lsi(ics, srcno); } else { write_xive_msi(ics, srcno); @@ -281,8 +303,9 @@ static void ics_reject(struct ics_state *ics, int nr) { struct ics_irq_state *irq = ics->irqs + nr - ics->offset; - irq->rejected = 1; /* Irrelevant but harmless for LSI */ - irq->sent = 0; /* Irrelevant but harmless for MSI */ + trace_xics_ics_reject(nr, nr - ics->offset); + irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */ + irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */ } static void ics_resend(struct ics_state *ics) @@ -290,10 +313,8 @@ static void ics_resend(struct ics_state *ics) int i; for (i = 0; i < ics->nr_irqs; i++) { - struct ics_irq_state *irq = ics->irqs + i; - /* FIXME: filter by server#? */ - if (irq->type == XICS_LSI) { + if (ics->islsi[i]) { resend_lsi(ics, i); } else { resend_msi(ics, i); @@ -306,8 +327,10 @@ static void ics_eoi(struct ics_state *ics, int nr) int srcno = nr - ics->offset; struct ics_irq_state *irq = ics->irqs + srcno; - if (irq->type == XICS_LSI) { - irq->sent = 0; + trace_xics_ics_eoi(nr); + + if (ics->islsi[srcno]) { + irq->status &= ~XICS_STATUS_SENT; } } @@ -315,30 +338,33 @@ static void ics_eoi(struct ics_state *ics, int nr) * Exported functions */ -qemu_irq xics_assign_irq(struct icp_state *icp, int irq, - enum xics_irq_type type) +qemu_irq xics_get_qirq(struct icp_state *icp, int irq) { - if ((irq < icp->ics->offset) - || (irq >= (icp->ics->offset + icp->ics->nr_irqs))) { + if (!ics_valid_irq(icp->ics, irq)) { return NULL; } - assert((type == XICS_MSI) || (type == XICS_LSI)); - - icp->ics->irqs[irq - icp->ics->offset].type = type; return icp->ics->qirqs[irq - icp->ics->offset]; } -static target_ulong h_cppr(CPUPPCState *env, sPAPREnvironment *spapr, +void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi) +{ + assert(ics_valid_irq(icp->ics, irq)); + + icp->ics->islsi[irq - icp->ics->offset] = lsi; +} + +static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { + CPUPPCState *env = &cpu->env; target_ulong cppr = args[0]; icp_set_cppr(spapr->icp, env->cpu_index, cppr); return H_SUCCESS; } -static target_ulong h_ipi(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong server = args[0]; @@ -353,18 +379,20 @@ static target_ulong h_ipi(CPUPPCState *env, sPAPREnvironment *spapr, } -static target_ulong h_xirr(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { + CPUPPCState *env = &cpu->env; uint32_t xirr = icp_accept(spapr->icp->ss + env->cpu_index); args[0] = xirr; return H_SUCCESS; } -static target_ulong h_eoi(CPUPPCState *env, sPAPREnvironment *spapr, +static target_ulong h_eoi(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { + CPUPPCState *env = &cpu->env; target_ulong xirr = args[0]; icp_eoi(spapr->icp, env->cpu_index, xirr); @@ -393,7 +421,7 @@ static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token, return; } - ics_write_xive(ics, nr, server, priority); + ics_write_xive(ics, nr, server, priority, priority); rtas_st(rets, 0, 0); /* Success */ } @@ -441,14 +469,8 @@ static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token, return; } - /* This is a NOP for now, since the described PAPR semantics don't - * seem to gel with what Linux does */ -#if 0 - struct ics_irq_state *irq = xics->irqs + (nr - xics->offset); - - irq->saved_priority = irq->priority; - ics_write_xive_msi(xics, nr, irq->server, 0xff); -#endif + ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff, + ics->irqs[nr - ics->offset].priority); rtas_st(rets, 0, 0); /* Success */ } @@ -472,22 +494,38 @@ static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token, return; } - /* This is a NOP for now, since the described PAPR semantics don't - * seem to gel with what Linux does */ -#if 0 - struct ics_irq_state *irq = xics->irqs + (nr - xics->offset); - - ics_write_xive_msi(xics, nr, irq->server, irq->saved_priority); -#endif + ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, + ics->irqs[nr - ics->offset].saved_priority, + ics->irqs[nr - ics->offset].saved_priority); rtas_st(rets, 0, 0); /* Success */ } +static void xics_reset(void *opaque) +{ + struct icp_state *icp = (struct icp_state *)opaque; + struct ics_state *ics = icp->ics; + int i; + + for (i = 0; i < icp->nr_servers; i++) { + icp->ss[i].xirr = 0; + icp->ss[i].pending_priority = 0xff; + icp->ss[i].mfrr = 0xff; + /* Make all outputs are deasserted */ + qemu_set_irq(icp->ss[i].output, 0); + } + + memset(ics->irqs, 0, sizeof(struct ics_irq_state) * ics->nr_irqs); + for (i = 0; i < ics->nr_irqs; i++) { + ics->irqs[i].priority = 0xff; + ics->irqs[i].saved_priority = 0xff; + } +} + struct icp_state *xics_system_init(int nr_irqs) { CPUPPCState *env; int max_server_num; - int i; struct icp_state *icp; struct ics_state *ics; @@ -502,10 +540,6 @@ struct icp_state *xics_system_init(int nr_irqs) icp->nr_servers = max_server_num + 1; icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state)); - for (i = 0; i < icp->nr_servers; i++) { - icp->ss[i].mfrr = 0xff; - } - for (env = first_cpu; env != NULL; env = env->next_cpu) { struct icp_server_state *ss = &icp->ss[env->cpu_index]; @@ -527,17 +561,13 @@ struct icp_state *xics_system_init(int nr_irqs) ics = g_malloc0(sizeof(*ics)); ics->nr_irqs = nr_irqs; - ics->offset = 16; + ics->offset = XICS_IRQ_BASE; ics->irqs = g_malloc0(nr_irqs * sizeof(struct ics_irq_state)); + ics->islsi = g_malloc0(nr_irqs * sizeof(bool)); icp->ics = ics; ics->icp = icp; - for (i = 0; i < nr_irqs; i++) { - ics->irqs[i].priority = 0xff; - ics->irqs[i].saved_priority = 0xff; - } - ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, nr_irqs); spapr_register_hypercall(H_CPPR, h_cppr); @@ -550,5 +580,7 @@ struct icp_state *xics_system_init(int nr_irqs) spapr_rtas_register("ibm,int-off", rtas_int_off); spapr_rtas_register("ibm,int-on", rtas_int_on); + qemu_register_reset(xics_reset, icp); + return icp; } @@ -28,16 +28,12 @@ #define __XICS_H__ #define XICS_IPI 0x2 +#define XICS_IRQ_BASE 0x10 struct icp_state; -enum xics_irq_type { - XICS_MSI, /* Message-signalled (edge) interrupt */ - XICS_LSI, /* Level-signalled interrupt */ -}; - -qemu_irq xics_assign_irq(struct icp_state *icp, int irq, - enum xics_irq_type type); +qemu_irq xics_get_qirq(struct icp_state *icp, int irq); +void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi); struct icp_state *xics_system_init(int nr_irqs); diff --git a/hw/xilinx.h b/hw/xilinx.h index 556c5aa9f1..a12eccbe3c 100644 --- a/hw/xilinx.h +++ b/hw/xilinx.h @@ -1,9 +1,13 @@ +#ifndef HW_XILINX_H +#define HW_XILINX_H 1 + + #include "stream.h" #include "qemu-common.h" -#include "net.h" +#include "net/net.h" static inline DeviceState * -xilinx_intc_create(target_phys_addr_t base, qemu_irq irq, int kind_of_intr) +xilinx_intc_create(hwaddr base, qemu_irq irq, int kind_of_intr) { DeviceState *dev; @@ -17,13 +21,13 @@ xilinx_intc_create(target_phys_addr_t base, qemu_irq irq, int kind_of_intr) /* OPB Timer/Counter. */ static inline DeviceState * -xilinx_timer_create(target_phys_addr_t base, qemu_irq irq, int oto, int freq) +xilinx_timer_create(hwaddr base, qemu_irq irq, int oto, int freq) { DeviceState *dev; - dev = qdev_create(NULL, "xlnx,xps-timer"); + dev = qdev_create(NULL, "xlnx.xps-timer"); qdev_prop_set_uint32(dev, "one-timer-only", oto); - qdev_prop_set_uint32(dev, "frequency", freq); + qdev_prop_set_uint32(dev, "clock-frequency", freq); qdev_init_nofail(dev); sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); @@ -32,7 +36,7 @@ xilinx_timer_create(target_phys_addr_t base, qemu_irq irq, int oto, int freq) /* XPS Ethernet Lite MAC. */ static inline DeviceState * -xilinx_ethlite_create(NICInfo *nd, target_phys_addr_t base, qemu_irq irq, +xilinx_ethlite_create(NICInfo *nd, hwaddr base, qemu_irq irq, int txpingpong, int rxpingpong) { DeviceState *dev; @@ -51,17 +55,21 @@ xilinx_ethlite_create(NICInfo *nd, target_phys_addr_t base, qemu_irq irq, static inline DeviceState * xilinx_axiethernet_create(NICInfo *nd, StreamSlave *peer, - target_phys_addr_t base, qemu_irq irq, + hwaddr base, qemu_irq irq, int txmem, int rxmem) { DeviceState *dev; + Error *errp = NULL; + qemu_check_nic_model(nd, "xlnx.axi-ethernet"); dev = qdev_create(NULL, "xlnx.axi-ethernet"); qdev_set_nic_properties(dev, nd); qdev_prop_set_uint32(dev, "rxmem", rxmem); qdev_prop_set_uint32(dev, "txmem", txmem); - object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL); + object_property_set_link(OBJECT(dev), OBJECT(peer), "axistream-connected", + &errp); + assert_no_error(errp); qdev_init_nofail(dev); sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); @@ -71,14 +79,20 @@ xilinx_axiethernet_create(NICInfo *nd, StreamSlave *peer, static inline void xilinx_axiethernetdma_init(DeviceState *dev, StreamSlave *peer, - target_phys_addr_t base, qemu_irq irq, + hwaddr base, qemu_irq irq, qemu_irq irq2, int freqhz) { + Error *errp = NULL; + qdev_prop_set_uint32(dev, "freqhz", freqhz); - object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL); + object_property_set_link(OBJECT(dev), OBJECT(peer), "axistream-connected", + &errp); + assert_no_error(errp); qdev_init_nofail(dev); sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); sysbus_connect_irq(sysbus_from_qdev(dev), 1, irq2); } + +#endif diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c index 0e28c51738..ce02764b3f 100644 --- a/hw/xilinx_axidma.c +++ b/hw/xilinx_axidma.c @@ -23,10 +23,9 @@ */ #include "sysbus.h" -#include "qemu-char.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "ptimer.h" -#include "qemu-log.h" +#include "qemu/log.h" #include "qdev-addr.h" #include "stream.h" @@ -140,7 +139,7 @@ static void stream_reset(struct Stream *s) } /* Map an offset addr into a channel index. */ -static inline int streamid_from_addr(target_phys_addr_t addr) +static inline int streamid_from_addr(hwaddr addr) { int sid; @@ -159,7 +158,7 @@ static void stream_desc_show(struct SDesc *d) } #endif -static void stream_desc_load(struct Stream *s, target_phys_addr_t addr) +static void stream_desc_load(struct Stream *s, hwaddr addr) { struct SDesc *d = &s->desc; int i; @@ -176,7 +175,7 @@ static void stream_desc_load(struct Stream *s, target_phys_addr_t addr) } } -static void stream_desc_store(struct Stream *s, target_phys_addr_t addr) +static void stream_desc_store(struct Stream *s, hwaddr addr) { struct SDesc *d = &s->desc; int i; @@ -364,7 +363,7 @@ axidma_push(StreamSlave *obj, unsigned char *buf, size_t len, uint32_t *app) stream_update_irq(s); } -static uint64_t axidma_read(void *opaque, target_phys_addr_t addr, +static uint64_t axidma_read(void *opaque, hwaddr addr, unsigned size) { struct XilinxAXIDMA *d = opaque; @@ -399,7 +398,7 @@ static uint64_t axidma_read(void *opaque, target_phys_addr_t addr, } -static void axidma_write(void *opaque, target_phys_addr_t addr, +static void axidma_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct XilinxAXIDMA *d = opaque; diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c index eec155d440..09e49b0aee 100644 --- a/hw/xilinx_axienet.c +++ b/hw/xilinx_axienet.c @@ -23,9 +23,8 @@ */ #include "sysbus.h" -#include "qemu-char.h" -#include "qemu-log.h" -#include "net.h" +#include "qemu/log.h" +#include "net/net.h" #include "net/checksum.h" #include "stream.h" @@ -412,7 +411,7 @@ static void enet_update_irq(struct XilinxAXIEnet *s) qemu_set_irq(s->irq, !!s->regs[R_IP]); } -static uint64_t enet_read(void *opaque, target_phys_addr_t addr, unsigned size) +static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size) { struct XilinxAXIEnet *s = opaque; uint32_t r = 0; @@ -503,7 +502,7 @@ static uint64_t enet_read(void *opaque, target_phys_addr_t addr, unsigned size) return r; } -static void enet_write(void *opaque, target_phys_addr_t addr, +static void enet_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { struct XilinxAXIEnet *s = opaque; @@ -591,6 +590,10 @@ static void enet_write(void *opaque, target_phys_addr_t addr, s->maddr[s->fmi & 3][addr & 1] = value; break; + case R_IS: + s->regs[addr] &= ~value; + break; + case 0x8000 ... 0x83ff: s->ext_mtable[addr - 0x8000] = value; break; diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index 56ca620dd7..4de4a53a0b 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -24,7 +24,7 @@ #include "sysbus.h" #include "hw.h" -#include "net.h" +#include "net/net.h" #define D(x) #define R_TX_BUF0 0 @@ -72,7 +72,7 @@ static inline void eth_pulse_irq(struct xlx_ethlite *s) } static uint64_t -eth_read(void *opaque, target_phys_addr_t addr, unsigned int size) +eth_read(void *opaque, hwaddr addr, unsigned int size) { struct xlx_ethlite *s = opaque; uint32_t r = 0; @@ -100,7 +100,7 @@ eth_read(void *opaque, target_phys_addr_t addr, unsigned int size) } static void -eth_write(void *opaque, target_phys_addr_t addr, +eth_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { struct xlx_ethlite *s = opaque; diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c index 386fd30743..7765079802 100644 --- a/hw/xilinx_intc.c +++ b/hw/xilinx_intc.c @@ -74,7 +74,7 @@ static void update_irq(struct xlx_pic *p) } static uint64_t -pic_read(void *opaque, target_phys_addr_t addr, unsigned int size) +pic_read(void *opaque, hwaddr addr, unsigned int size) { struct xlx_pic *p = opaque; uint32_t r = 0; @@ -93,7 +93,7 @@ pic_read(void *opaque, target_phys_addr_t addr, unsigned int size) } static void -pic_write(void *opaque, target_phys_addr_t addr, +pic_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { struct xlx_pic *p = opaque; diff --git a/hw/xilinx_spi.c b/hw/xilinx_spi.c new file mode 100644 index 0000000000..77f9178008 --- /dev/null +++ b/hw/xilinx_spi.c @@ -0,0 +1,385 @@ +/* + * QEMU model of the Xilinx SPI Controller + * + * Copyright (C) 2010 Edgar E. Iglesias. + * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com> + * Copyright (C) 2012 PetaLogix + * + * 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. + */ + +#include "sysbus.h" +#include "sysemu/sysemu.h" +#include "qemu/log.h" +#include "fifo.h" + +#include "ssi.h" + +#ifdef XILINX_SPI_ERR_DEBUG +#define DB_PRINT(...) do { \ + fprintf(stderr, ": %s: ", __func__); \ + fprintf(stderr, ## __VA_ARGS__); \ + } while (0); +#else + #define DB_PRINT(...) +#endif + +#define R_DGIER (0x1c / 4) +#define R_DGIER_IE (1 << 31) + +#define R_IPISR (0x20 / 4) +#define IRQ_DRR_NOT_EMPTY (1 << (31 - 23)) +#define IRQ_DRR_OVERRUN (1 << (31 - 26)) +#define IRQ_DRR_FULL (1 << (31 - 27)) +#define IRQ_TX_FF_HALF_EMPTY (1 << 6) +#define IRQ_DTR_UNDERRUN (1 << 3) +#define IRQ_DTR_EMPTY (1 << (31 - 29)) + +#define R_IPIER (0x28 / 4) +#define R_SRR (0x40 / 4) +#define R_SPICR (0x60 / 4) +#define R_SPICR_TXFF_RST (1 << 5) +#define R_SPICR_RXFF_RST (1 << 6) +#define R_SPICR_MTI (1 << 8) + +#define R_SPISR (0x64 / 4) +#define SR_TX_FULL (1 << 3) +#define SR_TX_EMPTY (1 << 2) +#define SR_RX_FULL (1 << 1) +#define SR_RX_EMPTY (1 << 0) + +#define R_SPIDTR (0x68 / 4) +#define R_SPIDRR (0x6C / 4) +#define R_SPISSR (0x70 / 4) +#define R_TX_FF_OCY (0x74 / 4) +#define R_RX_FF_OCY (0x78 / 4) +#define R_MAX (0x7C / 4) + +#define FIFO_CAPACITY 256 + +typedef struct XilinxSPI { + SysBusDevice busdev; + MemoryRegion mmio; + + qemu_irq irq; + int irqline; + + uint8_t num_cs; + qemu_irq *cs_lines; + + SSIBus *spi; + + Fifo8 rx_fifo; + Fifo8 tx_fifo; + + uint32_t regs[R_MAX]; +} XilinxSPI; + +static void txfifo_reset(XilinxSPI *s) +{ + fifo8_reset(&s->tx_fifo); + + s->regs[R_SPISR] &= ~SR_TX_FULL; + s->regs[R_SPISR] |= SR_TX_EMPTY; +} + +static void rxfifo_reset(XilinxSPI *s) +{ + fifo8_reset(&s->rx_fifo); + + s->regs[R_SPISR] |= SR_RX_EMPTY; + s->regs[R_SPISR] &= ~SR_RX_FULL; +} + +static void xlx_spi_update_cs(XilinxSPI *s) +{ + int i; + + for (i = 0; i < s->num_cs; ++i) { + qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i)); + } +} + +static void xlx_spi_update_irq(XilinxSPI *s) +{ + uint32_t pending; + + s->regs[R_IPISR] |= + (!fifo8_is_empty(&s->rx_fifo) ? IRQ_DRR_NOT_EMPTY : 0) | + (fifo8_is_full(&s->rx_fifo) ? IRQ_DRR_FULL : 0); + + pending = s->regs[R_IPISR] & s->regs[R_IPIER]; + + pending = pending && (s->regs[R_DGIER] & R_DGIER_IE); + pending = !!pending; + + /* This call lies right in the data paths so don't call the + irq chain unless things really changed. */ + if (pending != s->irqline) { + s->irqline = pending; + DB_PRINT("irq_change of state %d ISR:%x IER:%X\n", + pending, s->regs[R_IPISR], s->regs[R_IPIER]); + qemu_set_irq(s->irq, pending); + } + +} + +static void xlx_spi_do_reset(XilinxSPI *s) +{ + memset(s->regs, 0, sizeof s->regs); + + rxfifo_reset(s); + txfifo_reset(s); + + s->regs[R_SPISSR] = ~0; + xlx_spi_update_irq(s); + xlx_spi_update_cs(s); +} + +static void xlx_spi_reset(DeviceState *d) +{ + xlx_spi_do_reset(DO_UPCAST(XilinxSPI, busdev.qdev, d)); +} + +static inline int spi_master_enabled(XilinxSPI *s) +{ + return !(s->regs[R_SPICR] & R_SPICR_MTI); +} + +static void spi_flush_txfifo(XilinxSPI *s) +{ + uint32_t tx; + uint32_t rx; + + while (!fifo8_is_empty(&s->tx_fifo)) { + tx = (uint32_t)fifo8_pop(&s->tx_fifo); + DB_PRINT("data tx:%x\n", tx); + rx = ssi_transfer(s->spi, tx); + DB_PRINT("data rx:%x\n", rx); + if (fifo8_is_full(&s->rx_fifo)) { + s->regs[R_IPISR] |= IRQ_DRR_OVERRUN; + } else { + fifo8_push(&s->rx_fifo, (uint8_t)rx); + if (fifo8_is_full(&s->rx_fifo)) { + s->regs[R_SPISR] |= SR_RX_FULL; + s->regs[R_IPISR] |= IRQ_DRR_FULL; + } + } + + s->regs[R_SPISR] &= ~SR_RX_EMPTY; + s->regs[R_SPISR] &= ~SR_TX_FULL; + s->regs[R_SPISR] |= SR_TX_EMPTY; + + s->regs[R_IPISR] |= IRQ_DTR_EMPTY; + s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY; + } + +} + +static uint64_t +spi_read(void *opaque, hwaddr addr, unsigned int size) +{ + XilinxSPI *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) { + case R_SPIDRR: + if (fifo8_is_empty(&s->rx_fifo)) { + DB_PRINT("Read from empty FIFO!\n"); + return 0xdeadbeef; + } + + s->regs[R_SPISR] &= ~SR_RX_FULL; + r = fifo8_pop(&s->rx_fifo); + if (fifo8_is_empty(&s->rx_fifo)) { + s->regs[R_SPISR] |= SR_RX_EMPTY; + } + break; + + case R_SPISR: + r = s->regs[addr]; + break; + + default: + if (addr < ARRAY_SIZE(s->regs)) { + r = s->regs[addr]; + } + break; + + } + DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, r); + xlx_spi_update_irq(s); + return r; +} + +static void +spi_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + XilinxSPI *s = opaque; + uint32_t value = val64; + + DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, value); + addr >>= 2; + switch (addr) { + case R_SRR: + if (value != 0xa) { + DB_PRINT("Invalid write to SRR %x\n", value); + } else { + xlx_spi_do_reset(s); + } + break; + + case R_SPIDTR: + s->regs[R_SPISR] &= ~SR_TX_EMPTY; + fifo8_push(&s->tx_fifo, (uint8_t)value); + if (fifo8_is_full(&s->tx_fifo)) { + s->regs[R_SPISR] |= SR_TX_FULL; + } + if (!spi_master_enabled(s)) { + goto done; + } else { + DB_PRINT("DTR and master enabled\n"); + } + spi_flush_txfifo(s); + break; + + case R_SPISR: + DB_PRINT("Invalid write to SPISR %x\n", value); + break; + + case R_IPISR: + /* Toggle the bits. */ + s->regs[addr] ^= value; + break; + + /* Slave Select Register. */ + case R_SPISSR: + s->regs[addr] = value; + xlx_spi_update_cs(s); + break; + + case R_SPICR: + /* FIXME: reset irq and sr state to empty queues. */ + if (value & R_SPICR_RXFF_RST) { + rxfifo_reset(s); + } + + if (value & R_SPICR_TXFF_RST) { + txfifo_reset(s); + } + value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST); + s->regs[addr] = value; + + if (!(value & R_SPICR_MTI)) { + spi_flush_txfifo(s); + } + break; + + default: + if (addr < ARRAY_SIZE(s->regs)) { + s->regs[addr] = value; + } + break; + } + +done: + xlx_spi_update_irq(s); +} + +static const MemoryRegionOps spi_ops = { + .read = spi_read, + .write = spi_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static int xilinx_spi_init(SysBusDevice *dev) +{ + int i; + XilinxSPI *s = FROM_SYSBUS(typeof(*s), dev); + + DB_PRINT("\n"); + + s->spi = ssi_create_bus(&dev->qdev, "spi"); + + sysbus_init_irq(dev, &s->irq); + s->cs_lines = g_new(qemu_irq, s->num_cs); + ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi); + for (i = 0; i < s->num_cs; ++i) { + sysbus_init_irq(dev, &s->cs_lines[i]); + } + + memory_region_init_io(&s->mmio, &spi_ops, s, "xilinx-spi", R_MAX * 4); + sysbus_init_mmio(dev, &s->mmio); + + s->irqline = -1; + + fifo8_create(&s->tx_fifo, FIFO_CAPACITY); + fifo8_create(&s->rx_fifo, FIFO_CAPACITY); + + return 0; +} + +static const VMStateDescription vmstate_xilinx_spi = { + .name = "xilinx_spi", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_FIFO8(tx_fifo, XilinxSPI), + VMSTATE_FIFO8(rx_fifo, XilinxSPI), + VMSTATE_UINT32_ARRAY(regs, XilinxSPI, R_MAX), + VMSTATE_END_OF_LIST() + } +}; + +static Property xilinx_spi_properties[] = { + DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xilinx_spi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = xilinx_spi_init; + dc->reset = xlx_spi_reset; + dc->props = xilinx_spi_properties; + dc->vmsd = &vmstate_xilinx_spi; +} + +static TypeInfo xilinx_spi_info = { + .name = "xlnx.xps-spi", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(XilinxSPI), + .class_init = xilinx_spi_class_init, +}; + +static void xilinx_spi_register_types(void) +{ + type_register_static(&xilinx_spi_info); +} + +type_init(xilinx_spi_register_types) diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c new file mode 100644 index 0000000000..42e019dc05 --- /dev/null +++ b/hw/xilinx_spips.c @@ -0,0 +1,575 @@ +/* + * QEMU model of the Xilinx Zynq SPI controller + * + * Copyright (c) 2012 Peter A. G. Crosthwaite + * + * 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. + */ + +#include "sysbus.h" +#include "sysemu/sysemu.h" +#include "ptimer.h" +#include "qemu/log.h" +#include "fifo.h" +#include "ssi.h" +#include "qemu/bitops.h" + +#ifdef XILINX_SPIPS_ERR_DEBUG +#define DB_PRINT(...) do { \ + fprintf(stderr, ": %s: ", __func__); \ + fprintf(stderr, ## __VA_ARGS__); \ + } while (0); +#else + #define DB_PRINT(...) +#endif + +/* config register */ +#define R_CONFIG (0x00 / 4) +#define IFMODE (1 << 31) +#define ENDIAN (1 << 26) +#define MODEFAIL_GEN_EN (1 << 17) +#define MAN_START_COM (1 << 16) +#define MAN_START_EN (1 << 15) +#define MANUAL_CS (1 << 14) +#define CS (0xF << 10) +#define CS_SHIFT (10) +#define PERI_SEL (1 << 9) +#define REF_CLK (1 << 8) +#define FIFO_WIDTH (3 << 6) +#define BAUD_RATE_DIV (7 << 3) +#define CLK_PH (1 << 2) +#define CLK_POL (1 << 1) +#define MODE_SEL (1 << 0) + +/* interrupt mechanism */ +#define R_INTR_STATUS (0x04 / 4) +#define R_INTR_EN (0x08 / 4) +#define R_INTR_DIS (0x0C / 4) +#define R_INTR_MASK (0x10 / 4) +#define IXR_TX_FIFO_UNDERFLOW (1 << 6) +#define IXR_RX_FIFO_FULL (1 << 5) +#define IXR_RX_FIFO_NOT_EMPTY (1 << 4) +#define IXR_TX_FIFO_FULL (1 << 3) +#define IXR_TX_FIFO_NOT_FULL (1 << 2) +#define IXR_TX_FIFO_MODE_FAIL (1 << 1) +#define IXR_RX_FIFO_OVERFLOW (1 << 0) +#define IXR_ALL ((IXR_TX_FIFO_UNDERFLOW<<1)-1) + +#define R_EN (0x14 / 4) +#define R_DELAY (0x18 / 4) +#define R_TX_DATA (0x1C / 4) +#define R_RX_DATA (0x20 / 4) +#define R_SLAVE_IDLE_COUNT (0x24 / 4) +#define R_TX_THRES (0x28 / 4) +#define R_RX_THRES (0x2C / 4) +#define R_TXD1 (0x80 / 4) +#define R_TXD2 (0x84 / 4) +#define R_TXD3 (0x88 / 4) + +#define R_LQSPI_CFG (0xa0 / 4) +#define R_LQSPI_CFG_RESET 0x03A002EB +#define LQSPI_CFG_LQ_MODE (1 << 31) +#define LQSPI_CFG_TWO_MEM (1 << 30) +#define LQSPI_CFG_SEP_BUS (1 << 30) +#define LQSPI_CFG_U_PAGE (1 << 28) +#define LQSPI_CFG_MODE_EN (1 << 25) +#define LQSPI_CFG_MODE_WIDTH 8 +#define LQSPI_CFG_MODE_SHIFT 16 +#define LQSPI_CFG_DUMMY_WIDTH 3 +#define LQSPI_CFG_DUMMY_SHIFT 8 +#define LQSPI_CFG_INST_CODE 0xFF + +#define R_LQSPI_STS (0xA4 / 4) +#define LQSPI_STS_WR_RECVD (1 << 1) + +#define R_MOD_ID (0xFC / 4) + +#define R_MAX (R_MOD_ID+1) + +/* size of TXRX FIFOs */ +#define RXFF_A 32 +#define TXFF_A 32 + +/* 16MB per linear region */ +#define LQSPI_ADDRESS_BITS 24 +/* Bite off 4k chunks at a time */ +#define LQSPI_CACHE_SIZE 1024 + +#define SNOOP_CHECKING 0xFF +#define SNOOP_NONE 0xFE +#define SNOOP_STRIPING 0 + +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + MemoryRegion mmlqspi; + + qemu_irq irq; + int irqline; + + uint8_t num_cs; + uint8_t num_busses; + + uint8_t snoop_state; + qemu_irq *cs_lines; + SSIBus **spi; + + Fifo8 rx_fifo; + Fifo8 tx_fifo; + + uint8_t num_txrx_bytes; + + uint32_t regs[R_MAX]; + + uint32_t lqspi_buf[LQSPI_CACHE_SIZE]; + hwaddr lqspi_cached_addr; +} XilinxSPIPS; + +static inline int num_effective_busses(XilinxSPIPS *s) +{ + return (s->regs[R_LQSPI_STS] & LQSPI_CFG_SEP_BUS && + s->regs[R_LQSPI_STS] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1; +} + +static void xilinx_spips_update_cs_lines(XilinxSPIPS *s) +{ + int i, j; + bool found = false; + int field = s->regs[R_CONFIG] >> CS_SHIFT; + + for (i = 0; i < s->num_cs; i++) { + for (j = 0; j < num_effective_busses(s); j++) { + int upage = !!(s->regs[R_LQSPI_STS] & LQSPI_CFG_U_PAGE); + int cs_to_set = (j * s->num_cs + i + upage) % + (s->num_cs * s->num_busses); + + if (~field & (1 << i) && !found) { + DB_PRINT("selecting slave %d\n", i); + qemu_set_irq(s->cs_lines[cs_to_set], 0); + } else { + qemu_set_irq(s->cs_lines[cs_to_set], 1); + } + } + if (~field & (1 << i)) { + found = true; + } + } + if (!found) { + s->snoop_state = SNOOP_CHECKING; + } +} + +static void xilinx_spips_update_ixr(XilinxSPIPS *s) +{ + /* These are set/cleared as they occur */ + s->regs[R_INTR_STATUS] &= (IXR_TX_FIFO_UNDERFLOW | IXR_RX_FIFO_OVERFLOW | + IXR_TX_FIFO_MODE_FAIL); + /* these are pure functions of fifo state, set them here */ + s->regs[R_INTR_STATUS] |= + (fifo8_is_full(&s->rx_fifo) ? IXR_RX_FIFO_FULL : 0) | + (s->rx_fifo.num >= s->regs[R_RX_THRES] ? IXR_RX_FIFO_NOT_EMPTY : 0) | + (fifo8_is_full(&s->tx_fifo) ? IXR_TX_FIFO_FULL : 0) | + (s->tx_fifo.num < s->regs[R_TX_THRES] ? IXR_TX_FIFO_NOT_FULL : 0); + /* drive external interrupt pin */ + int new_irqline = !!(s->regs[R_INTR_MASK] & s->regs[R_INTR_STATUS] & + IXR_ALL); + if (new_irqline != s->irqline) { + s->irqline = new_irqline; + qemu_set_irq(s->irq, s->irqline); + } +} + +static void xilinx_spips_reset(DeviceState *d) +{ + XilinxSPIPS *s = DO_UPCAST(XilinxSPIPS, busdev.qdev, d); + + int i; + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } + + fifo8_reset(&s->rx_fifo); + fifo8_reset(&s->rx_fifo); + /* non zero resets */ + s->regs[R_CONFIG] |= MODEFAIL_GEN_EN; + s->regs[R_SLAVE_IDLE_COUNT] = 0xFF; + s->regs[R_TX_THRES] = 1; + s->regs[R_RX_THRES] = 1; + /* FIXME: move magic number definition somewhere sensible */ + s->regs[R_MOD_ID] = 0x01090106; + s->regs[R_LQSPI_CFG] = R_LQSPI_CFG_RESET; + s->snoop_state = SNOOP_CHECKING; + xilinx_spips_update_ixr(s); + xilinx_spips_update_cs_lines(s); +} + +static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) +{ + for (;;) { + int i; + uint8_t rx; + uint8_t tx = 0; + + for (i = 0; i < num_effective_busses(s); ++i) { + if (!i || s->snoop_state == SNOOP_STRIPING) { + if (fifo8_is_empty(&s->tx_fifo)) { + s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW; + xilinx_spips_update_ixr(s); + return; + } else { + tx = fifo8_pop(&s->tx_fifo); + } + } + rx = ssi_transfer(s->spi[i], (uint32_t)tx); + DB_PRINT("tx = %02x rx = %02x\n", tx, rx); + if (!i || s->snoop_state == SNOOP_STRIPING) { + if (fifo8_is_full(&s->rx_fifo)) { + s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW; + DB_PRINT("rx FIFO overflow"); + } else { + fifo8_push(&s->rx_fifo, (uint8_t)rx); + } + } + } + + switch (s->snoop_state) { + case (SNOOP_CHECKING): + switch (tx) { /* new instruction code */ + case 0x0b: /* dual/quad output read DOR/QOR */ + case 0x6b: + s->snoop_state = 4; + break; + /* FIXME: these vary between vendor - set to spansion */ + case 0xbb: /* high performance dual read DIOR */ + s->snoop_state = 4; + break; + case 0xeb: /* high performance quad read QIOR */ + s->snoop_state = 6; + break; + default: + s->snoop_state = SNOOP_NONE; + } + break; + case (SNOOP_STRIPING): + case (SNOOP_NONE): + break; + default: + s->snoop_state--; + } + } +} + +static inline void rx_data_bytes(XilinxSPIPS *s, uint32_t *value, int max) +{ + int i; + + *value = 0; + for (i = 0; i < max && !fifo8_is_empty(&s->rx_fifo); ++i) { + uint32_t next = fifo8_pop(&s->rx_fifo) & 0xFF; + *value |= next << 8 * (s->regs[R_CONFIG] & ENDIAN ? 3-i : i); + } +} + +static uint64_t xilinx_spips_read(void *opaque, hwaddr addr, + unsigned size) +{ + XilinxSPIPS *s = opaque; + uint32_t mask = ~0; + uint32_t ret; + + addr >>= 2; + switch (addr) { + case R_CONFIG: + mask = 0x0002FFFF; + break; + case R_INTR_STATUS: + case R_INTR_MASK: + mask = IXR_ALL; + break; + case R_EN: + mask = 0x1; + break; + case R_SLAVE_IDLE_COUNT: + mask = 0xFF; + break; + case R_MOD_ID: + mask = 0x01FFFFFF; + break; + case R_INTR_EN: + case R_INTR_DIS: + case R_TX_DATA: + mask = 0; + break; + case R_RX_DATA: + rx_data_bytes(s, &ret, s->num_txrx_bytes); + DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret); + xilinx_spips_update_ixr(s); + return ret; + } + DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, s->regs[addr] & mask); + return s->regs[addr] & mask; + +} + +static inline void tx_data_bytes(XilinxSPIPS *s, uint32_t value, int num) +{ + int i; + for (i = 0; i < num && !fifo8_is_full(&s->tx_fifo); ++i) { + if (s->regs[R_CONFIG] & ENDIAN) { + fifo8_push(&s->tx_fifo, (uint8_t)(value >> 24)); + value <<= 8; + } else { + fifo8_push(&s->tx_fifo, (uint8_t)value); + value >>= 8; + } + } +} + +static void xilinx_spips_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + int mask = ~0; + int man_start_com = 0; + XilinxSPIPS *s = opaque; + + DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value); + addr >>= 2; + switch (addr) { + case R_CONFIG: + mask = 0x0002FFFF; + if (value & MAN_START_COM) { + man_start_com = 1; + } + break; + case R_INTR_STATUS: + mask = IXR_ALL; + s->regs[R_INTR_STATUS] &= ~(mask & value); + goto no_reg_update; + case R_INTR_DIS: + mask = IXR_ALL; + s->regs[R_INTR_MASK] &= ~(mask & value); + goto no_reg_update; + case R_INTR_EN: + mask = IXR_ALL; + s->regs[R_INTR_MASK] |= mask & value; + goto no_reg_update; + case R_EN: + mask = 0x1; + break; + case R_SLAVE_IDLE_COUNT: + mask = 0xFF; + break; + case R_RX_DATA: + case R_INTR_MASK: + case R_MOD_ID: + mask = 0; + break; + case R_TX_DATA: + tx_data_bytes(s, (uint32_t)value, s->num_txrx_bytes); + goto no_reg_update; + case R_TXD1: + tx_data_bytes(s, (uint32_t)value, 1); + goto no_reg_update; + case R_TXD2: + tx_data_bytes(s, (uint32_t)value, 2); + goto no_reg_update; + case R_TXD3: + tx_data_bytes(s, (uint32_t)value, 3); + goto no_reg_update; + } + s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask); +no_reg_update: + if (man_start_com) { + xilinx_spips_flush_txfifo(s); + } + xilinx_spips_update_ixr(s); + xilinx_spips_update_cs_lines(s); +} + +static const MemoryRegionOps spips_ops = { + .read = xilinx_spips_read, + .write = xilinx_spips_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +#define LQSPI_CACHE_SIZE 1024 + +static uint64_t +lqspi_read(void *opaque, hwaddr addr, unsigned int size) +{ + int i; + XilinxSPIPS *s = opaque; + + if (addr >= s->lqspi_cached_addr && + addr <= s->lqspi_cached_addr + LQSPI_CACHE_SIZE - 4) { + return s->lqspi_buf[(addr - s->lqspi_cached_addr) >> 2]; + } else { + int flash_addr = (addr / num_effective_busses(s)); + int slave = flash_addr >> LQSPI_ADDRESS_BITS; + int cache_entry = 0; + + DB_PRINT("config reg status: %08x\n", s->regs[R_LQSPI_CFG]); + + fifo8_reset(&s->tx_fifo); + fifo8_reset(&s->rx_fifo); + + s->regs[R_CONFIG] &= ~CS; + s->regs[R_CONFIG] |= (~(1 << slave) << CS_SHIFT) & CS; + xilinx_spips_update_cs_lines(s); + + /* instruction */ + DB_PRINT("pushing read instruction: %02x\n", + (uint8_t)(s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE)); + fifo8_push(&s->tx_fifo, s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE); + /* read address */ + DB_PRINT("pushing read address %06x\n", flash_addr); + fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 16)); + fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 8)); + fifo8_push(&s->tx_fifo, (uint8_t)flash_addr); + /* mode bits */ + if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_MODE_EN) { + fifo8_push(&s->tx_fifo, extract32(s->regs[R_LQSPI_CFG], + LQSPI_CFG_MODE_SHIFT, + LQSPI_CFG_MODE_WIDTH)); + } + /* dummy bytes */ + for (i = 0; i < (extract32(s->regs[R_LQSPI_CFG], LQSPI_CFG_DUMMY_SHIFT, + LQSPI_CFG_DUMMY_WIDTH)); ++i) { + DB_PRINT("pushing dummy byte\n"); + fifo8_push(&s->tx_fifo, 0); + } + xilinx_spips_flush_txfifo(s); + fifo8_reset(&s->rx_fifo); + + DB_PRINT("starting QSPI data read\n"); + + for (i = 0; i < LQSPI_CACHE_SIZE / 4; ++i) { + tx_data_bytes(s, 0, 4); + xilinx_spips_flush_txfifo(s); + rx_data_bytes(s, &s->lqspi_buf[cache_entry], 4); + cache_entry++; + } + + s->regs[R_CONFIG] |= CS; + xilinx_spips_update_cs_lines(s); + + s->lqspi_cached_addr = addr; + return lqspi_read(opaque, addr, size); + } +} + +static const MemoryRegionOps lqspi_ops = { + .read = lqspi_read, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static int xilinx_spips_init(SysBusDevice *dev) +{ + XilinxSPIPS *s = FROM_SYSBUS(typeof(*s), dev); + int i; + + DB_PRINT("inited device model\n"); + + s->spi = g_new(SSIBus *, s->num_busses); + for (i = 0; i < s->num_busses; ++i) { + char bus_name[16]; + snprintf(bus_name, 16, "spi%d", i); + s->spi[i] = ssi_create_bus(&dev->qdev, bus_name); + } + + s->cs_lines = g_new(qemu_irq, s->num_cs * s->num_busses); + ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[0]); + ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[1]); + sysbus_init_irq(dev, &s->irq); + for (i = 0; i < s->num_cs * s->num_busses; ++i) { + sysbus_init_irq(dev, &s->cs_lines[i]); + } + + memory_region_init_io(&s->iomem, &spips_ops, s, "spi", R_MAX*4); + sysbus_init_mmio(dev, &s->iomem); + + memory_region_init_io(&s->mmlqspi, &lqspi_ops, s, "lqspi", + (1 << LQSPI_ADDRESS_BITS) * 2); + sysbus_init_mmio(dev, &s->mmlqspi); + + s->irqline = -1; + s->lqspi_cached_addr = ~0ULL; + + fifo8_create(&s->rx_fifo, RXFF_A); + fifo8_create(&s->tx_fifo, TXFF_A); + + return 0; +} + +static int xilinx_spips_post_load(void *opaque, int version_id) +{ + xilinx_spips_update_ixr((XilinxSPIPS *)opaque); + xilinx_spips_update_cs_lines((XilinxSPIPS *)opaque); + return 0; +} + +static const VMStateDescription vmstate_xilinx_spips = { + .name = "xilinx_spips", + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .post_load = xilinx_spips_post_load, + .fields = (VMStateField[]) { + VMSTATE_FIFO8(tx_fifo, XilinxSPIPS), + VMSTATE_FIFO8(rx_fifo, XilinxSPIPS), + VMSTATE_UINT32_ARRAY(regs, XilinxSPIPS, R_MAX), + VMSTATE_UINT8(snoop_state, XilinxSPIPS), + VMSTATE_END_OF_LIST() + } +}; + +static Property xilinx_spips_properties[] = { + DEFINE_PROP_UINT8("num-busses", XilinxSPIPS, num_busses, 1), + DEFINE_PROP_UINT8("num-ss-bits", XilinxSPIPS, num_cs, 4), + DEFINE_PROP_UINT8("num-txrx-bytes", XilinxSPIPS, num_txrx_bytes, 1), + DEFINE_PROP_END_OF_LIST(), +}; +static void xilinx_spips_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = xilinx_spips_init; + dc->reset = xilinx_spips_reset; + dc->props = xilinx_spips_properties; + dc->vmsd = &vmstate_xilinx_spips; +} + +static const TypeInfo xilinx_spips_info = { + .name = "xilinx,spips", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(XilinxSPIPS), + .class_init = xilinx_spips_class_init, +}; + +static void xilinx_spips_register_types(void) +{ + type_register_static(&xilinx_spips_info); +} + +type_init(xilinx_spips_register_types) diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c index b562bd065e..69294bb83c 100644 --- a/hw/xilinx_timer.c +++ b/hw/xilinx_timer.c @@ -24,6 +24,7 @@ #include "sysbus.h" #include "ptimer.h" +#include "qemu/log.h" #define D(x) @@ -71,7 +72,7 @@ static inline unsigned int num_timers(struct timerblock *t) return 2 - t->one_timer_only; } -static inline unsigned int timer_from_addr(target_phys_addr_t addr) +static inline unsigned int timer_from_addr(hwaddr addr) { /* Timers get a 4x32bit control reg area each. */ return addr >> 2; @@ -92,7 +93,7 @@ static void timer_update_irq(struct timerblock *t) } static uint64_t -timer_read(void *opaque, target_phys_addr_t addr, unsigned int size) +timer_read(void *opaque, hwaddr addr, unsigned int size) { struct timerblock *t = opaque; struct xlx_timer *xt; @@ -119,7 +120,7 @@ timer_read(void *opaque, target_phys_addr_t addr, unsigned int size) break; } - D(printf("%s timer=%d %x=%x\n", __func__, timer, addr * 4, r)); + D(fprintf(stderr, "%s timer=%d %x=%x\n", __func__, timer, addr * 4, r)); return r; } @@ -127,7 +128,7 @@ static void timer_enable(struct xlx_timer *xt) { uint64_t count; - D(printf("%s timer=%d down=%d\n", __func__, + D(fprintf(stderr, "%s timer=%d down=%d\n", __func__, xt->nr, xt->regs[R_TCSR] & TCSR_UDT)); ptimer_stop(xt->ptimer); @@ -141,7 +142,7 @@ static void timer_enable(struct xlx_timer *xt) } static void -timer_write(void *opaque, target_phys_addr_t addr, +timer_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { struct timerblock *t = opaque; @@ -152,7 +153,7 @@ timer_write(void *opaque, target_phys_addr_t addr, addr >>= 2; timer = timer_from_addr(addr); xt = &t->timers[timer]; - D(printf("%s addr=%x val=%x (timer=%d off=%d)\n", + D(fprintf(stderr, "%s addr=%x val=%x (timer=%d off=%d)\n", __func__, addr * 4, value, timer, addr & 3)); /* Further decoding to address a specific timers reg. */ addr &= 3; @@ -189,7 +190,7 @@ static void timer_hit(void *opaque) { struct xlx_timer *xt = opaque; struct timerblock *t = xt->parent; - D(printf("%s %d\n", __func__, timer)); + D(fprintf(stderr, "%s %d\n", __func__, xt->nr)); xt->regs[R_TCSR] |= TCSR_TINT; if (xt->regs[R_TCSR] & TCSR_ARHT) @@ -217,14 +218,15 @@ static int xilinx_timer_init(SysBusDevice *dev) ptimer_set_freq(xt->ptimer, t->freq_hz); } - memory_region_init_io(&t->mmio, &timer_ops, t, "xlnx,xps-timer", + memory_region_init_io(&t->mmio, &timer_ops, t, "xlnx.xps-timer", R_MAX * 4 * num_timers(t)); sysbus_init_mmio(dev, &t->mmio); return 0; } static Property xilinx_timer_properties[] = { - DEFINE_PROP_UINT32("frequency", struct timerblock, freq_hz, 62 * 1000000), + DEFINE_PROP_UINT32("clock-frequency", struct timerblock, freq_hz, + 62 * 1000000), DEFINE_PROP_UINT8("one-timer-only", struct timerblock, one_timer_only, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -239,7 +241,7 @@ static void xilinx_timer_class_init(ObjectClass *klass, void *data) } static TypeInfo xilinx_timer_info = { - .name = "xlnx,xps-timer", + .name = "xlnx.xps-timer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct timerblock), .class_init = xilinx_timer_class_init, diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c index d0f32db2c6..abd256ae00 100644 --- a/hw/xilinx_uartlite.c +++ b/hw/xilinx_uartlite.c @@ -23,7 +23,7 @@ */ #include "sysbus.h" -#include "qemu-char.h" +#include "char/char.h" #define DUART(x) @@ -84,7 +84,7 @@ static void uart_update_status(struct xlx_uartlite *s) } static uint64_t -uart_read(void *opaque, target_phys_addr_t addr, unsigned int size) +uart_read(void *opaque, hwaddr addr, unsigned int size) { struct xlx_uartlite *s = opaque; uint32_t r = 0; @@ -97,6 +97,7 @@ uart_read(void *opaque, target_phys_addr_t addr, unsigned int size) s->rx_fifo_len--; uart_update_status(s); uart_update_irq(s); + qemu_chr_accept_input(s->chr); break; default: @@ -109,7 +110,7 @@ uart_read(void *opaque, target_phys_addr_t addr, unsigned int size) } static void -uart_write(void *opaque, target_phys_addr_t addr, +uart_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { struct xlx_uartlite *s = opaque; @@ -182,12 +183,8 @@ static void uart_rx(void *opaque, const uint8_t *buf, int size) static int uart_can_rx(void *opaque) { struct xlx_uartlite *s = opaque; - int r; - r = s->rx_fifo_len < sizeof(s->rx_fifo); - if (!r) - printf("cannot receive!\n"); - return r; + return s->rx_fifo_len < sizeof(s->rx_fifo); } static void uart_event(void *opaque, int event) diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c index 7e6c27359e..da0a7d0aa1 100644 --- a/hw/xilinx_zynq.c +++ b/hw/xilinx_zynq.c @@ -17,13 +17,18 @@ #include "sysbus.h" #include "arm-misc.h" -#include "net.h" -#include "exec-memory.h" -#include "sysemu.h" +#include "net/net.h" +#include "exec/address-spaces.h" +#include "sysemu/sysemu.h" #include "boards.h" #include "flash.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" #include "loader.h" +#include "ssi.h" + +#define NUM_SPI_FLASHES 4 +#define NUM_QSPI_FLASHES 2 +#define NUM_QSPI_BUSSES 2 #define FLASH_SIZE (64 * 1024 * 1024) #define FLASH_SECTOR_SIZE (128 * 1024) @@ -46,10 +51,55 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) sysbus_connect_irq(s, 0, irq); } -static void zynq_init(ram_addr_t ram_size, const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, + bool is_qspi) +{ + DeviceState *dev; + SysBusDevice *busdev; + SSIBus *spi; + DeviceState *flash_dev; + int i, j; + int num_busses = is_qspi ? NUM_QSPI_BUSSES : 1; + int num_ss = is_qspi ? NUM_QSPI_FLASHES : NUM_SPI_FLASHES; + + dev = qdev_create(NULL, "xilinx,spips"); + qdev_prop_set_uint8(dev, "num-txrx-bytes", is_qspi ? 4 : 1); + qdev_prop_set_uint8(dev, "num-ss-bits", num_ss); + qdev_prop_set_uint8(dev, "num-busses", num_busses); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_mmio_map(busdev, 0, base_addr); + if (is_qspi) { + sysbus_mmio_map(busdev, 1, 0xFC000000); + } + sysbus_connect_irq(busdev, 0, irq); + + for (i = 0; i < num_busses; ++i) { + char bus_name[16]; + qemu_irq cs_line; + + snprintf(bus_name, 16, "spi%d", i); + spi = (SSIBus *)qdev_get_child_bus(dev, bus_name); + + for (j = 0; j < num_ss; ++j) { + flash_dev = ssi_create_slave_no_init(spi, "m25p80"); + qdev_prop_set_string(flash_dev, "partname", "n25q128"); + qdev_init_nofail(flash_dev); + + cs_line = qdev_get_gpio_in(flash_dev, 0); + sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line); + } + } + +} + +static void zynq_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ext_ram = g_new(MemoryRegion, 1); @@ -113,6 +163,13 @@ static void zynq_init(ram_addr_t ram_size, const char *boot_device, pic[n] = qdev_get_gpio_in(dev, n); } + zynq_init_spi_flashes(0xE0006000, pic[58-IRQ_OFFSET], false); + zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET], false); + zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true); + + sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]); + sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[75-IRQ_OFFSET]); + sysbus_create_simple("cadence_uart", 0xE0000000, pic[59-IRQ_OFFSET]); sysbus_create_simple("cadence_uart", 0xE0001000, pic[82-IRQ_OFFSET]); @@ -144,7 +201,7 @@ static QEMUMachine zynq_machine = { .name = "xilinx-zynq-a9", .desc = "Xilinx Zynq Platform Baseboard for Cortex-A9", .init = zynq_init, - .use_scsi = 1, + .block_default_type = IF_SCSI, .max_cpus = 1, .no_sdcard = 1 }; diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c index 0d8a5e7020..2dcd46bff1 100644 --- a/hw/xio3130_downstream.c +++ b/hw/xio3130_downstream.c @@ -19,9 +19,9 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "pci_ids.h" -#include "msi.h" -#include "pcie.h" +#include "pci/pci_ids.h" +#include "pci/msi.h" +#include "pci/pcie.h" #include "xio3130_downstream.h" #define PCI_DEVICE_ID_TI_XIO3130D 0x8233 /* downstream port */ diff --git a/hw/xio3130_downstream.h b/hw/xio3130_downstream.h index 010487f2d9..559dff6565 100644 --- a/hw/xio3130_downstream.h +++ b/hw/xio3130_downstream.h @@ -1,7 +1,7 @@ #ifndef QEMU_XIO3130_DOWNSTREAM_H #define QEMU_XIO3130_DOWNSTREAM_H -#include "pcie_port.h" +#include "pci/pcie_port.h" PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction, const char *bus_name, pci_map_irq_fn map_irq, diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c index d46b86c74d..713caf2dda 100644 --- a/hw/xio3130_upstream.c +++ b/hw/xio3130_upstream.c @@ -19,9 +19,9 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "pci_ids.h" -#include "msi.h" -#include "pcie.h" +#include "pci/pci_ids.h" +#include "pci/msi.h" +#include "pci/pcie.h" #include "xio3130_upstream.h" #define PCI_DEVICE_ID_TI_XIO3130U 0x8232 /* upstream port */ diff --git a/hw/xio3130_upstream.h b/hw/xio3130_upstream.h index e9969975ff..fa09656b35 100644 --- a/hw/xio3130_upstream.h +++ b/hw/xio3130_upstream.h @@ -1,7 +1,7 @@ #ifndef QEMU_XIO3130_UPSTREAM_H #define QEMU_XIO3130_UPSTREAM_H -#include "pcie_port.h" +#include "pci/pcie_port.h" PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction, const char *bus_name, pci_map_irq_fn map_irq, diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c index 3653f65b1e..0b9a52851a 100644 --- a/hw/xtensa_lx60.c +++ b/hw/xtensa_lx60.c @@ -25,16 +25,18 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "boards.h" #include "loader.h" #include "elf.h" -#include "memory.h" -#include "exec-memory.h" -#include "pc.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" +#include "serial.h" +#include "net/net.h" #include "sysbus.h" #include "flash.h" -#include "blockdev.h" +#include "sysemu/blockdev.h" +#include "char/char.h" #include "xtensa_bootparam.h" typedef struct LxBoardDesc { @@ -57,7 +59,7 @@ static void lx60_fpga_reset(void *opaque) s->switches = 0; } -static uint64_t lx60_fpga_read(void *opaque, target_phys_addr_t addr, +static uint64_t lx60_fpga_read(void *opaque, hwaddr addr, unsigned size) { Lx60FpgaState *s = opaque; @@ -78,7 +80,7 @@ static uint64_t lx60_fpga_read(void *opaque, target_phys_addr_t addr, return 0; } -static void lx60_fpga_write(void *opaque, target_phys_addr_t addr, +static void lx60_fpga_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { Lx60FpgaState *s = opaque; @@ -103,7 +105,7 @@ static const MemoryRegionOps lx60_fpga_ops = { }; static Lx60FpgaState *lx60_fpga_init(MemoryRegion *address_space, - target_phys_addr_t base) + hwaddr base) { Lx60FpgaState *s = g_malloc(sizeof(Lx60FpgaState)); @@ -116,9 +118,9 @@ static Lx60FpgaState *lx60_fpga_init(MemoryRegion *address_space, } static void lx60_net_init(MemoryRegion *address_space, - target_phys_addr_t base, - target_phys_addr_t descriptors, - target_phys_addr_t buffers, + hwaddr base, + hwaddr descriptors, + hwaddr buffers, qemu_irq irq, NICInfo *nd) { DeviceState *dev; @@ -154,10 +156,7 @@ static void lx60_reset(void *opaque) cpu_reset(CPU(cpu)); } -static void lx_init(const LxBoardDesc *board, - ram_addr_t ram_size, const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args) { #ifdef TARGET_WORDS_BIGENDIAN int be = 1; @@ -170,6 +169,9 @@ static void lx_init(const LxBoardDesc *board, MemoryRegion *ram, *rom, *system_io; DriveInfo *dinfo; pflash_t *flash = NULL; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; int n; if (!cpu_model) { @@ -193,7 +195,7 @@ static void lx_init(const LxBoardDesc *board, } ram = g_malloc(sizeof(*ram)); - memory_region_init_ram(ram, "lx60.dram", ram_size); + memory_region_init_ram(ram, "lx60.dram", args->ram_size); vmstate_register_ram_global(ram); memory_region_add_subregion(system_memory, 0, ram); @@ -268,34 +270,24 @@ static void lx_init(const LxBoardDesc *board, } } -static void xtensa_lx60_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void xtensa_lx60_init(QEMUMachineInitArgs *args) { static const LxBoardDesc lx60_board = { .flash_size = 0x400000, .flash_sector_size = 0x10000, .sram_size = 0x20000, }; - lx_init(&lx60_board, ram_size, boot_device, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model); + lx_init(&lx60_board, args); } -static void xtensa_lx200_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void xtensa_lx200_init(QEMUMachineInitArgs *args) { static const LxBoardDesc lx200_board = { .flash_size = 0x1000000, .flash_sector_size = 0x20000, .sram_size = 0x2000000, }; - lx_init(&lx200_board, ram_size, boot_device, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model); + lx_init(&lx200_board, args); } static QEMUMachine xtensa_lx60_machine = { diff --git a/hw/xtensa_pic.c b/hw/xtensa_pic.c index 653ded6820..97d36be272 100644 --- a/hw/xtensa_pic.c +++ b/hw/xtensa_pic.c @@ -26,8 +26,8 @@ */ #include "hw.h" -#include "qemu-log.h" -#include "qemu-timer.h" +#include "qemu/log.h" +#include "qemu/timer.h" void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d) { @@ -125,12 +125,13 @@ void xtensa_rearm_ccompare_timer(CPUXtensaState *env) static void xtensa_ccompare_cb(void *opaque) { - CPUXtensaState *env = opaque; + XtensaCPU *cpu = opaque; + CPUXtensaState *env = &cpu->env; if (env->halted) { env->halt_clock = qemu_get_clock_ns(vm_clock); xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]); - if (!cpu_has_work(env)) { + if (!cpu_has_work(CPU(cpu))) { env->sregs[CCOUNT] = env->wake_ccount + 1; xtensa_rearm_ccompare_timer(env); } @@ -139,12 +140,14 @@ static void xtensa_ccompare_cb(void *opaque) void xtensa_irq_init(CPUXtensaState *env) { + XtensaCPU *cpu = xtensa_env_get_cpu(env); + env->irq_inputs = (void **)qemu_allocate_irqs( xtensa_set_irq, env, env->config->ninterrupt); if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) && env->config->nccompare > 0) { env->ccompare_timer = - qemu_new_timer_ns(vm_clock, &xtensa_ccompare_cb, env); + qemu_new_timer_ns(vm_clock, &xtensa_ccompare_cb, cpu); } } diff --git a/hw/xtensa_sim.c b/hw/xtensa_sim.c index 831460b7c4..14fe85b2fc 100644 --- a/hw/xtensa_sim.c +++ b/hw/xtensa_sim.c @@ -25,12 +25,12 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "boards.h" #include "loader.h" #include "elf.h" -#include "memory.h" -#include "exec-memory.h" +#include "exec/memory.h" +#include "exec/address-spaces.h" static uint64_t translate_phys_addr(void *env, uint64_t addr) { @@ -44,16 +44,20 @@ static void sim_reset(void *opaque) cpu_reset(CPU(cpu)); } -static void sim_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void xtensa_sim_init(QEMUMachineInitArgs *args) { XtensaCPU *cpu = NULL; CPUXtensaState *env = NULL; MemoryRegion *ram, *rom; + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; int n; + if (!cpu_model) { + cpu_model = XTENSA_DEFAULT_CPU_MODEL; + } + for (n = 0; n < smp_cpus; n++) { cpu = cpu_xtensa_init(cpu_model); if (cpu == NULL) { @@ -96,18 +100,6 @@ static void sim_init(ram_addr_t ram_size, } } -static void xtensa_sim_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) -{ - if (!cpu_model) { - cpu_model = XTENSA_DEFAULT_CPU_MODEL; - } - sim_init(ram_size, boot_device, kernel_filename, kernel_cmdline, - initrd_filename, cpu_model); -} - static QEMUMachine xtensa_sim_machine = { .name = "sim", .desc = "sim machine (" XTENSA_DEFAULT_CPU_MODEL ")", @@ -18,12 +18,12 @@ #include "i2c.h" #include "ssi.h" #include "boards.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #include "flash.h" -#include "blockdev.h" -#include "console.h" +#include "sysemu/blockdev.h" +#include "ui/console.h" #include "audio/audio.h" -#include "exec-memory.h" +#include "exec/address-spaces.h" #ifdef DEBUG_Z2 #define DPRINTF(fmt, ...) \ @@ -161,10 +161,11 @@ static int zipit_lcd_init(SSISlave *dev) static VMStateDescription vmstate_zipit_lcd_state = { .name = "zipit-lcd", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, .fields = (VMStateField[]) { + VMSTATE_SSI_SLAVE(ssidev, ZipitLCD), VMSTATE_INT32(selected, ZipitLCD), VMSTATE_INT32(enabled, ZipitLCD), VMSTATE_BUFFER(buf, ZipitLCD), @@ -294,11 +295,12 @@ static TypeInfo aer915_info = { .class_init = aer915_class_init, }; -static void z2_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void z2_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; MemoryRegion *address_space_mem = get_system_memory(); uint32_t sector_len = 0x10000; PXA2xxState *mpu; diff --git a/hw/zaurus.c b/hw/zaurus.c index 72838ec440..d77b34ecce 100644 --- a/hw/zaurus.c +++ b/hw/zaurus.c @@ -68,7 +68,7 @@ static inline void scoop_gpio_handler_update(ScoopInfo *s) { s->prev_level = level; } -static uint64_t scoop_read(void *opaque, target_phys_addr_t addr, +static uint64_t scoop_read(void *opaque, hwaddr addr, unsigned size) { ScoopInfo *s = (ScoopInfo *) opaque; @@ -102,7 +102,7 @@ static uint64_t scoop_read(void *opaque, target_phys_addr_t addr, return 0; } -static void scoop_write(void *opaque, target_phys_addr_t addr, +static void scoop_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { ScoopInfo *s = (ScoopInfo *) opaque; @@ -285,7 +285,7 @@ static struct QEMU_PACKED sl_param_info { .phadadj = 0x01, }; -void sl_bootparam_write(target_phys_addr_t ptr) +void sl_bootparam_write(hwaddr ptr) { cpu_physical_memory_write(ptr, (void *)&zaurus_bootparam, sizeof(struct sl_param_info)); diff --git a/hw/zynq_slcr.c b/hw/zynq_slcr.c index 4f97575770..143a7cf436 100644 --- a/hw/zynq_slcr.c +++ b/hw/zynq_slcr.c @@ -15,9 +15,9 @@ */ #include "hw.h" -#include "qemu-timer.h" +#include "qemu/timer.h" #include "sysbus.h" -#include "sysemu.h" +#include "sysemu/sysemu.h" #ifdef ZYNQ_ARM_SLCR_ERR_DEBUG #define DB_PRINT(...) do { \ @@ -91,7 +91,7 @@ typedef enum { typedef enum { PSS, DDDR, - DMAC, + DMAC = 3, USB, GEM, SDIO, @@ -246,7 +246,7 @@ static void zynq_slcr_reset(DeviceState *d) } static inline uint32_t zynq_slcr_read_imp(void *opaque, - target_phys_addr_t offset) + hwaddr offset) { ZynqSLCRState *s = (ZynqSLCRState *)opaque; @@ -329,21 +329,21 @@ static inline uint32_t zynq_slcr_read_imp(void *opaque, } } -static uint64_t zynq_slcr_read(void *opaque, target_phys_addr_t offset, +static uint64_t zynq_slcr_read(void *opaque, hwaddr offset, unsigned size) { uint32_t ret = zynq_slcr_read_imp(opaque, offset); - DB_PRINT("addr: %08x data: %08x\n", offset, ret); + DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)ret); return ret; } -static void zynq_slcr_write(void *opaque, target_phys_addr_t offset, +static void zynq_slcr_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { ZynqSLCRState *s = (ZynqSLCRState *)opaque; - DB_PRINT("offset: %08x data: %08x\n", offset, (unsigned)val); + DB_PRINT("offset: %08x data: %08x\n", (unsigned)offset, (unsigned)val); switch (offset) { case 0x00: /* SCL */ @@ -476,7 +476,8 @@ static void zynq_slcr_write(void *opaque, target_phys_addr_t offset, break; default: bad_reg: - DB_PRINT("Bad register write %x <= %08x\n", (int)offset, val); + DB_PRINT("Bad register write %x <= %08x\n", (int)offset, + (unsigned)val); } } else { DB_PRINT("SCLR registers are locked. Unlock them first\n"); |