diff options
author | Avi Kivity <avi@redhat.com> | 2011-02-09 15:22:40 +0200 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-02-09 15:22:40 +0200 |
commit | 7aa8c46b2d3bc3bebbf87cb68e02baee6338b597 (patch) | |
tree | 2b7d7d8bbe85107d84781edbbc924f97c91675d4 | |
parent | e374f7e06fe82c195be2e62c667ae0b3ffcb27ad (diff) | |
parent | bf883ad26873e9e3ae9fec02d136f6ef281f924d (diff) |
Merge branch 'upstream-merge' into stable-0.14qemu-kvm-0.14.0-rc1
* upstream-merge: (34 commits)
x86: Fix MCA broadcast parameters for TCG case
qemu-timer: Fix compilation of new timer code for w32, w64
Update version for 0.14.0-rc1
block: enable in_use flag
Add flag to indicate external users to block device
block-migration: add reference to target DriveInfo
blockdev: add refcount to DriveInfo
block-migration: actually disable dirty tracking on cleanup
ahci: make number of ports runtime determined
ahci: Implement HBA reset
ahci: send init d2h fis on fis enable
ahci: split ICH and AHCI even more
ahci: add license header in ahci.h
ahci: split ICH9 from core
block/vdi: Fix wrong size in conditionally used memset, memcmp
Documentation: add Sheepdog disk images
qcow2: Really use cache=unsafe for image creation
do not pass NULL to strdup.
Set the right overflow bit for neon 32 and 64 bit saturating add/sub.
target-arm: Fix Neon vsra instructions.
...
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | Makefile.objs | 1 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | block-migration.c | 9 | ||||
-rw-r--r-- | block.c | 13 | ||||
-rw-r--r-- | block.h | 2 | ||||
-rw-r--r-- | block/qcow2.c | 3 | ||||
-rw-r--r-- | block/vdi.c | 4 | ||||
-rw-r--r-- | block_int.h | 1 | ||||
-rw-r--r-- | blockdev.c | 22 | ||||
-rw-r--r-- | blockdev.h | 4 | ||||
-rw-r--r-- | hw/apic.c | 9 | ||||
-rw-r--r-- | hw/ide/ahci.c | 485 | ||||
-rw-r--r-- | hw/ide/ahci.h | 333 | ||||
-rw-r--r-- | hw/ide/ich.c | 148 | ||||
-rw-r--r-- | hw/ioapic.c | 221 | ||||
-rw-r--r-- | hw/ioapic.h | 20 | ||||
-rw-r--r-- | hw/pci-hotplug.c | 2 | ||||
-rw-r--r-- | hw/virtio-serial-bus.c | 3 | ||||
-rw-r--r-- | qemu-doc.texi | 52 | ||||
-rw-r--r-- | qemu-timer.c | 71 | ||||
-rw-r--r-- | savevm.c | 10 | ||||
-rw-r--r-- | target-arm/helpers.h | 12 | ||||
-rw-r--r-- | target-arm/neon_helper.c | 89 | ||||
-rw-r--r-- | target-arm/op_helper.c | 49 | ||||
-rw-r--r-- | target-arm/translate.c | 22 | ||||
-rw-r--r-- | target-i386/helper.c | 4 | ||||
-rw-r--r-- | target-sh4/translate.c | 4 | ||||
-rw-r--r-- | ui/sdl.c | 8 | ||||
-rw-r--r-- | ui/vnc-jobs-async.c | 4 | ||||
-rw-r--r-- | vl.c | 4 |
30 files changed, 993 insertions, 618 deletions
diff --git a/Makefile.objs b/Makefile.objs index c4b4883c9..a647c45e1 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -247,6 +247,7 @@ hw-obj-$(CONFIG_IDE_CMD646) += ide/cmd646.o hw-obj-$(CONFIG_IDE_MACIO) += ide/macio.o hw-obj-$(CONFIG_IDE_VIA) += ide/via.o hw-obj-$(CONFIG_AHCI) += ide/ahci.o +hw-obj-$(CONFIG_AHCI) += ide/ich.o # SCSI layer hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o @@ -1 +1 @@ -0.13.90 +0.13.91 diff --git a/block-migration.c b/block-migration.c index c9d3e81db..8218bac09 100644 --- a/block-migration.c +++ b/block-migration.c @@ -19,6 +19,7 @@ #include "monitor.h" #include "block-migration.h" #include "migration.h" +#include "blockdev.h" #include <assert.h> #define BLOCK_SIZE (BDRV_SECTORS_PER_DIRTY_CHUNK << BDRV_SECTOR_BITS) @@ -299,6 +300,8 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs) bmds->completed_sectors = 0; bmds->shared_base = block_mig_state.shared_base; alloc_aio_bitmap(bmds); + drive_get_ref(drive_get_by_blockdev(bs)); + bdrv_set_in_use(bs, 1); block_mig_state.total_sector_sum += sectors; @@ -533,8 +536,12 @@ static void blk_mig_cleanup(Monitor *mon) BlkMigDevState *bmds; BlkMigBlock *blk; + set_dirty_tracking(0); + while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) { QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry); + bdrv_set_in_use(bmds->bs, 0); + drive_put_ref(drive_get_by_blockdev(bmds->bs)); qemu_free(bmds->aio_bitmap); qemu_free(bmds); } @@ -545,8 +552,6 @@ static void blk_mig_cleanup(Monitor *mon) qemu_free(blk); } - set_dirty_tracking(0); - monitor_printf(mon, "\n"); } @@ -1132,6 +1132,8 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset) return -ENOTSUP; if (bs->read_only) return -EACCES; + if (bdrv_in_use(bs)) + return -EBUSY; ret = drv->bdrv_truncate(bs, offset); if (ret == 0) { ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); @@ -2774,6 +2776,17 @@ int64_t bdrv_get_dirty_count(BlockDriverState *bs) return bs->dirty_count; } +void bdrv_set_in_use(BlockDriverState *bs, int in_use) +{ + assert(bs->in_use != in_use); + bs->in_use = in_use; +} + +int bdrv_in_use(BlockDriverState *bs) +{ + return bs->in_use; +} + int bdrv_img_create(const char *filename, const char *fmt, const char *base_filename, const char *base_fmt, char *options, uint64_t img_size, int flags) @@ -241,6 +241,8 @@ void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); int64_t bdrv_get_dirty_count(BlockDriverState *bs); +void bdrv_set_in_use(BlockDriverState *bs, int in_use); +int bdrv_in_use(BlockDriverState *bs); typedef enum { BLKDBG_L1_UPDATE, diff --git a/block/qcow2.c b/block/qcow2.c index dbe4fdd44..a1773e479 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -975,7 +975,8 @@ static int qcow2_create2(const char *filename, int64_t total_size, */ BlockDriver* drv = bdrv_find_format("qcow2"); assert(drv != NULL); - ret = bdrv_open(bs, filename, BDRV_O_RDWR | BDRV_O_NO_FLUSH, drv); + ret = bdrv_open(bs, filename, + BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv); if (ret < 0) { goto out; } diff --git a/block/vdi.c b/block/vdi.c index ab8f70f17..116b25bc9 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -119,13 +119,13 @@ void uuid_unparse(const uuid_t uu, char *out); #if !defined(CONFIG_UUID) void uuid_generate(uuid_t out) { - memset(out, 0, sizeof(out)); + memset(out, 0, sizeof(uuid_t)); } int uuid_is_null(const uuid_t uu) { uuid_t null_uuid = { 0 }; - return memcmp(uu, null_uuid, sizeof(uu)) == 0; + return memcmp(uu, null_uuid, sizeof(uuid_t)) == 0; } void uuid_unparse(const uuid_t uu, char *out) diff --git a/block_int.h b/block_int.h index 6ebdc3eea..545ad11ff 100644 --- a/block_int.h +++ b/block_int.h @@ -199,6 +199,7 @@ struct BlockDriverState { char device_name[32]; unsigned long *dirty_bitmap; int64_t dirty_count; + int in_use; /* users other than guest access, eg. block migration */ QTAILQ_ENTRY(BlockDriverState) list; void *private; }; diff --git a/blockdev.c b/blockdev.c index c9e249ef3..6399d6658 100644 --- a/blockdev.c +++ b/blockdev.c @@ -73,7 +73,7 @@ void blockdev_auto_del(BlockDriverState *bs) DriveInfo *dinfo = drive_get_by_blockdev(bs); if (dinfo && dinfo->auto_del) { - drive_uninit(dinfo); + drive_put_ref(dinfo); } } @@ -180,7 +180,7 @@ static void bdrv_format_print(void *opaque, const char *name) error_printf(" %s", name); } -void drive_uninit(DriveInfo *dinfo) +static void drive_uninit(DriveInfo *dinfo) { qemu_opts_del(dinfo->opts); bdrv_delete(dinfo->bdrv); @@ -188,6 +188,19 @@ void drive_uninit(DriveInfo *dinfo) qemu_free(dinfo); } +void drive_put_ref(DriveInfo *dinfo) +{ + assert(dinfo->refcount); + if (--dinfo->refcount == 0) { + drive_uninit(dinfo); + } +} + +void drive_get_ref(DriveInfo *dinfo) +{ + dinfo->refcount++; +} + static int parse_block_error_action(const char *buf, int is_read) { if (!strcmp(buf, "ignore")) { @@ -462,6 +475,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi) dinfo->bus = bus_id; dinfo->unit = unit_id; dinfo->opts = opts; + dinfo->refcount = 1; if (serial) strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1); QTAILQ_INSERT_TAIL(&drives, dinfo, next); @@ -725,6 +739,10 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) qerror_report(QERR_DEVICE_NOT_FOUND, id); return -1; } + if (bdrv_in_use(bs)) { + qerror_report(QERR_DEVICE_IN_USE, id); + return -1; + } /* quiesce block driver; prevent further io */ qemu_aio_flush(); diff --git a/blockdev.h b/blockdev.h index c0ee19973..8739f4620 100644 --- a/blockdev.h +++ b/blockdev.h @@ -36,13 +36,15 @@ struct DriveInfo { QemuOpts *opts; char serial[BLOCK_SERIAL_STRLEN + 1]; QTAILQ_ENTRY(DriveInfo) next; + int refcount; }; DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit); DriveInfo *drive_get_by_index(BlockInterfaceType type, int index); int drive_get_max_bus(BlockInterfaceType type); DriveInfo *drive_get_next(BlockInterfaceType type); -void drive_uninit(DriveInfo *dinfo); +void drive_get_ref(DriveInfo *dinfo); +void drive_put_ref(DriveInfo *dinfo); DriveInfo *drive_get_by_blockdev(BlockDriverState *bs); QemuOpts *drive_def(const char *optstr); @@ -18,6 +18,7 @@ */ #include "hw.h" #include "apic.h" +#include "ioapic.h" #include "qemu-timer.h" #include "host-utils.h" #include "sysbus.h" @@ -58,7 +59,8 @@ #define ESR_ILLEGAL_ADDRESS (1 << 7) -#define APIC_SV_ENABLE (1 << 8) +#define APIC_SV_DIRECTED_IO (1<<12) +#define APIC_SV_ENABLE (1<<8) #define MAX_APICS 255 #define MAX_APIC_WORDS 8 @@ -429,8 +431,9 @@ static void apic_eoi(APICState *s) if (isrv < 0) return; reset_bit(s->isr, isrv); - /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to - set the remote IRR bit for level triggered interrupts. */ + if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && get_bit(s->tmr, isrv)) { + ioapic_eoi_broadcast(isrv); + } apic_update_irq(s); } diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 671b4df7f..98bdf7059 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -19,47 +19,6 @@ * 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/>. * - * - * lspci dump of a ICH-9 real device in IDE mode (hopefully close enough): - * - * 00:1f.2 SATA controller [0106]: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922] (rev 02) (prog-if 01 [AHCI 1.0]) - * Subsystem: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922] - * Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+ - * Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx- - * Latency: 0 - * Interrupt: pin B routed to IRQ 222 - * Region 0: I/O ports at d000 [size=8] - * Region 1: I/O ports at cc00 [size=4] - * Region 2: I/O ports at c880 [size=8] - * Region 3: I/O ports at c800 [size=4] - * Region 4: I/O ports at c480 [size=32] - * Region 5: Memory at febf9000 (32-bit, non-prefetchable) [size=2K] - * Capabilities: [80] Message Signalled Interrupts: Mask- 64bit- Count=1/16 Enable+ - * Address: fee0f00c Data: 41d9 - * Capabilities: [70] Power Management version 3 - * Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot+,D3cold-) - * Status: D0 PME-Enable- DSel=0 DScale=0 PME- - * Capabilities: [a8] SATA HBA <?> - * Capabilities: [b0] Vendor Specific Information <?> - * Kernel driver in use: ahci - * Kernel modules: ahci - * 00: 86 80 22 29 07 04 b0 02 02 01 06 01 00 00 00 00 - * 10: 01 d0 00 00 01 cc 00 00 81 c8 00 00 01 c8 00 00 - * 20: 81 c4 00 00 00 90 bf fe 00 00 00 00 86 80 22 29 - * 30: 00 00 00 00 80 00 00 00 00 00 00 00 0f 02 00 00 - * 40: 00 80 00 80 00 00 00 00 00 00 00 00 00 00 00 00 - * 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * 70: 01 a8 03 40 08 00 00 00 00 00 00 00 00 00 00 00 - * 80: 05 70 09 00 0c f0 e0 fe d9 41 00 00 00 00 00 00 - * 90: 40 00 0f 82 93 01 00 00 00 00 00 00 00 00 00 00 - * a0: ac 00 00 00 0a 00 12 00 12 b0 10 00 48 00 00 00 - * b0: 09 00 06 20 00 00 00 00 00 00 00 00 00 00 00 00 - * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * f0: 00 00 00 00 00 00 00 00 86 0f 02 00 00 00 00 00 - * */ #include <hw/hw.h> @@ -72,6 +31,7 @@ #include "cpu-common.h" #include "internal.h" #include <hw/ide/pci.h> +#include <hw/ide/ahci.h> /* #define DEBUG_AHCI */ @@ -83,308 +43,11 @@ do { fprintf(stderr, "ahci: %s: [%d] ", __FUNCTION__, port); \ #define DPRINTF(port, fmt, ...) do {} while(0) #endif -#define AHCI_PCI_BAR 5 -#define AHCI_MAX_PORTS 32 -#define AHCI_MAX_SG 168 /* hardware max is 64K */ -#define AHCI_DMA_BOUNDARY 0xffffffff -#define AHCI_USE_CLUSTERING 0 -#define AHCI_MAX_CMDS 32 -#define AHCI_CMD_SZ 32 -#define AHCI_CMD_SLOT_SZ (AHCI_MAX_CMDS * AHCI_CMD_SZ) -#define AHCI_RX_FIS_SZ 256 -#define AHCI_CMD_TBL_CDB 0x40 -#define AHCI_CMD_TBL_HDR_SZ 0x80 -#define AHCI_CMD_TBL_SZ (AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16)) -#define AHCI_CMD_TBL_AR_SZ (AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS) -#define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \ - AHCI_RX_FIS_SZ) - -#define AHCI_IRQ_ON_SG (1 << 31) -#define AHCI_CMD_ATAPI (1 << 5) -#define AHCI_CMD_WRITE (1 << 6) -#define AHCI_CMD_PREFETCH (1 << 7) -#define AHCI_CMD_RESET (1 << 8) -#define AHCI_CMD_CLR_BUSY (1 << 10) - -#define RX_FIS_D2H_REG 0x40 /* offset of D2H Register FIS data */ -#define RX_FIS_SDB 0x58 /* offset of SDB FIS data */ -#define RX_FIS_UNK 0x60 /* offset of Unknown FIS data */ - -/* global controller registers */ -#define HOST_CAP 0x00 /* host capabilities */ -#define HOST_CTL 0x04 /* global host control */ -#define HOST_IRQ_STAT 0x08 /* interrupt status */ -#define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */ -#define HOST_VERSION 0x10 /* AHCI spec. version compliancy */ - -/* HOST_CTL bits */ -#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */ -#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */ -#define HOST_CTL_AHCI_EN (1 << 31) /* AHCI enabled */ - -/* HOST_CAP bits */ -#define HOST_CAP_SSC (1 << 14) /* Slumber capable */ -#define HOST_CAP_AHCI (1 << 18) /* AHCI only */ -#define HOST_CAP_CLO (1 << 24) /* Command List Override support */ -#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */ -#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */ -#define HOST_CAP_64 (1 << 31) /* PCI DAC (64-bit DMA) support */ - -/* registers for each SATA port */ -#define PORT_LST_ADDR 0x00 /* command list DMA addr */ -#define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */ -#define PORT_FIS_ADDR 0x08 /* FIS rx buf addr */ -#define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */ -#define PORT_IRQ_STAT 0x10 /* interrupt status */ -#define PORT_IRQ_MASK 0x14 /* interrupt enable/disable mask */ -#define PORT_CMD 0x18 /* port command */ -#define PORT_TFDATA 0x20 /* taskfile data */ -#define PORT_SIG 0x24 /* device TF signature */ -#define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */ -#define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */ -#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */ -#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */ -#define PORT_CMD_ISSUE 0x38 /* command issue */ -#define PORT_RESERVED 0x3c /* reserved */ - -/* PORT_IRQ_{STAT,MASK} bits */ -#define PORT_IRQ_COLD_PRES (1 << 31) /* cold presence detect */ -#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */ -#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */ -#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */ -#define PORT_IRQ_IF_ERR (1 << 27) /* interface fatal error */ -#define PORT_IRQ_IF_NONFATAL (1 << 26) /* interface non-fatal error */ -#define PORT_IRQ_OVERFLOW (1 << 24) /* xfer exhausted available S/G */ -#define PORT_IRQ_BAD_PMP (1 << 23) /* incorrect port multiplier */ - -#define PORT_IRQ_PHYRDY (1 << 22) /* PhyRdy changed */ -#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */ -#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */ -#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */ -#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */ -#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */ -#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */ -#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */ -#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */ - -#define PORT_IRQ_FREEZE (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | \ - PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | \ - PORT_IRQ_UNK_FIS) -#define PORT_IRQ_ERROR (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | \ - PORT_IRQ_HBUS_DATA_ERR) -#define DEF_PORT_IRQ (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | \ - PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | \ - PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS) - -/* PORT_CMD bits */ -#define PORT_CMD_ATAPI (1 << 24) /* Device is ATAPI */ -#define PORT_CMD_LIST_ON (1 << 15) /* cmd list DMA engine running */ -#define PORT_CMD_FIS_ON (1 << 14) /* FIS DMA engine running */ -#define PORT_CMD_FIS_RX (1 << 4) /* Enable FIS receive DMA engine */ -#define PORT_CMD_CLO (1 << 3) /* Command list override */ -#define PORT_CMD_POWER_ON (1 << 2) /* Power up device */ -#define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */ -#define PORT_CMD_START (1 << 0) /* Enable port DMA engine */ - -#define PORT_CMD_ICC_MASK (0xf << 28) /* i/f ICC state mask */ -#define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */ -#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */ -#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */ - -#define PORT_IRQ_STAT_DHRS (1 << 0) /* Device to Host Register FIS */ -#define PORT_IRQ_STAT_PSS (1 << 1) /* PIO Setup FIS */ -#define PORT_IRQ_STAT_DSS (1 << 2) /* DMA Setup FIS */ -#define PORT_IRQ_STAT_SDBS (1 << 3) /* Set Device Bits */ -#define PORT_IRQ_STAT_UFS (1 << 4) /* Unknown FIS */ -#define PORT_IRQ_STAT_DPS (1 << 5) /* Descriptor Processed */ -#define PORT_IRQ_STAT_PCS (1 << 6) /* Port Connect Change Status */ -#define PORT_IRQ_STAT_DMPS (1 << 7) /* Device Mechanical Presence - Status */ -#define PORT_IRQ_STAT_PRCS (1 << 22) /* File Ready Status */ -#define PORT_IRQ_STAT_IPMS (1 << 23) /* Incorrect Port Multiplier - Status */ -#define PORT_IRQ_STAT_OFS (1 << 24) /* Overflow Status */ -#define PORT_IRQ_STAT_INFS (1 << 26) /* Interface Non-Fatal Error - Status */ -#define PORT_IRQ_STAT_IFS (1 << 27) /* Interface Fatal Error */ -#define PORT_IRQ_STAT_HBDS (1 << 28) /* Host Bus Data Error Status */ -#define PORT_IRQ_STAT_HBFS (1 << 29) /* Host Bus Fatal Error Status */ -#define PORT_IRQ_STAT_TFES (1 << 30) /* Task File Error Status */ -#define PORT_IRQ_STAT_CPDS (1 << 31) /* Code Port Detect Status */ - -/* ap->flags bits */ -#define AHCI_FLAG_NO_NCQ (1 << 24) -#define AHCI_FLAG_IGN_IRQ_IF_ERR (1 << 25) /* ignore IRQ_IF_ERR */ -#define AHCI_FLAG_HONOR_PI (1 << 26) /* honor PORTS_IMPL */ -#define AHCI_FLAG_IGN_SERR_INTERNAL (1 << 27) /* ignore SERR_INTERNAL */ -#define AHCI_FLAG_32BIT_ONLY (1 << 28) /* force 32bit */ - -#define ATA_SRST (1 << 2) /* software reset */ - -#define STATE_RUN 0 -#define STATE_RESET 1 - -#define SATA_SCR_SSTATUS_DET_NODEV 0x0 -#define SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP 0x3 - -#define SATA_SCR_SSTATUS_SPD_NODEV 0x00 -#define SATA_SCR_SSTATUS_SPD_GEN1 0x10 - -#define SATA_SCR_SSTATUS_IPM_NODEV 0x000 -#define SATA_SCR_SSTATUS_IPM_ACTIVE 0X100 - -#define AHCI_SCR_SCTL_DET 0xf - -#define SATA_FIS_TYPE_REGISTER_H2D 0x27 -#define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80 - -#define AHCI_CMD_HDR_CMD_FIS_LEN 0x1f -#define AHCI_CMD_HDR_PRDT_LEN 16 - -#define SATA_SIGNATURE_CDROM 0xeb140000 -#define SATA_SIGNATURE_DISK 0x00000101 - -#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20 - /* Shouldn't this be 0x2c? */ - -#define SATA_PORTS 4 - -#define AHCI_PORT_REGS_START_ADDR 0x100 -#define AHCI_PORT_REGS_END_ADDR (AHCI_PORT_REGS_START_ADDR + SATA_PORTS * 0x80) -#define AHCI_PORT_ADDR_OFFSET_MASK 0x7f - -#define AHCI_NUM_COMMAND_SLOTS 31 -#define AHCI_SUPPORTED_SPEED 20 -#define AHCI_SUPPORTED_SPEED_GEN1 1 -#define AHCI_VERSION_1_0 0x10000 - -#define AHCI_PROGMODE_MAJOR_REV_1 1 - -#define AHCI_COMMAND_TABLE_ACMD 0x40 - -#define IDE_FEATURE_DMA 1 - -#define READ_FPDMA_QUEUED 0x60 -#define WRITE_FPDMA_QUEUED 0x61 - -#define RES_FIS_DSFIS 0x00 -#define RES_FIS_PSFIS 0x20 -#define RES_FIS_RFIS 0x40 -#define RES_FIS_SDBFIS 0x58 -#define RES_FIS_UFIS 0x60 - -typedef struct AHCIControlRegs { - uint32_t cap; - uint32_t ghc; - uint32_t irqstatus; - uint32_t impl; - uint32_t version; -} AHCIControlRegs; - -typedef struct AHCIPortRegs { - uint32_t lst_addr; - uint32_t lst_addr_hi; - uint32_t fis_addr; - uint32_t fis_addr_hi; - uint32_t irq_stat; - uint32_t irq_mask; - uint32_t cmd; - uint32_t unused0; - uint32_t tfdata; - uint32_t sig; - uint32_t scr_stat; - uint32_t scr_ctl; - uint32_t scr_err; - uint32_t scr_act; - uint32_t cmd_issue; - uint32_t reserved; -} AHCIPortRegs; - -typedef struct AHCICmdHdr { - uint32_t opts; - uint32_t status; - uint64_t tbl_addr; - uint32_t reserved[4]; -} __attribute__ ((packed)) AHCICmdHdr; - -typedef struct AHCI_SG { - uint64_t addr; - uint32_t reserved; - uint32_t flags_size; -} __attribute__ ((packed)) AHCI_SG; - -typedef struct AHCIDevice AHCIDevice; - -typedef struct NCQTransferState { - AHCIDevice *drive; - BlockDriverAIOCB *aiocb; - QEMUSGList sglist; - int is_read; - uint16_t sector_count; - uint64_t lba; - uint8_t tag; - int slot; - int used; -} NCQTransferState; - -struct AHCIDevice { - IDEDMA dma; - IDEBus port; - int port_no; - uint32_t port_state; - uint32_t finished; - AHCIPortRegs port_regs; - struct AHCIState *hba; - QEMUBH *check_bh; - uint8_t *lst; - uint8_t *res_fis; - int dma_status; - int done_atapi_packet; - int busy_slot; - BlockDriverCompletionFunc *dma_cb; - AHCICmdHdr *cur_cmd; - NCQTransferState ncq_tfs[AHCI_MAX_CMDS]; -}; - -typedef struct AHCIState { - AHCIDevice dev[SATA_PORTS]; - AHCIControlRegs control_regs; - int mem; - qemu_irq irq; -} AHCIState; - -typedef struct AHCIPCIState { - PCIDevice card; - AHCIState ahci; -} AHCIPCIState; - -typedef struct NCQFrame { - uint8_t fis_type; - uint8_t c; - uint8_t command; - uint8_t sector_count_low; - uint8_t lba0; - uint8_t lba1; - uint8_t lba2; - uint8_t fua; - uint8_t lba3; - uint8_t lba4; - uint8_t lba5; - uint8_t sector_count_high; - uint8_t tag; - uint8_t reserved5; - uint8_t reserved6; - uint8_t control; - uint8_t reserved7; - uint8_t reserved8; - uint8_t reserved9; - uint8_t reserved10; -} __attribute__ ((packed)) NCQFrame; - static void check_cmd(AHCIState *s, int port); static int handle_cmd(AHCIState *s,int port,int slot); static void ahci_reset_port(AHCIState *s, int port); static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis); +static void ahci_init_d2h(AHCIDevice *ad); static uint32_t ahci_port_read(AHCIState *s, int port, int offset) { @@ -482,7 +145,7 @@ static void ahci_check_irq(AHCIState *s) DPRINTF(-1, "check irq %#x\n", s->control_regs.irqstatus); - for (i = 0; i < SATA_PORTS; i++) { + for (i = 0; i < s->ports; i++) { AHCIPortRegs *pr = &s->dev[i].port_regs; if (pr->irq_stat & pr->irq_mask) { s->control_regs.irqstatus |= (1 << i); @@ -568,6 +231,16 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) pr->cmd |= PORT_CMD_FIS_ON; } + /* XXX usually the FIS would be pending on the bus here and + issuing deferred until the OS enables FIS receival. + Instead, we only submit it once - which works in most + cases, but is a hack. */ + if ((pr->cmd & PORT_CMD_FIS_ON) && + !s->dev[port].init_d2h_sent) { + ahci_init_d2h(&s->dev[port]); + s->dev[port].init_d2h_sent = 1; + } + check_cmd(s, port); break; case PORT_TFDATA: @@ -630,7 +303,8 @@ static uint32_t ahci_mem_readl(void *ptr, target_phys_addr_t addr) DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val); } else if ((addr >= AHCI_PORT_REGS_START_ADDR) && - (addr < AHCI_PORT_REGS_END_ADDR)) { + (addr < (AHCI_PORT_REGS_START_ADDR + + (s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) { val = ahci_port_read(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7, addr & AHCI_PORT_ADDR_OFFSET_MASK); } @@ -662,7 +336,7 @@ static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) case HOST_CTL: /* R/W */ if (val & HOST_CTL_RESET) { DPRINTF(-1, "HBA Reset\n"); - /* FIXME reset? */ + ahci_reset(container_of(s, AHCIPCIState, ahci)); } else { s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN; ahci_check_irq(s); @@ -682,7 +356,8 @@ static void ahci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) DPRINTF(-1, "write to unknown register 0x%x\n", (unsigned)addr); } } else if ((addr >= AHCI_PORT_REGS_START_ADDR) && - (addr < AHCI_PORT_REGS_END_ADDR)) { + (addr < (AHCI_PORT_REGS_START_ADDR + + (s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) { ahci_port_write(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7, addr & AHCI_PORT_ADDR_OFFSET_MASK, val); } @@ -705,16 +380,16 @@ static void ahci_reg_init(AHCIState *s) { int i; - s->control_regs.cap = (SATA_PORTS - 1) | + s->control_regs.cap = (s->ports - 1) | (AHCI_NUM_COMMAND_SLOTS << 8) | (AHCI_SUPPORTED_SPEED_GEN1 << AHCI_SUPPORTED_SPEED) | HOST_CAP_NCQ | HOST_CAP_AHCI; - s->control_regs.impl = (1 << SATA_PORTS) - 1; + s->control_regs.impl = (1 << s->ports) - 1; s->control_regs.version = AHCI_VERSION_1_0; - for (i = 0; i < SATA_PORTS; i++) { + for (i = 0; i < s->ports; i++) { s->dev[i].port_state = STATE_RUN; } } @@ -800,12 +475,29 @@ static void ahci_check_cmd_bh(void *opaque) check_cmd(ad->hba, ad->port_no); } +static void ahci_init_d2h(AHCIDevice *ad) +{ + uint8_t init_fis[0x20]; + IDEState *ide_state = &ad->port.ifs[0]; + + memset(init_fis, 0, sizeof(init_fis)); + + init_fis[4] = 1; + init_fis[12] = 1; + + if (ide_state->drive_kind == IDE_CD) { + init_fis[5] = ide_state->lcyl; + init_fis[6] = ide_state->hcyl; + } + + ahci_write_fis_d2h(ad, init_fis); +} + static void ahci_reset_port(AHCIState *s, int port) { AHCIDevice *d = &s->dev[port]; AHCIPortRegs *pr = &d->port_regs; IDEState *ide_state = &d->port.ifs[0]; - uint8_t init_fis[0x20]; int i; DPRINTF(port, "reset port\n"); @@ -820,6 +512,7 @@ static void ahci_reset_port(AHCIState *s, int port) pr->scr_err = 0; pr->scr_act = 0; d->busy_slot = -1; + d->init_d2h_sent = 0; ide_state = &s->dev[port].port.ifs[0]; if (!ide_state->bs) { @@ -842,7 +535,6 @@ static void ahci_reset_port(AHCIState *s, int port) ncq_tfs->used = 0; } - memset(init_fis, 0, sizeof(init_fis)); s->dev[port].port_state = STATE_RUN; if (!ide_state->bs) { s->dev[port].port_regs.sig = 0; @@ -852,8 +544,6 @@ static void ahci_reset_port(AHCIState *s, int port) ide_state->lcyl = 0x14; ide_state->hcyl = 0xeb; DPRINTF(port, "set lcyl = %d\n", ide_state->lcyl); - init_fis[5] = ide_state->lcyl; - init_fis[6] = ide_state->hcyl; ide_state->status = SEEK_STAT | WRERR_STAT | READY_STAT; } else { s->dev[port].port_regs.sig = SATA_SIGNATURE_DISK; @@ -861,9 +551,7 @@ static void ahci_reset_port(AHCIState *s, int port) } ide_state->error = 1; - init_fis[4] = 1; - init_fis[12] = 1; - ahci_write_fis_d2h(d, init_fis); + ahci_init_d2h(d); } static void debug_print_fis(uint8_t *fis, int cmd_len) @@ -1410,17 +1098,19 @@ static const IDEDMAOps ahci_dma_ops = { .reset = ahci_dma_reset, }; -static void ahci_init(AHCIState *s, DeviceState *qdev) +void ahci_init(AHCIState *s, DeviceState *qdev, int ports) { qemu_irq *irqs; int i; + s->ports = ports; + s->dev = qemu_mallocz(sizeof(AHCIDevice) * ports); ahci_reg_init(s); s->mem = cpu_register_io_memory(ahci_readfn, ahci_writefn, s, DEVICE_LITTLE_ENDIAN); - irqs = qemu_allocate_irqs(ahci_irq_set, s, SATA_PORTS); + irqs = qemu_allocate_irqs(ahci_irq_set, s, s->ports); - for (i = 0; i < SATA_PORTS; i++) { + for (i = 0; i < s->ports; i++) { AHCIDevice *ad = &s->dev[i]; ide_bus_new(&ad->port, qdev, i); @@ -1434,7 +1124,12 @@ static void ahci_init(AHCIState *s, DeviceState *qdev) } } -static void ahci_pci_map(PCIDevice *pci_dev, int region_num, +void ahci_uninit(AHCIState *s) +{ + qemu_free(s->dev); +} + +void ahci_pci_map(PCIDevice *pci_dev, int region_num, pcibus_t addr, pcibus_t size, int type) { struct AHCIPCIState *d = (struct AHCIPCIState *)pci_dev; @@ -1443,81 +1138,15 @@ static void ahci_pci_map(PCIDevice *pci_dev, int region_num, cpu_register_physical_memory(addr, size, s->mem); } -static void ahci_reset(void *opaque) +void ahci_reset(void *opaque) { struct AHCIPCIState *d = opaque; int i; - for (i = 0; i < SATA_PORTS; i++) { - ahci_reset_port(&d->ahci, i); - } -} - -static int pci_ahci_init(PCIDevice *dev) -{ - struct AHCIPCIState *d; - d = DO_UPCAST(struct AHCIPCIState, card, dev); - - pci_config_set_vendor_id(d->card.config, PCI_VENDOR_ID_INTEL); - pci_config_set_device_id(d->card.config, PCI_DEVICE_ID_INTEL_82801IR); - - pci_config_set_class(d->card.config, PCI_CLASS_STORAGE_SATA); - pci_config_set_revision(d->card.config, 0x02); - pci_config_set_prog_interface(d->card.config, AHCI_PROGMODE_MAJOR_REV_1); - - d->card.config[PCI_CACHE_LINE_SIZE] = 0x08; /* Cache line size */ - d->card.config[PCI_LATENCY_TIMER] = 0x00; /* Latency timer */ - pci_config_set_interrupt_pin(d->card.config, 1); - - /* XXX Software should program this register */ - d->card.config[0x90] = 1 << 6; /* Address Map Register - AHCI mode */ - - qemu_register_reset(ahci_reset, d); - - /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */ - pci_register_bar(&d->card, 5, 0x1000, PCI_BASE_ADDRESS_SPACE_MEMORY, - ahci_pci_map); - - msi_init(dev, 0x50, 1, true, false); - - ahci_init(&d->ahci, &dev->qdev); - d->ahci.irq = d->card.irq[0]; - - return 0; -} + d->ahci.control_regs.irqstatus = 0; + d->ahci.control_regs.ghc = 0; -static int pci_ahci_uninit(PCIDevice *dev) -{ - struct AHCIPCIState *d; - d = DO_UPCAST(struct AHCIPCIState, card, dev); - - if (msi_enabled(dev)) { - msi_uninit(dev); + for (i = 0; i < d->ahci.ports; i++) { + ahci_reset_port(&d->ahci, i); } - - qemu_unregister_reset(ahci_reset, d); - - return 0; } - -static void pci_ahci_write_config(PCIDevice *pci, uint32_t addr, - uint32_t val, int len) -{ - pci_default_write_config(pci, addr, val, len); - msi_write_config(pci, addr, val, len); -} - -static PCIDeviceInfo ahci_info = { - .qdev.name = "ahci", - .qdev.size = sizeof(AHCIPCIState), - .init = pci_ahci_init, - .exit = pci_ahci_uninit, - .config_write = pci_ahci_write_config, -}; - -static void ahci_pci_register_devices(void) -{ - pci_qdev_register(&ahci_info); -} - -device_init(ahci_pci_register_devices) diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h new file mode 100644 index 000000000..a4560c41b --- /dev/null +++ b/hw/ide/ahci.h @@ -0,0 +1,333 @@ +/* + * QEMU AHCI Emulation + * + * Copyright (c) 2010 qiaochong@loongson.cn + * Copyright (c) 2010 Roland Elek <elek.roland@gmail.com> + * Copyright (c) 2010 Sebastian Herbszt <herbszt@gmx.de> + * Copyright (c) 2010 Alexander Graf <agraf@suse.de> + * + * 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_IDE_AHCI_H +#define HW_IDE_AHCI_H + +#define AHCI_PCI_BAR 5 +#define AHCI_MAX_PORTS 32 +#define AHCI_MAX_SG 168 /* hardware max is 64K */ +#define AHCI_DMA_BOUNDARY 0xffffffff +#define AHCI_USE_CLUSTERING 0 +#define AHCI_MAX_CMDS 32 +#define AHCI_CMD_SZ 32 +#define AHCI_CMD_SLOT_SZ (AHCI_MAX_CMDS * AHCI_CMD_SZ) +#define AHCI_RX_FIS_SZ 256 +#define AHCI_CMD_TBL_CDB 0x40 +#define AHCI_CMD_TBL_HDR_SZ 0x80 +#define AHCI_CMD_TBL_SZ (AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16)) +#define AHCI_CMD_TBL_AR_SZ (AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS) +#define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \ + AHCI_RX_FIS_SZ) + +#define AHCI_IRQ_ON_SG (1 << 31) +#define AHCI_CMD_ATAPI (1 << 5) +#define AHCI_CMD_WRITE (1 << 6) +#define AHCI_CMD_PREFETCH (1 << 7) +#define AHCI_CMD_RESET (1 << 8) +#define AHCI_CMD_CLR_BUSY (1 << 10) + +#define RX_FIS_D2H_REG 0x40 /* offset of D2H Register FIS data */ +#define RX_FIS_SDB 0x58 /* offset of SDB FIS data */ +#define RX_FIS_UNK 0x60 /* offset of Unknown FIS data */ + +/* global controller registers */ +#define HOST_CAP 0x00 /* host capabilities */ +#define HOST_CTL 0x04 /* global host control */ +#define HOST_IRQ_STAT 0x08 /* interrupt status */ +#define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */ +#define HOST_VERSION 0x10 /* AHCI spec. version compliancy */ + +/* HOST_CTL bits */ +#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */ +#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */ +#define HOST_CTL_AHCI_EN (1 << 31) /* AHCI enabled */ + +/* HOST_CAP bits */ +#define HOST_CAP_SSC (1 << 14) /* Slumber capable */ +#define HOST_CAP_AHCI (1 << 18) /* AHCI only */ +#define HOST_CAP_CLO (1 << 24) /* Command List Override support */ +#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */ +#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */ +#define HOST_CAP_64 (1 << 31) /* PCI DAC (64-bit DMA) support */ + +/* registers for each SATA port */ +#define PORT_LST_ADDR 0x00 /* command list DMA addr */ +#define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */ +#define PORT_FIS_ADDR 0x08 /* FIS rx buf addr */ +#define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */ +#define PORT_IRQ_STAT 0x10 /* interrupt status */ +#define PORT_IRQ_MASK 0x14 /* interrupt enable/disable mask */ +#define PORT_CMD 0x18 /* port command */ +#define PORT_TFDATA 0x20 /* taskfile data */ +#define PORT_SIG 0x24 /* device TF signature */ +#define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */ +#define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */ +#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */ +#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */ +#define PORT_CMD_ISSUE 0x38 /* command issue */ +#define PORT_RESERVED 0x3c /* reserved */ + +/* PORT_IRQ_{STAT,MASK} bits */ +#define PORT_IRQ_COLD_PRES (1 << 31) /* cold presence detect */ +#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */ +#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */ +#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */ +#define PORT_IRQ_IF_ERR (1 << 27) /* interface fatal error */ +#define PORT_IRQ_IF_NONFATAL (1 << 26) /* interface non-fatal error */ +#define PORT_IRQ_OVERFLOW (1 << 24) /* xfer exhausted available S/G */ +#define PORT_IRQ_BAD_PMP (1 << 23) /* incorrect port multiplier */ + +#define PORT_IRQ_PHYRDY (1 << 22) /* PhyRdy changed */ +#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */ +#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */ +#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */ +#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */ +#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */ +#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */ +#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */ +#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */ + +#define PORT_IRQ_FREEZE (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | \ + PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | \ + PORT_IRQ_UNK_FIS) +#define PORT_IRQ_ERROR (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | \ + PORT_IRQ_HBUS_DATA_ERR) +#define DEF_PORT_IRQ (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | \ + PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | \ + PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS) + +/* PORT_CMD bits */ +#define PORT_CMD_ATAPI (1 << 24) /* Device is ATAPI */ +#define PORT_CMD_LIST_ON (1 << 15) /* cmd list DMA engine running */ +#define PORT_CMD_FIS_ON (1 << 14) /* FIS DMA engine running */ +#define PORT_CMD_FIS_RX (1 << 4) /* Enable FIS receive DMA engine */ +#define PORT_CMD_CLO (1 << 3) /* Command list override */ +#define PORT_CMD_POWER_ON (1 << 2) /* Power up device */ +#define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */ +#define PORT_CMD_START (1 << 0) /* Enable port DMA engine */ + +#define PORT_CMD_ICC_MASK (0xf << 28) /* i/f ICC state mask */ +#define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */ +#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */ +#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */ + +#define PORT_IRQ_STAT_DHRS (1 << 0) /* Device to Host Register FIS */ +#define PORT_IRQ_STAT_PSS (1 << 1) /* PIO Setup FIS */ +#define PORT_IRQ_STAT_DSS (1 << 2) /* DMA Setup FIS */ +#define PORT_IRQ_STAT_SDBS (1 << 3) /* Set Device Bits */ +#define PORT_IRQ_STAT_UFS (1 << 4) /* Unknown FIS */ +#define PORT_IRQ_STAT_DPS (1 << 5) /* Descriptor Processed */ +#define PORT_IRQ_STAT_PCS (1 << 6) /* Port Connect Change Status */ +#define PORT_IRQ_STAT_DMPS (1 << 7) /* Device Mechanical Presence + Status */ +#define PORT_IRQ_STAT_PRCS (1 << 22) /* File Ready Status */ +#define PORT_IRQ_STAT_IPMS (1 << 23) /* Incorrect Port Multiplier + Status */ +#define PORT_IRQ_STAT_OFS (1 << 24) /* Overflow Status */ +#define PORT_IRQ_STAT_INFS (1 << 26) /* Interface Non-Fatal Error + Status */ +#define PORT_IRQ_STAT_IFS (1 << 27) /* Interface Fatal Error */ +#define PORT_IRQ_STAT_HBDS (1 << 28) /* Host Bus Data Error Status */ +#define PORT_IRQ_STAT_HBFS (1 << 29) /* Host Bus Fatal Error Status */ +#define PORT_IRQ_STAT_TFES (1 << 30) /* Task File Error Status */ +#define PORT_IRQ_STAT_CPDS (1 << 31) /* Code Port Detect Status */ + +/* ap->flags bits */ +#define AHCI_FLAG_NO_NCQ (1 << 24) +#define AHCI_FLAG_IGN_IRQ_IF_ERR (1 << 25) /* ignore IRQ_IF_ERR */ +#define AHCI_FLAG_HONOR_PI (1 << 26) /* honor PORTS_IMPL */ +#define AHCI_FLAG_IGN_SERR_INTERNAL (1 << 27) /* ignore SERR_INTERNAL */ +#define AHCI_FLAG_32BIT_ONLY (1 << 28) /* force 32bit */ + +#define ATA_SRST (1 << 2) /* software reset */ + +#define STATE_RUN 0 +#define STATE_RESET 1 + +#define SATA_SCR_SSTATUS_DET_NODEV 0x0 +#define SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP 0x3 + +#define SATA_SCR_SSTATUS_SPD_NODEV 0x00 +#define SATA_SCR_SSTATUS_SPD_GEN1 0x10 + +#define SATA_SCR_SSTATUS_IPM_NODEV 0x000 +#define SATA_SCR_SSTATUS_IPM_ACTIVE 0X100 + +#define AHCI_SCR_SCTL_DET 0xf + +#define SATA_FIS_TYPE_REGISTER_H2D 0x27 +#define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80 + +#define AHCI_CMD_HDR_CMD_FIS_LEN 0x1f +#define AHCI_CMD_HDR_PRDT_LEN 16 + +#define SATA_SIGNATURE_CDROM 0xeb140000 +#define SATA_SIGNATURE_DISK 0x00000101 + +#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20 + /* Shouldn't this be 0x2c? */ + +#define AHCI_PORT_REGS_START_ADDR 0x100 +#define AHCI_PORT_ADDR_OFFSET_MASK 0x7f +#define AHCI_PORT_ADDR_OFFSET_LEN 0x80 + +#define AHCI_NUM_COMMAND_SLOTS 31 +#define AHCI_SUPPORTED_SPEED 20 +#define AHCI_SUPPORTED_SPEED_GEN1 1 +#define AHCI_VERSION_1_0 0x10000 + +#define AHCI_PROGMODE_MAJOR_REV_1 1 + +#define AHCI_COMMAND_TABLE_ACMD 0x40 + +#define IDE_FEATURE_DMA 1 + +#define READ_FPDMA_QUEUED 0x60 +#define WRITE_FPDMA_QUEUED 0x61 + +#define RES_FIS_DSFIS 0x00 +#define RES_FIS_PSFIS 0x20 +#define RES_FIS_RFIS 0x40 +#define RES_FIS_SDBFIS 0x58 +#define RES_FIS_UFIS 0x60 + +typedef struct AHCIControlRegs { + uint32_t cap; + uint32_t ghc; + uint32_t irqstatus; + uint32_t impl; + uint32_t version; +} AHCIControlRegs; + +typedef struct AHCIPortRegs { + uint32_t lst_addr; + uint32_t lst_addr_hi; + uint32_t fis_addr; + uint32_t fis_addr_hi; + uint32_t irq_stat; + uint32_t irq_mask; + uint32_t cmd; + uint32_t unused0; + uint32_t tfdata; + uint32_t sig; + uint32_t scr_stat; + uint32_t scr_ctl; + uint32_t scr_err; + uint32_t scr_act; + uint32_t cmd_issue; + uint32_t reserved; +} AHCIPortRegs; + +typedef struct AHCICmdHdr { + uint32_t opts; + uint32_t status; + uint64_t tbl_addr; + uint32_t reserved[4]; +} __attribute__ ((packed)) AHCICmdHdr; + +typedef struct AHCI_SG { + uint64_t addr; + uint32_t reserved; + uint32_t flags_size; +} __attribute__ ((packed)) AHCI_SG; + +typedef struct AHCIDevice AHCIDevice; + +typedef struct NCQTransferState { + AHCIDevice *drive; + BlockDriverAIOCB *aiocb; + QEMUSGList sglist; + int is_read; + uint16_t sector_count; + uint64_t lba; + uint8_t tag; + int slot; + int used; +} NCQTransferState; + +struct AHCIDevice { + IDEDMA dma; + IDEBus port; + int port_no; + uint32_t port_state; + uint32_t finished; + AHCIPortRegs port_regs; + struct AHCIState *hba; + QEMUBH *check_bh; + uint8_t *lst; + uint8_t *res_fis; + int dma_status; + int done_atapi_packet; + int busy_slot; + int init_d2h_sent; + BlockDriverCompletionFunc *dma_cb; + AHCICmdHdr *cur_cmd; + NCQTransferState ncq_tfs[AHCI_MAX_CMDS]; +}; + +typedef struct AHCIState { + AHCIDevice *dev; + AHCIControlRegs control_regs; + int mem; + int ports; + qemu_irq irq; +} AHCIState; + +typedef struct AHCIPCIState { + PCIDevice card; + AHCIState ahci; +} AHCIPCIState; + +typedef struct NCQFrame { + uint8_t fis_type; + uint8_t c; + uint8_t command; + uint8_t sector_count_low; + uint8_t lba0; + uint8_t lba1; + uint8_t lba2; + uint8_t fua; + uint8_t lba3; + uint8_t lba4; + uint8_t lba5; + uint8_t sector_count_high; + uint8_t tag; + uint8_t reserved5; + uint8_t reserved6; + uint8_t control; + uint8_t reserved7; + uint8_t reserved8; + uint8_t reserved9; + uint8_t reserved10; +} __attribute__ ((packed)) NCQFrame; + +void ahci_init(AHCIState *s, DeviceState *qdev, int ports); +void ahci_uninit(AHCIState *s); + +void ahci_pci_map(PCIDevice *pci_dev, int region_num, + pcibus_t addr, pcibus_t size, int type); + +void ahci_reset(void *opaque); + +#endif /* HW_IDE_AHCI_H */ diff --git a/hw/ide/ich.c b/hw/ide/ich.c new file mode 100644 index 000000000..f242d7a81 --- /dev/null +++ b/hw/ide/ich.c @@ -0,0 +1,148 @@ +/* + * QEMU ICH Emulation + * + * Copyright (c) 2010 Sebastian Herbszt <herbszt@gmx.de> + * Copyright (c) 2010 Alexander Graf <agraf@suse.de> + * + * 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/>. + * + * + * lspci dump of a ICH-9 real device + * + * 00:1f.2 SATA controller [0106]: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922] (rev 02) (prog-if 01 [AHCI 1.0]) + * Subsystem: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA AHCI Controller [8086:2922] + * Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+ + * Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx- + * Latency: 0 + * Interrupt: pin B routed to IRQ 222 + * Region 0: I/O ports at d000 [size=8] + * Region 1: I/O ports at cc00 [size=4] + * Region 2: I/O ports at c880 [size=8] + * Region 3: I/O ports at c800 [size=4] + * Region 4: I/O ports at c480 [size=32] + * Region 5: Memory at febf9000 (32-bit, non-prefetchable) [size=2K] + * Capabilities: [80] Message Signalled Interrupts: Mask- 64bit- Count=1/16 Enable+ + * Address: fee0f00c Data: 41d9 + * Capabilities: [70] Power Management version 3 + * Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot+,D3cold-) + * Status: D0 PME-Enable- DSel=0 DScale=0 PME- + * Capabilities: [a8] SATA HBA <?> + * Capabilities: [b0] Vendor Specific Information <?> + * Kernel driver in use: ahci + * Kernel modules: ahci + * 00: 86 80 22 29 07 04 b0 02 02 01 06 01 00 00 00 00 + * 10: 01 d0 00 00 01 cc 00 00 81 c8 00 00 01 c8 00 00 + * 20: 81 c4 00 00 00 90 bf fe 00 00 00 00 86 80 22 29 + * 30: 00 00 00 00 80 00 00 00 00 00 00 00 0f 02 00 00 + * 40: 00 80 00 80 00 00 00 00 00 00 00 00 00 00 00 00 + * 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * 70: 01 a8 03 40 08 00 00 00 00 00 00 00 00 00 00 00 + * 80: 05 70 09 00 0c f0 e0 fe d9 41 00 00 00 00 00 00 + * 90: 40 00 0f 82 93 01 00 00 00 00 00 00 00 00 00 00 + * a0: ac 00 00 00 0a 00 12 00 12 b0 10 00 48 00 00 00 + * b0: 09 00 06 20 00 00 00 00 00 00 00 00 00 00 00 00 + * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * f0: 00 00 00 00 00 00 00 00 86 0f 02 00 00 00 00 00 + * + */ + +#include <hw/hw.h> +#include <hw/msi.h> +#include <hw/pc.h> +#include <hw/pci.h> +#include <hw/isa.h> +#include "block.h" +#include "block_int.h" +#include "sysemu.h" +#include "dma.h" + +#include <hw/ide/pci.h> +#include <hw/ide/ahci.h> + +static int pci_ich9_ahci_init(PCIDevice *dev) +{ + struct AHCIPCIState *d; + d = DO_UPCAST(struct AHCIPCIState, card, dev); + + pci_config_set_vendor_id(d->card.config, PCI_VENDOR_ID_INTEL); + pci_config_set_device_id(d->card.config, PCI_DEVICE_ID_INTEL_82801IR); + + pci_config_set_class(d->card.config, PCI_CLASS_STORAGE_SATA); + pci_config_set_revision(d->card.config, 0x02); + pci_config_set_prog_interface(d->card.config, AHCI_PROGMODE_MAJOR_REV_1); + + d->card.config[PCI_CACHE_LINE_SIZE] = 0x08; /* Cache line size */ + d->card.config[PCI_LATENCY_TIMER] = 0x00; /* Latency timer */ + pci_config_set_interrupt_pin(d->card.config, 1); + + /* XXX Software should program this register */ + d->card.config[0x90] = 1 << 6; /* Address Map Register - AHCI mode */ + + qemu_register_reset(ahci_reset, d); + + /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */ + pci_register_bar(&d->card, 5, 0x1000, PCI_BASE_ADDRESS_SPACE_MEMORY, + ahci_pci_map); + + msi_init(dev, 0x50, 1, true, false); + + ahci_init(&d->ahci, &dev->qdev, 6); + d->ahci.irq = d->card.irq[0]; + + return 0; +} + +static int pci_ich9_uninit(PCIDevice *dev) +{ + struct AHCIPCIState *d; + d = DO_UPCAST(struct AHCIPCIState, card, dev); + + if (msi_enabled(dev)) { + msi_uninit(dev); + } + + qemu_unregister_reset(ahci_reset, d); + ahci_uninit(&d->ahci); + + return 0; +} + +static void pci_ich9_write_config(PCIDevice *pci, uint32_t addr, + uint32_t val, int len) +{ + pci_default_write_config(pci, addr, val, len); + msi_write_config(pci, addr, val, len); +} + +static PCIDeviceInfo ich_ahci_info[] = { + { + .qdev.name = "ich9-ahci", + .qdev.alias = "ahci", + .qdev.size = sizeof(AHCIPCIState), + .init = pci_ich9_ahci_init, + .exit = pci_ich9_uninit, + .config_write = pci_ich9_write_config, + },{ + /* end of list */ + } +}; + +static void ich_ahci_register(void) +{ + pci_qdev_register_many(ich_ahci_info); +} +device_init(ich_ahci_register); diff --git a/hw/ioapic.c b/hw/ioapic.c index aeb3653e7..8fab34f71 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -25,6 +25,7 @@ #include "apic.h" #include "sysemu.h" #include "apic.h" +#include "ioapic.h" #include "qemu-timer.h" #include "host-utils.h" #include "sysbus.h" @@ -41,19 +42,50 @@ #endif #define IOAPIC_DEFAULT_BASE_ADDRESS 0xfec00000 -#define IOAPIC_LVT_MASKED (1<<16) +#define MAX_IOAPICS 1 -#define IOAPIC_TRIGGER_EDGE 0 -#define IOAPIC_TRIGGER_LEVEL 1 +#define IOAPIC_VERSION 0x11 + +#define IOAPIC_LVT_DEST_SHIFT 56 +#define IOAPIC_LVT_MASKED_SHIFT 16 +#define IOAPIC_LVT_TRIGGER_MODE_SHIFT 15 +#define IOAPIC_LVT_REMOTE_IRR_SHIFT 14 +#define IOAPIC_LVT_POLARITY_SHIFT 13 +#define IOAPIC_LVT_DELIV_STATUS_SHIFT 12 +#define IOAPIC_LVT_DEST_MODE_SHIFT 11 +#define IOAPIC_LVT_DELIV_MODE_SHIFT 8 + +#define IOAPIC_LVT_MASKED (1 << IOAPIC_LVT_MASKED_SHIFT) +#define IOAPIC_LVT_REMOTE_IRR (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT) + +#define IOAPIC_TRIGGER_EDGE 0 +#define IOAPIC_TRIGGER_LEVEL 1 /*io{apic,sapic} delivery mode*/ -#define IOAPIC_DM_FIXED 0x0 -#define IOAPIC_DM_LOWEST_PRIORITY 0x1 -#define IOAPIC_DM_PMI 0x2 -#define IOAPIC_DM_NMI 0x4 -#define IOAPIC_DM_INIT 0x5 -#define IOAPIC_DM_SIPI 0x5 -#define IOAPIC_DM_EXTINT 0x7 +#define IOAPIC_DM_FIXED 0x0 +#define IOAPIC_DM_LOWEST_PRIORITY 0x1 +#define IOAPIC_DM_PMI 0x2 +#define IOAPIC_DM_NMI 0x4 +#define IOAPIC_DM_INIT 0x5 +#define IOAPIC_DM_SIPI 0x6 +#define IOAPIC_DM_EXTINT 0x7 +#define IOAPIC_DM_MASK 0x7 + +#define IOAPIC_VECTOR_MASK 0xff + +#define IOAPIC_IOREGSEL 0x00 +#define IOAPIC_IOWIN 0x10 + +#define IOAPIC_REG_ID 0x00 +#define IOAPIC_REG_VER 0x01 +#define IOAPIC_REG_ARB 0x02 +#define IOAPIC_REG_REDTBL_BASE 0x10 +#define IOAPIC_ID 0x00 + +#define IOAPIC_ID_SHIFT 24 +#define IOAPIC_ID_MASK 0xf + +#define IOAPIC_VER_ENTRIES_SHIFT 16 typedef struct IOAPICState IOAPICState; @@ -62,11 +94,12 @@ struct IOAPICState { uint8_t id; uint8_t ioregsel; uint64_t base_address; - uint32_t irr; uint64_t ioredtbl[IOAPIC_NUM_PINS]; }; +static IOAPICState *ioapics[MAX_IOAPICS]; + static void ioapic_service(IOAPICState *s) { uint8_t i; @@ -84,18 +117,22 @@ static void ioapic_service(IOAPICState *s) if (s->irr & mask) { entry = s->ioredtbl[i]; if (!(entry & IOAPIC_LVT_MASKED)) { - trig_mode = ((entry >> 15) & 1); - dest = entry >> 56; - dest_mode = (entry >> 11) & 1; - delivery_mode = (entry >> 8) & 7; - polarity = (entry >> 13) & 1; - if (trig_mode == IOAPIC_TRIGGER_EDGE) + trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1); + dest = entry >> IOAPIC_LVT_DEST_SHIFT; + dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1; + delivery_mode = + (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK; + polarity = (entry >> IOAPIC_LVT_POLARITY_SHIFT) & 1; + if (trig_mode == IOAPIC_TRIGGER_EDGE) { s->irr &= ~mask; - if (delivery_mode == IOAPIC_DM_EXTINT) + } else { + s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR; + } + if (delivery_mode == IOAPIC_DM_EXTINT) { vector = pic_read_irq(isa_pic); - else - vector = entry & 0xff; - + } else { + vector = entry & IOAPIC_VECTOR_MASK; + } apic_deliver_irq(dest, dest_mode, delivery_mode, vector, polarity, trig_mode); } @@ -111,16 +148,16 @@ static void ioapic_set_irq(void *opaque, int vector, int level) * to GSI 2. GSI maps to ioapic 1-1. This is not * the cleanest way of doing it but it should work. */ - DPRINTF("%s: %s vec %x\n", __func__, level? "raise" : "lower", vector); + DPRINTF("%s: %s vec %x\n", __func__, level ? "raise" : "lower", vector); if (vector == 0 && irq0override) { vector = 2; } - if (vector >= 0 && vector < IOAPIC_NUM_PINS) { uint32_t mask = 1 << vector; uint64_t entry = s->ioredtbl[vector]; - if ((entry >> 15) & 1) { + if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) == + IOAPIC_TRIGGER_LEVEL) { /* level triggered */ if (level) { s->irr |= mask; @@ -138,71 +175,101 @@ static void ioapic_set_irq(void *opaque, int vector, int level) } } +void ioapic_eoi_broadcast(int vector) +{ + IOAPICState *s; + uint64_t entry; + int i, n; + + for (i = 0; i < MAX_IOAPICS; i++) { + s = ioapics[i]; + if (!s) { + continue; + } + for (n = 0; n < IOAPIC_NUM_PINS; n++) { + entry = s->ioredtbl[n]; + if ((entry & IOAPIC_LVT_REMOTE_IRR) + && (entry & IOAPIC_VECTOR_MASK) == vector) { + s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR; + if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) { + ioapic_service(s); + } + } + } + } +} + static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr) { IOAPICState *s = opaque; int index; uint32_t val = 0; - addr &= 0xff; - if (addr == 0x00) { + switch (addr & 0xff) { + case IOAPIC_IOREGSEL: val = s->ioregsel; - } else if (addr == 0x10) { + break; + case IOAPIC_IOWIN: switch (s->ioregsel) { - case 0x00: - val = s->id << 24; - break; - case 0x01: - val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */ - break; - case 0x02: - val = 0; - break; - default: - index = (s->ioregsel - 0x10) >> 1; - if (index >= 0 && index < IOAPIC_NUM_PINS) { - if (s->ioregsel & 1) - val = s->ioredtbl[index] >> 32; - else - val = s->ioredtbl[index] & 0xffffffff; + case IOAPIC_REG_ID: + val = s->id << IOAPIC_ID_SHIFT; + break; + case IOAPIC_REG_VER: + val = IOAPIC_VERSION | + ((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT); + break; + case IOAPIC_REG_ARB: + val = 0; + break; + default: + index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1; + if (index >= 0 && index < IOAPIC_NUM_PINS) { + if (s->ioregsel & 1) { + val = s->ioredtbl[index] >> 32; + } else { + val = s->ioredtbl[index] & 0xffffffff; } + } } DPRINTF("read: %08x = %08x\n", s->ioregsel, val); + break; } return val; } -static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +static void +ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { IOAPICState *s = opaque; int index; - addr &= 0xff; - if (addr == 0x00) { + switch (addr & 0xff) { + case IOAPIC_IOREGSEL: s->ioregsel = val; - return; - } else if (addr == 0x10) { + break; + case IOAPIC_IOWIN: DPRINTF("write: %08x = %08x\n", s->ioregsel, val); switch (s->ioregsel) { - case 0x00: - s->id = (val >> 24) & 0xff; - return; - case 0x01: - case 0x02: - return; - default: - index = (s->ioregsel - 0x10) >> 1; - if (index >= 0 && index < IOAPIC_NUM_PINS) { - if (s->ioregsel & 1) { - s->ioredtbl[index] &= 0xffffffff; - s->ioredtbl[index] |= (uint64_t)val << 32; - } else { - s->ioredtbl[index] &= ~0xffffffffULL; - s->ioredtbl[index] |= val; - } - ioapic_service(s); + case IOAPIC_REG_ID: + s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK; + break; + case IOAPIC_REG_VER: + case IOAPIC_REG_ARB: + break; + default: + index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1; + if (index >= 0 && index < IOAPIC_NUM_PINS) { + if (s->ioregsel & 1) { + s->ioredtbl[index] &= 0xffffffff; + s->ioredtbl[index] |= (uint64_t)val << 32; + } else { + s->ioredtbl[index] &= ~0xffffffffULL; + s->ioredtbl[index] |= val; } + ioapic_service(s); + } } + break; } } @@ -272,21 +339,27 @@ static int ioapic_post_load(void *opaque, int version_id) { IOAPICState *s = opaque; + if (version_id == 1) { + /* set sane value */ + s->irr = 0; + } + if (kvm_enabled() && kvm_irqchip_in_kernel()) { kvm_kernel_ioapic_load_from_user(s); } + return 0; } static const VMStateDescription vmstate_ioapic = { .name = "ioapic", - .version_id = 2, + .version_id = 3, + .post_load = ioapic_post_load, .minimum_version_id = 1, .minimum_version_id_old = 1, .pre_load = ioapic_pre_load, - .post_load = ioapic_post_load, .pre_save = ioapic_pre_save, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(id, IOAPICState), VMSTATE_UINT8(ioregsel, IOAPICState), VMSTATE_UINT64_V(base_address, IOAPICState, 2), @@ -305,8 +378,9 @@ static void ioapic_reset(DeviceState *d) s->id = 0; s->ioregsel = 0; s->irr = 0; - for(i = 0; i < IOAPIC_NUM_PINS; i++) - s->ioredtbl[i] = 1 << 16; /* mask LVT */ + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT; + } #ifdef KVM_CAP_IRQCHIP if (kvm_enabled() && kvm_irqchip_in_kernel()) { kvm_kernel_ioapic_load_from_user(s); @@ -330,6 +404,11 @@ static int ioapic_init1(SysBusDevice *dev) { IOAPICState *s = FROM_SYSBUS(IOAPICState, dev); int io_memory; + static int ioapic_no; + + if (ioapic_no >= MAX_IOAPICS) { + return -1; + } io_memory = cpu_register_io_memory(ioapic_mem_read, ioapic_mem_write, s, @@ -338,6 +417,8 @@ static int ioapic_init1(SysBusDevice *dev) qdev_init_gpio_in(&dev->qdev, ioapic_set_irq, IOAPIC_NUM_PINS); + ioapics[ioapic_no++] = s; + return 0; } diff --git a/hw/ioapic.h b/hw/ioapic.h new file mode 100644 index 000000000..cb2642ae5 --- /dev/null +++ b/hw/ioapic.h @@ -0,0 +1,20 @@ +/* + * ioapic.c IOAPIC emulation logic + * + * Copyright (c) 2011 Jan Kiszka, Siemens AG + * + * 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/>. + */ + +void ioapic_eoi_broadcast(int vector); diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index 2f0d15989..4385aa2e7 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -148,7 +148,7 @@ void drive_hot_add(Monitor *mon, const QDict *qdict) err: if (dinfo) - drive_uninit(dinfo); + drive_put_ref(dinfo); return; } diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index 09e22aa44..e05ab5e60 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -117,6 +117,9 @@ static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev) { VirtQueueElement elem; + if (!virtio_queue_ready(vq)) { + return; + } while (virtqueue_pop(vq, &elem)) { virtqueue_push(vq, &elem, 0); } diff --git a/qemu-doc.texi b/qemu-doc.texi index 22a8663f6..86e017ccf 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -407,6 +407,7 @@ snapshots. * host_drives:: Using host drives * disk_images_fat_images:: Virtual FAT disk images * disk_images_nbd:: NBD access +* disk_images_sheepdog:: Sheepdog disk images @end menu @node disk_images_quickstart @@ -630,6 +631,57 @@ qemu -cdrom nbd:localhost:exportname=debian-500-ppc-netinst qemu -cdrom nbd:localhost:exportname=openSUSE-11.1-ppc-netinst @end example +@node disk_images_sheepdog +@subsection Sheepdog disk images + +Sheepdog is a distributed storage system for QEMU. It provides highly +available block level storage volumes that can be attached to +QEMU-based virtual machines. + +You can create a Sheepdog disk image with the command: +@example +qemu-img create sheepdog:@var{image} @var{size} +@end example +where @var{image} is the Sheepdog image name and @var{size} is its +size. + +To import the existing @var{filename} to Sheepdog, you can use a +convert command. +@example +qemu-img convert @var{filename} sheepdog:@var{image} +@end example + +You can boot from the Sheepdog disk image with the command: +@example +qemu sheepdog:@var{image} +@end example + +You can also create a snapshot of the Sheepdog image like qcow2. +@example +qemu-img snapshot -c @var{tag} sheepdog:@var{image} +@end example +where @var{tag} is a tag name of the newly created snapshot. + +To boot from the Sheepdog snapshot, specify the tag name of the +snapshot. +@example +qemu sheepdog:@var{image}:@var{tag} +@end example + +You can create a cloned image from the existing snapshot. +@example +qemu-img create -b sheepdog:@var{base}:@var{tag} sheepdog:@var{image} +@end example +where @var{base} is a image name of the source snapshot and @var{tag} +is its tag name. + +If the Sheepdog daemon doesn't run on the local host, you need to +specify one of the Sheepdog servers to connect to. +@example +qemu-img create sheepdog:@var{hostname}:@var{port}:@var{image} @var{size} +qemu sheepdog:@var{hostname}:@var{port}:@var{image} +@end example + @node pcsys_network @section Network emulation diff --git a/qemu-timer.c b/qemu-timer.c index c25070660..218a2a3d8 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -197,8 +197,8 @@ static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t) t->rearm(t); } -/* TODO: MIN_TIMER_REARM_US should be optimized */ -#define MIN_TIMER_REARM_US 250 +/* TODO: MIN_TIMER_REARM_NS should be optimized */ +#define MIN_TIMER_REARM_NS 250000 #ifdef _WIN32 @@ -635,6 +635,8 @@ void qemu_run_all_timers(void) qemu_run_timers(host_clock); } +static int64_t qemu_next_alarm_deadline(void); + #ifdef _WIN32 static void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, @@ -677,14 +679,7 @@ static void host_alarm_handler(int host_signum) } #endif if (alarm_has_dynticks(t) || - (!use_icount && - qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL], - qemu_get_clock(vm_clock))) || - qemu_timer_expired(active_timers[QEMU_CLOCK_REALTIME], - qemu_get_clock(rt_clock)) || - qemu_timer_expired(active_timers[QEMU_CLOCK_HOST], - qemu_get_clock(host_clock))) { - + qemu_next_alarm_deadline () <= 0) { t->expired = alarm_has_dynticks(t); t->pending = 1; qemu_notify_event(); @@ -698,11 +693,11 @@ int64_t qemu_next_deadline(void) if (active_timers[QEMU_CLOCK_VIRTUAL]) { delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time - - qemu_get_clock(vm_clock); + qemu_get_clock_ns(vm_clock); } if (active_timers[QEMU_CLOCK_HOST]) { int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time - - qemu_get_clock(host_clock); + qemu_get_clock_ns(host_clock); if (hdelta < delta) delta = hdelta; } @@ -713,35 +708,37 @@ int64_t qemu_next_deadline(void) return delta; } -#ifndef _WIN32 - -#if defined(__linux__) - -#define RTC_FREQ 1024 - -static uint64_t qemu_next_deadline_dyntick(void) +static int64_t qemu_next_alarm_deadline(void) { int64_t delta; int64_t rtdelta; - if (use_icount) + if (!use_icount && active_timers[QEMU_CLOCK_VIRTUAL]) { + delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time - + qemu_get_clock(vm_clock); + } else { delta = INT32_MAX; - else - delta = (qemu_next_deadline() + 999) / 1000; - + } + if (active_timers[QEMU_CLOCK_HOST]) { + int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time - + qemu_get_clock_ns(host_clock); + if (hdelta < delta) + delta = hdelta; + } if (active_timers[QEMU_CLOCK_REALTIME]) { - rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time - - qemu_get_clock(rt_clock))*1000; + rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time * 1000000 - + qemu_get_clock_ns(rt_clock)); if (rtdelta < delta) delta = rtdelta; } - if (delta < MIN_TIMER_REARM_US) - delta = MIN_TIMER_REARM_US; - return delta; } +#if defined(__linux__) + +#define RTC_FREQ 1024 + static void enable_sigio_timer(int fd) { struct sigaction act; @@ -887,8 +884,8 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t) { timer_t host_timer = (timer_t)(long)t->priv; struct itimerspec timeout; - int64_t nearest_delta_us = INT64_MAX; - int64_t current_us; + int64_t nearest_delta_ns = INT64_MAX; + int64_t current_ns; assert(alarm_has_dynticks(t)); if (!active_timers[QEMU_CLOCK_REALTIME] && @@ -896,7 +893,9 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t) !active_timers[QEMU_CLOCK_HOST]) return; - nearest_delta_us = qemu_next_deadline_dyntick(); + nearest_delta_ns = qemu_next_alarm_deadline(); + if (nearest_delta_ns < MIN_TIMER_REARM_NS) + nearest_delta_ns = MIN_TIMER_REARM_NS; /* check whether a timer is already running */ if (timer_gettime(host_timer, &timeout)) { @@ -904,14 +903,14 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t) fprintf(stderr, "Internal timer error: aborting\n"); exit(1); } - current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000; - if (current_us && current_us <= nearest_delta_us) + current_ns = timeout.it_value.tv_sec * 1000000000LL + timeout.it_value.tv_nsec; + if (current_ns && current_ns <= nearest_delta_ns) return; timeout.it_interval.tv_sec = 0; timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */ - timeout.it_value.tv_sec = nearest_delta_us / 1000000; - timeout.it_value.tv_nsec = (nearest_delta_us % 1000000) * 1000; + timeout.it_value.tv_sec = nearest_delta_ns / 1000000000; + timeout.it_value.tv_nsec = nearest_delta_ns % 1000000000; if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) { perror("settime"); fprintf(stderr, "Internal timer error: aborting\n"); @@ -921,6 +920,8 @@ static void dynticks_rearm_timer(struct qemu_alarm_timer *t) #endif /* defined(__linux__) */ +#if !defined(_WIN32) + static int unix_start_timer(struct qemu_alarm_timer *t) { struct sigaction act; @@ -1661,6 +1661,12 @@ static const VMStateDescription *vmstate_get_subsection(const VMStateSubsection static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd, void *opaque) { + const VMStateSubsection *sub = vmsd->subsections; + + if (!sub || !sub->needed) { + return 0; + } + while (qemu_peek_byte(f) == QEMU_VM_SUBSECTION) { char idstr[256]; int ret; @@ -1673,10 +1679,11 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd, idstr[len] = 0; version_id = qemu_get_be32(f); - sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr); + sub_vmsd = vmstate_get_subsection(sub, idstr); if (sub_vmsd == NULL) { return -ENOENT; } + assert(!sub_vmsd->subsections); ret = vmstate_load_state(f, sub_vmsd, opaque, version_id); if (ret) { return ret; @@ -1700,6 +1707,7 @@ static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd, qemu_put_byte(f, len); qemu_put_buffer(f, (uint8_t *)vmsd->name, len); qemu_put_be32(f, vmsd->version_id); + assert(!vmsd->subsections); vmstate_save_state(f, vmsd, opaque); } sub++; diff --git a/target-arm/helpers.h b/target-arm/helpers.h index b88ebaecc..8a2564ec6 100644 --- a/target-arm/helpers.h +++ b/target-arm/helpers.h @@ -137,10 +137,6 @@ DEF_HELPER_2(rsqrte_f32, f32, f32, env) DEF_HELPER_2(recpe_u32, i32, i32, env) DEF_HELPER_2(rsqrte_u32, i32, i32, env) DEF_HELPER_4(neon_tbl, i32, i32, i32, i32, i32) -DEF_HELPER_2(neon_add_saturate_u64, i64, i64, i64) -DEF_HELPER_2(neon_add_saturate_s64, i64, i64, i64) -DEF_HELPER_2(neon_sub_saturate_u64, i64, i64, i64) -DEF_HELPER_2(neon_sub_saturate_s64, i64, i64, i64) DEF_HELPER_2(add_cc, i32, i32, i32) DEF_HELPER_2(adc_cc, i32, i32, i32) @@ -160,10 +156,18 @@ DEF_HELPER_3(neon_qadd_u8, i32, env, i32, i32) DEF_HELPER_3(neon_qadd_s8, i32, env, i32, i32) DEF_HELPER_3(neon_qadd_u16, i32, env, i32, i32) DEF_HELPER_3(neon_qadd_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qadd_u32, i32, env, i32, i32) +DEF_HELPER_3(neon_qadd_s32, i32, env, i32, i32) DEF_HELPER_3(neon_qsub_u8, i32, env, i32, i32) DEF_HELPER_3(neon_qsub_s8, i32, env, i32, i32) DEF_HELPER_3(neon_qsub_u16, i32, env, i32, i32) DEF_HELPER_3(neon_qsub_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qsub_u32, i32, env, i32, i32) +DEF_HELPER_3(neon_qsub_s32, i32, env, i32, i32) +DEF_HELPER_3(neon_qadd_u64, i64, env, i64, i64) +DEF_HELPER_3(neon_qadd_s64, i64, env, i64, i64) +DEF_HELPER_3(neon_qsub_u64, i64, env, i64, i64) +DEF_HELPER_3(neon_qsub_s64, i64, env, i64, i64) DEF_HELPER_2(neon_hadd_s8, i32, i32, i32) DEF_HELPER_2(neon_hadd_u8, i32, i32, i32) diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index fead1525c..268af33a6 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -198,6 +198,28 @@ NEON_VOP_ENV(qadd_u16, neon_u16, 2) #undef NEON_FN #undef NEON_USAT +uint32_t HELPER(neon_qadd_u32)(CPUState *env, uint32_t a, uint32_t b) +{ + uint32_t res = a + b; + if (res < a) { + SET_QC(); + res = ~0; + } + return res; +} + +uint64_t HELPER(neon_qadd_u64)(CPUState *env, uint64_t src1, uint64_t src2) +{ + uint64_t res; + + res = src1 + src2; + if (res < src1) { + SET_QC(); + res = ~(uint64_t)0; + } + return res; +} + #define NEON_SSAT(dest, src1, src2, type) do { \ int32_t tmp = (uint32_t)src1 + (uint32_t)src2; \ if (tmp != (type)tmp) { \ @@ -218,6 +240,28 @@ NEON_VOP_ENV(qadd_s16, neon_s16, 2) #undef NEON_FN #undef NEON_SSAT +uint32_t HELPER(neon_qadd_s32)(CPUState *env, uint32_t a, uint32_t b) +{ + uint32_t res = a + b; + if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) { + SET_QC(); + res = ~(((int32_t)a >> 31) ^ SIGNBIT); + } + return res; +} + +uint64_t HELPER(neon_qadd_s64)(CPUState *env, uint64_t src1, uint64_t src2) +{ + uint64_t res; + + res = src1 + src2; + if (((res ^ src1) & SIGNBIT64) && !((src1 ^ src2) & SIGNBIT64)) { + SET_QC(); + res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64; + } + return res; +} + #define NEON_USAT(dest, src1, src2, type) do { \ uint32_t tmp = (uint32_t)src1 - (uint32_t)src2; \ if (tmp != (type)tmp) { \ @@ -234,6 +278,29 @@ NEON_VOP_ENV(qsub_u16, neon_u16, 2) #undef NEON_FN #undef NEON_USAT +uint32_t HELPER(neon_qsub_u32)(CPUState *env, uint32_t a, uint32_t b) +{ + uint32_t res = a - b; + if (res > a) { + SET_QC(); + res = 0; + } + return res; +} + +uint64_t HELPER(neon_qsub_u64)(CPUState *env, uint64_t src1, uint64_t src2) +{ + uint64_t res; + + if (src1 < src2) { + SET_QC(); + res = 0; + } else { + res = src1 - src2; + } + return res; +} + #define NEON_SSAT(dest, src1, src2, type) do { \ int32_t tmp = (uint32_t)src1 - (uint32_t)src2; \ if (tmp != (type)tmp) { \ @@ -254,6 +321,28 @@ NEON_VOP_ENV(qsub_s16, neon_s16, 2) #undef NEON_FN #undef NEON_SSAT +uint32_t HELPER(neon_qsub_s32)(CPUState *env, uint32_t a, uint32_t b) +{ + uint32_t res = a - b; + if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) { + SET_QC(); + res = ~(((int32_t)a >> 31) ^ SIGNBIT); + } + return res; +} + +uint64_t HELPER(neon_qsub_s64)(CPUState *env, uint64_t src1, uint64_t src2) +{ + uint64_t res; + + res = src1 - src2; + if (((res ^ src1) & SIGNBIT64) && ((src1 ^ src2) & SIGNBIT64)) { + SET_QC(); + res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64; + } + return res; +} + #define NEON_FN(dest, src1, src2) dest = (src1 + src2) >> 1 NEON_VOP(hadd_s8, neon_s8, 4) NEON_VOP(hadd_u8, neon_u8, 4) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 43baa6300..3de261034 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -424,52 +424,3 @@ uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i) return ((uint32_t)x >> shift) | (x << (32 - shift)); } } - -uint64_t HELPER(neon_add_saturate_s64)(uint64_t src1, uint64_t src2) -{ - uint64_t res; - - res = src1 + src2; - if (((res ^ src1) & SIGNBIT64) && !((src1 ^ src2) & SIGNBIT64)) { - env->QF = 1; - res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64; - } - return res; -} - -uint64_t HELPER(neon_add_saturate_u64)(uint64_t src1, uint64_t src2) -{ - uint64_t res; - - res = src1 + src2; - if (res < src1) { - env->QF = 1; - res = ~(uint64_t)0; - } - return res; -} - -uint64_t HELPER(neon_sub_saturate_s64)(uint64_t src1, uint64_t src2) -{ - uint64_t res; - - res = src1 - src2; - if (((res ^ src1) & SIGNBIT64) && ((src1 ^ src2) & SIGNBIT64)) { - env->QF = 1; - res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64; - } - return res; -} - -uint64_t HELPER(neon_sub_saturate_u64)(uint64_t src1, uint64_t src2) -{ - uint64_t res; - - if (src1 < src2) { - env->QF = 1; - res = 0; - } else { - res = src1 - src2; - } - return res; -} diff --git a/target-arm/translate.c b/target-arm/translate.c index d95133f72..514954300 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -3539,12 +3539,6 @@ static inline void gen_neon_rsb(int size, TCGv t0, TCGv t1) #define gen_helper_neon_pmin_s32 gen_helper_neon_min_s32 #define gen_helper_neon_pmin_u32 gen_helper_neon_min_u32 -/* FIXME: This is wrong. They set the wrong overflow bit. */ -#define gen_helper_neon_qadd_s32(a, e, b, c) gen_helper_add_saturate(a, b, c) -#define gen_helper_neon_qadd_u32(a, e, b, c) gen_helper_add_usaturate(a, b, c) -#define gen_helper_neon_qsub_s32(a, e, b, c) gen_helper_sub_saturate(a, b, c) -#define gen_helper_neon_qsub_u32(a, e, b, c) gen_helper_sub_usaturate(a, b, c) - #define GEN_NEON_INTEGER_OP_ENV(name) do { \ switch ((size << 1) | u) { \ case 0: \ @@ -4233,16 +4227,20 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) switch (op) { case 1: /* VQADD */ if (u) { - gen_helper_neon_add_saturate_u64(CPU_V001); + gen_helper_neon_qadd_u64(cpu_V0, cpu_env, + cpu_V0, cpu_V1); } else { - gen_helper_neon_add_saturate_s64(CPU_V001); + gen_helper_neon_qadd_s64(cpu_V0, cpu_env, + cpu_V0, cpu_V1); } break; case 5: /* VQSUB */ if (u) { - gen_helper_neon_sub_saturate_u64(CPU_V001); + gen_helper_neon_qsub_u64(cpu_V0, cpu_env, + cpu_V0, cpu_V1); } else { - gen_helper_neon_sub_saturate_s64(CPU_V001); + gen_helper_neon_qsub_s64(cpu_V0, cpu_env, + cpu_V0, cpu_V1); } break; case 8: /* VSHL */ @@ -4686,7 +4684,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } if (op == 1 || op == 3) { /* Accumulate. */ - neon_load_reg64(cpu_V0, rd + pass); + neon_load_reg64(cpu_V1, rd + pass); tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1); } else if (op == 4 || (op == 5 && u)) { /* Insert */ @@ -4750,7 +4748,7 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) if (op == 1 || op == 3) { /* Accumulate. */ tmp2 = neon_load_reg(rd, pass); - gen_neon_add(size, tmp2, tmp); + gen_neon_add(size, tmp, tmp2); dead_tmp(tmp2); } else if (op == 4 || (op == 5 && u)) { /* Insert */ diff --git a/target-i386/helper.c b/target-i386/helper.c index 30c5d5edd..86202e684 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1149,8 +1149,8 @@ void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, if (cenv == env) { continue; } - - qemu_inject_x86_mce(env, 1, 0xa000000000000000, 0, 0, 0); + qemu_inject_x86_mce(env, 1, MCI_STATUS_VAL | MCI_STATUS_UC, + MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0); } } } diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 35573be5f..58e9b8f93 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -960,9 +960,9 @@ static void _decode_opc(DisasContext * ctx) tcg_gen_andi_i32(t1, cpu_sr, SR_T); tcg_gen_sub_i32(REG(B11_8), t0, t1); tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T); - tcg_gen_setcond_i32(TCG_COND_GE, t1, REG(B11_8), t0); + tcg_gen_setcondi_i32(TCG_COND_GTU, t1, t0, 0); tcg_gen_or_i32(cpu_sr, cpu_sr, t1); - tcg_gen_setcondi_i32(TCG_COND_GE, t1, t0, 0); + tcg_gen_setcond_i32(TCG_COND_GTU, t1, REG(B11_8), t0); tcg_gen_or_i32(cpu_sr, cpu_sr, t1); tcg_temp_free(t0); tcg_temp_free(t1); @@ -388,12 +388,16 @@ static void sdl_process_key(SDL_KeyboardEvent *ev) else modifiers_state[keycode] = 1; break; +#define QEMU_SDL_VERSION ((SDL_MAJOR_VERSION << 8) + SDL_MINOR_VERSION) +#if QEMU_SDL_VERSION < 0x102 || QEMU_SDL_VERSION == 0x102 && SDL_PATCHLEVEL < 14 + /* SDL versions before 1.2.14 don't support key up for caps/num lock. */ case 0x45: /* num lock */ case 0x3a: /* caps lock */ /* SDL does not send the key up event, so we generate it */ kbd_put_keycode(keycode); kbd_put_keycode(keycode | SCANCODE_UP); return; +#endif } /* now send the key code */ @@ -831,6 +835,10 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 0); } + /* Enable normal up/down events for Caps-Lock and Num-Lock keys. + * This requires SDL >= 1.2.14. */ + setenv("SDL_DISABLE_LOCK_KEYS", "1", 1); + flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE; if (SDL_Init (flags)) { fprintf(stderr, "Could not initialize SDL(%s) - exiting\n", diff --git a/ui/vnc-jobs-async.c b/ui/vnc-jobs-async.c index 6e9cf08b6..0b5d750f2 100644 --- a/ui/vnc-jobs-async.c +++ b/ui/vnc-jobs-async.c @@ -227,6 +227,10 @@ static int vnc_worker_thread_loop(VncJobQueue *queue) if (job->vs->csock == -1) { vnc_unlock_display(job->vs->vd); + /* output mutex must be locked before going to + * disconnected: + */ + vnc_lock_output(job->vs); goto disconnected; } @@ -742,7 +742,7 @@ void add_boot_device_path(int32_t bootindex, DeviceState *dev, node = qemu_mallocz(sizeof(FWBootEntry)); node->bootindex = bootindex; - node->suffix = strdup(suffix); + node->suffix = suffix ? qemu_strdup(suffix) : NULL; node->dev = dev; QTAILQ_FOREACH(i, &fw_boot_order, link) { @@ -789,7 +789,7 @@ char *get_boot_devices_list(uint32_t *size) } else if (devpath) { bootpath = devpath; } else { - bootpath = strdup(i->suffix); + bootpath = qemu_strdup(i->suffix); assert(bootpath); } |