summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--block.c5
-rw-r--r--block/gluster.c143
-rw-r--r--block/iscsi.c133
-rw-r--r--block/quorum.c9
-rw-r--r--block/vmdk.c2
-rw-r--r--default-configs/s390x-softmmu.mak1
-rw-r--r--default-configs/sparc-softmmu.mak1
-rw-r--r--docs/qmp/qmp-events.txt75
-rw-r--r--hw/display/Makefile.objs1
-rw-r--r--hw/display/cg3.c385
-rw-r--r--hw/intc/Makefile.objs1
-rw-r--r--hw/intc/s390_flic.c322
-rw-r--r--hw/s390x/event-facility.c93
-rw-r--r--hw/s390x/ipl.c21
-rw-r--r--hw/s390x/s390-virtio-ccw.c8
-rw-r--r--hw/s390x/s390-virtio-hcall.c14
-rw-r--r--hw/s390x/s390-virtio.c2
-rw-r--r--hw/s390x/sclp.c69
-rw-r--r--hw/scsi/scsi-bus.c7
-rw-r--r--hw/scsi/scsi-disk.c29
-rw-r--r--hw/scsi/scsi-generic.c2
-rw-r--r--hw/scsi/spapr_vscsi.c1
-rw-r--r--hw/sparc/sun4m.c62
-rw-r--r--hw/timer/slavio_timer.c25
-rw-r--r--include/hw/nvram/openbios_firmware_abi.h2
-rw-r--r--include/hw/s390x/event-facility.h19
-rw-r--r--include/hw/s390x/s390_flic.h33
-rw-r--r--include/hw/s390x/sclp.h24
-rw-r--r--include/hw/scsi/scsi.h4
-rw-r--r--include/sysemu/sysemu.h1
-rw-r--r--linux-headers/asm-s390/kvm.h19
-rw-r--r--linux-headers/linux/kvm.h66
-rw-r--r--pc-bios/QEMU,cgthree.binbin0 -> 850 bytes
-rw-r--r--pc-bios/README4
-rw-r--r--pc-bios/s390-ccw.imgbin9336 -> 9336 bytes
-rw-r--r--pc-bios/s390-ccw/main.c3
-rw-r--r--pc-bios/s390-ccw/virtio.c1
-rw-r--r--qapi-schema.json5
-rw-r--r--target-i386/cc_helper.c2
-rw-r--r--target-i386/cpu.h3
-rw-r--r--target-i386/fpu_helper.c15
-rw-r--r--target-i386/gdbstub.c2
-rw-r--r--target-i386/translate.c48
-rw-r--r--target-s390x/cpu.c15
-rw-r--r--target-s390x/cpu.h6
-rw-r--r--target-s390x/kvm.c249
-rw-r--r--target-s390x/misc_helper.c2
-rwxr-xr-xtests/qemu-iotests-quick.sh1
-rwxr-xr-xtests/qemu-iotests/0813
-rw-r--r--tests/qemu-iotests/081.out2
-rw-r--r--tests/qemu-iotests/common.rc2
-rw-r--r--tests/qemu-iotests/group34
-rw-r--r--trace-events5
-rw-r--r--vl.c24
55 files changed, 1607 insertions, 401 deletions
diff --git a/Makefile b/Makefile
index a28a3c8d49..ea6c71284b 100644
--- a/Makefile
+++ b/Makefile
@@ -159,6 +159,7 @@ qemu-options.def: $(SRC_PATH)/qemu-options.hx
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
+$(SOFTMMU_SUBDIR_RULES): $(block-obj-y)
$(SOFTMMU_SUBDIR_RULES): config-all-devices.mak
subdir-%:
@@ -319,7 +320,7 @@ ifdef INSTALL_BLOBS
BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
acpi-dsdt.aml q35-acpi-dsdt.aml \
-ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin \
+ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
diff --git a/block.c b/block.c
index 2fd5482572..38bbdf3083 100644
--- a/block.c
+++ b/block.c
@@ -547,8 +547,9 @@ int get_tmp_filename(char *filename, int size)
int fd;
const char *tmpdir;
tmpdir = getenv("TMPDIR");
- if (!tmpdir)
- tmpdir = "/tmp";
+ if (!tmpdir) {
+ tmpdir = "/var/tmp";
+ }
if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
return -EOVERFLOW;
}
diff --git a/block/gluster.c b/block/gluster.c
index 14d390b4c7..54ee9b7d93 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -45,11 +45,13 @@ typedef struct GlusterConf {
static void qemu_gluster_gconf_free(GlusterConf *gconf)
{
- g_free(gconf->server);
- g_free(gconf->volname);
- g_free(gconf->image);
- g_free(gconf->transport);
- g_free(gconf);
+ if (gconf) {
+ g_free(gconf->server);
+ g_free(gconf->volname);
+ g_free(gconf->image);
+ g_free(gconf->transport);
+ g_free(gconf);
+ }
}
static int parse_volume_options(GlusterConf *gconf, char *path)
@@ -272,11 +274,28 @@ static QemuOptsList runtime_opts = {
},
};
+static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
+{
+ assert(open_flags != NULL);
+
+ *open_flags |= O_BINARY;
+
+ if (bdrv_flags & BDRV_O_RDWR) {
+ *open_flags |= O_RDWR;
+ } else {
+ *open_flags |= O_RDONLY;
+ }
+
+ if ((bdrv_flags & BDRV_O_NOCACHE)) {
+ *open_flags |= O_DIRECT;
+ }
+}
+
static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
int bdrv_flags, Error **errp)
{
BDRVGlusterState *s = bs->opaque;
- int open_flags = O_BINARY;
+ int open_flags = 0;
int ret = 0;
GlusterConf *gconf = g_malloc0(sizeof(GlusterConf));
QemuOpts *opts;
@@ -299,15 +318,7 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
goto out;
}
- if (bdrv_flags & BDRV_O_RDWR) {
- open_flags |= O_RDWR;
- } else {
- open_flags |= O_RDONLY;
- }
-
- if ((bdrv_flags & BDRV_O_NOCACHE)) {
- open_flags |= O_DIRECT;
- }
+ qemu_gluster_parse_flags(bdrv_flags, &open_flags);
s->fd = glfs_open(s->glfs, gconf->image, open_flags);
if (!s->fd) {
@@ -329,6 +340,96 @@ out:
return ret;
}
+typedef struct BDRVGlusterReopenState {
+ struct glfs *glfs;
+ struct glfs_fd *fd;
+} BDRVGlusterReopenState;
+
+
+static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
+ BlockReopenQueue *queue, Error **errp)
+{
+ int ret = 0;
+ BDRVGlusterReopenState *reop_s;
+ GlusterConf *gconf = NULL;
+ int open_flags = 0;
+
+ assert(state != NULL);
+ assert(state->bs != NULL);
+
+ state->opaque = g_malloc0(sizeof(BDRVGlusterReopenState));
+ reop_s = state->opaque;
+
+ qemu_gluster_parse_flags(state->flags, &open_flags);
+
+ gconf = g_malloc0(sizeof(GlusterConf));
+
+ reop_s->glfs = qemu_gluster_init(gconf, state->bs->filename);
+ if (reop_s->glfs == NULL) {
+ ret = -errno;
+ goto exit;
+ }
+
+ reop_s->fd = glfs_open(reop_s->glfs, gconf->image, open_flags);
+ if (reop_s->fd == NULL) {
+ /* reops->glfs will be cleaned up in _abort */
+ ret = -errno;
+ goto exit;
+ }
+
+exit:
+ /* state->opaque will be freed in either the _abort or _commit */
+ qemu_gluster_gconf_free(gconf);
+ return ret;
+}
+
+static void qemu_gluster_reopen_commit(BDRVReopenState *state)
+{
+ BDRVGlusterReopenState *reop_s = state->opaque;
+ BDRVGlusterState *s = state->bs->opaque;
+
+
+ /* close the old */
+ if (s->fd) {
+ glfs_close(s->fd);
+ }
+ if (s->glfs) {
+ glfs_fini(s->glfs);
+ }
+
+ /* use the newly opened image / connection */
+ s->fd = reop_s->fd;
+ s->glfs = reop_s->glfs;
+
+ g_free(state->opaque);
+ state->opaque = NULL;
+
+ return;
+}
+
+
+static void qemu_gluster_reopen_abort(BDRVReopenState *state)
+{
+ BDRVGlusterReopenState *reop_s = state->opaque;
+
+ if (reop_s == NULL) {
+ return;
+ }
+
+ if (reop_s->fd) {
+ glfs_close(reop_s->fd);
+ }
+
+ if (reop_s->glfs) {
+ glfs_fini(reop_s->glfs);
+ }
+
+ g_free(state->opaque);
+ state->opaque = NULL;
+
+ return;
+}
+
#ifdef CONFIG_GLUSTERFS_ZEROFILL
static coroutine_fn int qemu_gluster_co_write_zeroes(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags)
@@ -619,6 +720,9 @@ static BlockDriver bdrv_gluster = {
.instance_size = sizeof(BDRVGlusterState),
.bdrv_needs_filename = true,
.bdrv_file_open = qemu_gluster_open,
+ .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
+ .bdrv_reopen_commit = qemu_gluster_reopen_commit,
+ .bdrv_reopen_abort = qemu_gluster_reopen_abort,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
.bdrv_getlength = qemu_gluster_getlength,
@@ -643,6 +747,9 @@ static BlockDriver bdrv_gluster_tcp = {
.instance_size = sizeof(BDRVGlusterState),
.bdrv_needs_filename = true,
.bdrv_file_open = qemu_gluster_open,
+ .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
+ .bdrv_reopen_commit = qemu_gluster_reopen_commit,
+ .bdrv_reopen_abort = qemu_gluster_reopen_abort,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
.bdrv_getlength = qemu_gluster_getlength,
@@ -667,6 +774,9 @@ static BlockDriver bdrv_gluster_unix = {
.instance_size = sizeof(BDRVGlusterState),
.bdrv_needs_filename = true,
.bdrv_file_open = qemu_gluster_open,
+ .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
+ .bdrv_reopen_commit = qemu_gluster_reopen_commit,
+ .bdrv_reopen_abort = qemu_gluster_reopen_abort,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
.bdrv_getlength = qemu_gluster_getlength,
@@ -691,6 +801,9 @@ static BlockDriver bdrv_gluster_rdma = {
.instance_size = sizeof(BDRVGlusterState),
.bdrv_needs_filename = true,
.bdrv_file_open = qemu_gluster_open,
+ .bdrv_reopen_prepare = qemu_gluster_reopen_prepare,
+ .bdrv_reopen_commit = qemu_gluster_reopen_commit,
+ .bdrv_reopen_abort = qemu_gluster_reopen_abort,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
.bdrv_getlength = qemu_gluster_getlength,
diff --git a/block/iscsi.c b/block/iscsi.c
index 41ec09709d..0a15f53f8c 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -145,12 +145,13 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
if (iTask->retries-- > 0 && status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_UNIT_ATTENTION) {
+ error_report("iSCSI CheckCondition: %s", iscsi_get_error(iscsi));
iTask->do_retry = 1;
goto out;
}
if (status != SCSI_STATUS_GOOD) {
- error_report("iSCSI: Failure. %s", iscsi_get_error(iscsi));
+ error_report("iSCSI Failure: %s", iscsi_get_error(iscsi));
}
out:
@@ -325,6 +326,7 @@ retry:
}
if (iTask.do_retry) {
+ iTask.complete = 0;
goto retry;
}
@@ -399,6 +401,7 @@ retry:
}
if (iTask.do_retry) {
+ iTask.complete = 0;
goto retry;
}
@@ -433,6 +436,7 @@ retry:
}
if (iTask.do_retry) {
+ iTask.complete = 0;
goto retry;
}
@@ -683,6 +687,7 @@ retry:
scsi_free_scsi_task(iTask.task);
iTask.task = NULL;
}
+ iTask.complete = 0;
goto retry;
}
@@ -767,6 +772,7 @@ retry:
}
if (iTask.do_retry) {
+ iTask.complete = 0;
goto retry;
}
@@ -830,24 +836,26 @@ retry:
qemu_coroutine_yield();
}
+ if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
+ iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
+ iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
+ /* WRITE SAME is not supported by the target */
+ iscsilun->has_write_same = false;
+ scsi_free_scsi_task(iTask.task);
+ return -ENOTSUP;
+ }
+
if (iTask.task != NULL) {
scsi_free_scsi_task(iTask.task);
iTask.task = NULL;
}
if (iTask.do_retry) {
+ iTask.complete = 0;
goto retry;
}
if (iTask.status != SCSI_STATUS_GOOD) {
- if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
- iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
- iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
- /* WRITE SAME is not supported by the target */
- iscsilun->has_write_same = false;
- return -ENOTSUP;
- }
-
return -EIO;
}
@@ -1060,7 +1068,7 @@ static QemuOptsList runtime_opts = {
};
static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
- int evpd, int pc, Error **errp)
+ int evpd, int pc, void **inq, Error **errp)
{
int full_size;
struct scsi_task *task = NULL;
@@ -1079,14 +1087,19 @@ static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
}
}
+ *inq = scsi_datain_unmarshall(task);
+ if (*inq == NULL) {
+ error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
+ goto fail;
+ }
+
return task;
fail:
error_setg(errp, "iSCSI: Inquiry command failed : %s",
iscsi_get_error(iscsi));
- if (task) {
+ if (task != NULL) {
scsi_free_scsi_task(task);
- return NULL;
}
return NULL;
}
@@ -1107,11 +1120,12 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
struct iscsi_url *iscsi_url = NULL;
struct scsi_task *task = NULL;
struct scsi_inquiry_standard *inq = NULL;
+ struct scsi_inquiry_supported_pages *inq_vpd;
char *initiator_name = NULL;
QemuOpts *opts;
Error *local_err = NULL;
const char *filename;
- int ret;
+ int i, ret;
if ((BDRV_SECTOR_SIZE % 512) != 0) {
error_setg(errp, "iSCSI: Invalid BDRV_SECTOR_SIZE. "
@@ -1197,24 +1211,17 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
iscsilun->iscsi = iscsi;
iscsilun->lun = iscsi_url->lun;
+ iscsilun->has_write_same = true;
- task = iscsi_inquiry_sync(iscsi, iscsilun->lun, 0, 0, 36);
-
- if (task == NULL || task->status != SCSI_STATUS_GOOD) {
- error_setg(errp, "iSCSI: failed to send inquiry command.");
- ret = -EINVAL;
- goto out;
- }
-
- inq = scsi_datain_unmarshall(task);
- if (inq == NULL) {
- error_setg(errp, "iSCSI: Failed to unmarshall inquiry data.");
+ task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 0, 0,
+ (void **) &inq, errp);
+ if (task == NULL) {
ret = -EINVAL;
goto out;
}
-
iscsilun->type = inq->periperal_device_type;
- iscsilun->has_write_same = true;
+ scsi_free_scsi_task(task);
+ task = NULL;
iscsi_readcapacity_sync(iscsilun, &local_err);
if (local_err != NULL) {
@@ -1233,46 +1240,48 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
bs->sg = 1;
}
- if (iscsilun->lbpme) {
- struct scsi_inquiry_logical_block_provisioning *inq_lbp;
- task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
- SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING,
- errp);
- if (task == NULL) {
- ret = -EINVAL;
- goto out;
- }
- inq_lbp = scsi_datain_unmarshall(task);
- if (inq_lbp == NULL) {
- error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
- ret = -EINVAL;
- goto out;
- }
- memcpy(&iscsilun->lbp, inq_lbp,
- sizeof(struct scsi_inquiry_logical_block_provisioning));
- scsi_free_scsi_task(task);
- task = NULL;
+ task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
+ SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES,
+ (void **) &inq_vpd, errp);
+ if (task == NULL) {
+ ret = -EINVAL;
+ goto out;
}
-
- if (iscsilun->lbp.lbpu || iscsilun->lbp.lbpws) {
+ for (i = 0; i < inq_vpd->num_pages; i++) {
+ struct scsi_task *inq_task;
+ struct scsi_inquiry_logical_block_provisioning *inq_lbp;
struct scsi_inquiry_block_limits *inq_bl;
- task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
- SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS, errp);
- if (task == NULL) {
- ret = -EINVAL;
- goto out;
- }
- inq_bl = scsi_datain_unmarshall(task);
- if (inq_bl == NULL) {
- error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
- ret = -EINVAL;
- goto out;
+ switch (inq_vpd->pages[i]) {
+ case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING:
+ inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
+ SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING,
+ (void **) &inq_lbp, errp);
+ if (inq_task == NULL) {
+ ret = -EINVAL;
+ goto out;
+ }
+ memcpy(&iscsilun->lbp, inq_lbp,
+ sizeof(struct scsi_inquiry_logical_block_provisioning));
+ scsi_free_scsi_task(inq_task);
+ break;
+ case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS:
+ inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
+ SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS,
+ (void **) &inq_bl, errp);
+ if (inq_task == NULL) {
+ ret = -EINVAL;
+ goto out;
+ }
+ memcpy(&iscsilun->bl, inq_bl,
+ sizeof(struct scsi_inquiry_block_limits));
+ scsi_free_scsi_task(inq_task);
+ break;
+ default:
+ break;
}
- memcpy(&iscsilun->bl, inq_bl,
- sizeof(struct scsi_inquiry_block_limits));
- scsi_free_scsi_task(task);
- task = NULL;
}
+ scsi_free_scsi_task(task);
+ task = NULL;
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
/* Set up a timer for sending out iSCSI NOPs */
diff --git a/block/quorum.c b/block/quorum.c
index 6c28239718..bd997b7322 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -200,11 +200,14 @@ static void quorum_report_bad(QuorumAIOCB *acb, char *node_name, int ret)
{
QObject *data;
assert(node_name);
- data = qobject_from_jsonf("{ 'ret': %d"
- ", 'node-name': %s"
+ data = qobject_from_jsonf("{ 'node-name': %s"
", 'sector-num': %" PRId64
", 'sectors-count': %d }",
- ret, node_name, acb->sector_num, acb->nb_sectors);
+ node_name, acb->sector_num, acb->nb_sectors);
+ if (ret < 0) {
+ QDict *dict = qobject_to_qdict(data);
+ qdict_put(dict, "error", qstring_from_str(strerror(-ret)));
+ }
monitor_protocol_event(QEVENT_QUORUM_REPORT_BAD, data);
qobject_decref(data);
}
diff --git a/block/vmdk.c b/block/vmdk.c
index 83839f9b7a..b69988d169 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1184,7 +1184,7 @@ static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
break;
case VMDK_OK:
ret = BDRV_BLOCK_DATA;
- if (extent->file == bs->file) {
+ if (extent->file == bs->file && !extent->compressed) {
ret |= BDRV_BLOCK_OFFSET_VALID | offset;
}
diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak
index 81fbc68654..d843dc0d57 100644
--- a/default-configs/s390x-softmmu.mak
+++ b/default-configs/s390x-softmmu.mak
@@ -1,2 +1,3 @@
CONFIG_VIRTIO=y
CONFIG_SCLPCONSOLE=y
+CONFIG_S390_FLIC=$(CONFIG_KVM)
diff --git a/default-configs/sparc-softmmu.mak b/default-configs/sparc-softmmu.mak
index 8fc93dd643..ab796b3d4f 100644
--- a/default-configs/sparc-softmmu.mak
+++ b/default-configs/sparc-softmmu.mak
@@ -10,6 +10,7 @@ CONFIG_EMPTY_SLOT=y
CONFIG_PCNET_COMMON=y
CONFIG_LANCE=y
CONFIG_TCX=y
+CONFIG_CG3=y
CONFIG_SLAVIO=y
CONFIG_CS4231=y
CONFIG_GRLIB=y
diff --git a/docs/qmp/qmp-events.txt b/docs/qmp/qmp-events.txt
index 00f95154dd..145402e078 100644
--- a/docs/qmp/qmp-events.txt
+++ b/docs/qmp/qmp-events.txt
@@ -225,6 +225,45 @@ Data:
"timestamp": { "seconds": 1368697518, "microseconds": 326866 } }
}
+QUORUM_FAILURE
+--------------
+
+Emitted by the Quorum block driver if it fails to establish a quorum.
+
+Data:
+
+- "reference": device name if defined else node name.
+- "sector-num": Number of the first sector of the failed read operation.
+- "sector-count": Failed read operation sector count.
+
+Example:
+
+{ "event": "QUORUM_FAILURE",
+ "data": { "reference": "usr1", "sector-num": 345435, "sector-count": 5 },
+ "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
+
+QUORUM_REPORT_BAD
+-----------------
+
+Emitted to report a corruption of a Quorum file.
+
+Data:
+
+- "error": Error message (json-string, optional)
+ Only present on failure. This field contains a human-readable
+ error message. There are no semantics other than that the
+ block layer reported an error and clients should not try to
+ interpret the error string.
+- "node-name": The graph node name of the block driver state.
+- "sector-num": Number of the first sector of the failed read operation.
+- "sector-count": Failed read operation sector count.
+
+Example:
+
+{ "event": "QUORUM_REPORT_BAD",
+ "data": { "node-name": "1.raw", "sector-num": 345435, "sector-count": 5 },
+ "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
+
RESET
-----
@@ -500,39 +539,3 @@ Example:
Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
followed respectively by the RESET, SHUTDOWN, or STOP events.
-
-QUORUM_FAILURE
---------------
-
-Emitted by the Quorum block driver if it fails to establish a quorum.
-
-Data:
-
-- "reference": device name if defined else node name.
-- "sector-num": Number of the first sector of the failed read operation.
-- "sector-count": Failed read operation sector count.
-
-Example:
-
-{ "event": "QUORUM_FAILURE",
- "data": { "reference": "usr1", "sector-num": 345435, "sector-count": 5 },
- "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
-
-QUORUM_REPORT_BAD
------------------
-
-Emitted to report a corruption of a Quorum file.
-
-Data:
-
-- "ret": The IO return code.
-- "node-name": The graph node name of the block driver state.
-- "sector-num": Number of the first sector of the failed read operation.
-- "sector-count": Failed read operation sector count.
-
-Example:
-
-{ "event": "QUORUM_REPORT_BAD",
- "data": { "ret": 0, "node-name": "1.raw", "sector-num": 345435,
- "sector-count": 5 },
- "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index 540df82600..7ed76a9c24 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -28,6 +28,7 @@ obj-$(CONFIG_OMAP) += omap_lcdc.o
obj-$(CONFIG_PXA2XX) += pxa2xx_lcd.o
obj-$(CONFIG_SM501) += sm501.o
obj-$(CONFIG_TCX) += tcx.o
+obj-$(CONFIG_CG3) += cg3.o
obj-$(CONFIG_VGA) += vga.o
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
new file mode 100644
index 0000000000..6db8ca362a
--- /dev/null
+++ b/hw/display/cg3.c
@@ -0,0 +1,385 @@
+/*
+ * QEMU CG3 Frame buffer
+ *
+ * Copyright (c) 2012 Bob Breuer
+ * Copyright (c) 2013 Mark Cave-Ayland
+ *
+ * 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 "qemu/error-report.h"
+#include "ui/console.h"
+#include "hw/sysbus.h"
+#include "hw/loader.h"
+
+/* Change to 1 to enable debugging */
+#define DEBUG_CG3 0
+
+#define CG3_ROM_FILE "QEMU,cgthree.bin"
+#define FCODE_MAX_ROM_SIZE 0x10000
+
+#define CG3_REG_SIZE 0x20
+
+#define CG3_REG_BT458_ADDR 0x0
+#define CG3_REG_BT458_COLMAP 0x4
+#define CG3_REG_FBC_CTRL 0x10
+#define CG3_REG_FBC_STATUS 0x11
+#define CG3_REG_FBC_CURSTART 0x12
+#define CG3_REG_FBC_CUREND 0x13
+#define CG3_REG_FBC_VCTRL 0x14
+
+/* Control register flags */
+#define CG3_CR_ENABLE_INTS 0x80
+
+/* Status register flags */
+#define CG3_SR_PENDING_INT 0x80
+#define CG3_SR_1152_900_76_B 0x60
+#define CG3_SR_ID_COLOR 0x01
+
+#define CG3_VRAM_SIZE 0x100000
+#define CG3_VRAM_OFFSET 0x800000
+
+#define DPRINTF(fmt, ...) do { \
+ if (DEBUG_CG3) { \
+ printf("CG3: " fmt , ## __VA_ARGS__); \
+ } \
+} while (0);
+
+#define TYPE_CG3 "cgthree"
+#define CG3(obj) OBJECT_CHECK(CG3State, (obj), TYPE_CG3)
+
+typedef struct CG3State {
+ SysBusDevice parent_obj;
+
+ QemuConsole *con;
+ qemu_irq irq;
+ hwaddr prom_addr;
+ MemoryRegion vram_mem;
+ MemoryRegion rom;
+ MemoryRegion reg;
+ uint32_t vram_size;
+ int full_update;
+ uint8_t regs[16];
+ uint8_t r[256], g[256], b[256];
+ uint16_t width, height, depth;
+ uint8_t dac_index, dac_state;
+} CG3State;
+
+static void cg3_update_display(void *opaque)
+{
+ CG3State *s = opaque;
+ DisplaySurface *surface = qemu_console_surface(s->con);
+ const uint8_t *pix;
+ uint32_t *data;
+ uint32_t dval;
+ int x, y, y_start;
+ unsigned int width, height;
+ ram_addr_t page, page_min, page_max;
+
+ if (surface_bits_per_pixel(surface) != 32) {
+ return;
+ }
+ width = s->width;
+ height = s->height;
+
+ y_start = -1;
+ page_min = -1;
+ page_max = 0;
+ page = 0;
+ pix = memory_region_get_ram_ptr(&s->vram_mem);
+ data = (uint32_t *)surface_data(surface);
+
+ for (y = 0; y < height; y++) {
+ int update = s->full_update;
+
+ page = (y * width) & TARGET_PAGE_MASK;
+ update |= memory_region_get_dirty(&s->vram_mem, page, page + width,
+ DIRTY_MEMORY_VGA);
+ if (update) {
+ if (y_start < 0) {
+ y_start = y;
+ }
+ if (page < page_min) {
+ page_min = page;
+ }
+ if (page > page_max) {
+ page_max = page;
+ }
+
+ for (x = 0; x < width; x++) {
+ dval = *pix++;
+ dval = (s->r[dval] << 16) | (s->g[dval] << 8) | s->b[dval];
+ *data++ = dval;
+ }
+ } else {
+ if (y_start >= 0) {
+ dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
+ y_start = -1;
+ }
+ pix += width;
+ data += width;
+ }
+ }
+ s->full_update = 0;
+ if (y_start >= 0) {
+ dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
+ }
+ if (page_max >= page_min) {
+ memory_region_reset_dirty(&s->vram_mem,
+ page_min, page_max - page_min + TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_VGA);
+ }
+ /* vsync interrupt? */
+ if (s->regs[0] & CG3_CR_ENABLE_INTS) {
+ s->regs[1] |= CG3_SR_PENDING_INT;
+ qemu_irq_raise(s->irq);
+ }
+}
+
+static void cg3_invalidate_display(void *opaque)
+{
+ CG3State *s = opaque;
+
+ memory_region_set_dirty(&s->vram_mem, 0, CG3_VRAM_SIZE);
+}
+
+static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size)
+{
+ CG3State *s = opaque;
+ int val;
+
+ switch (addr) {
+ case CG3_REG_BT458_ADDR:
+ case CG3_REG_BT458_COLMAP:
+ val = 0;
+ break;
+ case CG3_REG_FBC_CTRL:
+ val = s->regs[0];
+ break;
+ case CG3_REG_FBC_STATUS:
+ /* monitor ID 6, board type = 1 (color) */
+ val = s->regs[1] | CG3_SR_1152_900_76_B | CG3_SR_ID_COLOR;
+ break;
+ case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE:
+ val = s->regs[addr - 0x10];
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "cg3: Unimplemented register read "
+ "reg 0x%" HWADDR_PRIx " size 0x%x\n",
+ addr, size);
+ val = 0;
+ break;
+ }
+ DPRINTF("read %02x from reg %" HWADDR_PRIx "\n", val, addr);
+ return val;
+}
+
+static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ CG3State *s = opaque;
+ uint8_t regval;
+ int i;
+
+ DPRINTF("write %" PRIx64 " to reg %" HWADDR_PRIx " size %d\n",
+ val, addr, size);
+
+ switch (addr) {
+ case CG3_REG_BT458_ADDR:
+ s->dac_index = val;
+ s->dac_state = 0;
+ break;
+ case CG3_REG_BT458_COLMAP:
+ /* This register can be written to as either a long word or a byte */
+ if (size == 1) {
+ val <<= 24;
+ }
+
+ for (i = 0; i < size; i++) {
+ regval = val >> 24;
+
+ switch (s->dac_state) {
+ case 0:
+ s->r[s->dac_index] = regval;
+ s->dac_state++;
+ break;
+ case 1:
+ s->g[s->dac_index] = regval;
+ s->dac_state++;
+ break;
+ case 2:
+ s->b[s->dac_index] = regval;
+ /* Index autoincrement */
+ s->dac_index = (s->dac_index + 1) & 0xff;
+ default:
+ s->dac_state = 0;
+ break;
+ }
+ val <<= 8;
+ }
+ s->full_update = 1;
+ break;
+ case CG3_REG_FBC_CTRL:
+ s->regs[0] = val;
+ break;
+ case CG3_REG_FBC_STATUS:
+ if (s->regs[1] & CG3_SR_PENDING_INT) {
+ /* clear interrupt */
+ s->regs[1] &= ~CG3_SR_PENDING_INT;
+ qemu_irq_lower(s->irq);
+ }
+ break;
+ case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE:
+ s->regs[addr - 0x10] = val;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "cg3: Unimplemented register write "
+ "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n",
+ addr, size, val);
+ break;
+ }
+}
+
+static const MemoryRegionOps cg3_reg_ops = {
+ .read = cg3_reg_read,
+ .write = cg3_reg_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+static const GraphicHwOps cg3_ops = {
+ .invalidate = cg3_invalidate_display,
+ .gfx_update = cg3_update_display,
+};
+
+static void cg3_realizefn(DeviceState *dev, Error **errp)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ CG3State *s = CG3(dev);
+ int ret;
+ char *fcode_filename;
+
+ /* FCode ROM */
+ memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE);
+ vmstate_register_ram_global(&s->rom);
+ memory_region_set_readonly(&s->rom, true);
+ sysbus_init_mmio(sbd, &s->rom);
+
+ fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, CG3_ROM_FILE);
+ if (fcode_filename) {
+ ret = load_image_targphys(fcode_filename, s->prom_addr,
+ FCODE_MAX_ROM_SIZE);
+ if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) {
+ error_report("cg3: could not load prom '%s'", CG3_ROM_FILE);
+ }
+ }
+
+ memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg",
+ CG3_REG_SIZE);
+ sysbus_init_mmio(sbd, &s->reg);
+
+ memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size);
+ vmstate_register_ram_global(&s->vram_mem);
+ sysbus_init_mmio(sbd, &s->vram_mem);
+
+ sysbus_init_irq(sbd, &s->irq);
+
+ s->con = graphic_console_init(DEVICE(dev), &cg3_ops, s);
+ qemu_console_resize(s->con, s->width, s->height);
+}
+
+static int vmstate_cg3_post_load(void *opaque, int version_id)
+{
+ CG3State *s = opaque;
+
+ cg3_invalidate_display(s);
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_cg3 = {
+ .name = "cg3",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .post_load = vmstate_cg3_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16(height, CG3State),
+ VMSTATE_UINT16(width, CG3State),
+ VMSTATE_UINT16(depth, CG3State),
+ VMSTATE_BUFFER(r, CG3State),
+ VMSTATE_BUFFER(g, CG3State),
+ VMSTATE_BUFFER(b, CG3State),
+ VMSTATE_UINT8(dac_index, CG3State),
+ VMSTATE_UINT8(dac_state, CG3State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void cg3_reset(DeviceState *d)
+{
+ CG3State *s = CG3(d);
+
+ /* Initialize palette */
+ memset(s->r, 0, 256);
+ memset(s->g, 0, 256);
+ memset(s->b, 0, 256);
+
+ s->dac_state = 0;
+ s->full_update = 1;
+ qemu_irq_lower(s->irq);
+}
+
+static Property cg3_properties[] = {
+ DEFINE_PROP_UINT32("vram-size", CG3State, vram_size, -1),
+ DEFINE_PROP_UINT16("width", CG3State, width, -1),
+ DEFINE_PROP_UINT16("height", CG3State, height, -1),
+ DEFINE_PROP_UINT16("depth", CG3State, depth, -1),
+ DEFINE_PROP_UINT64("prom-addr", CG3State, prom_addr, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void cg3_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = cg3_realizefn;
+ dc->reset = cg3_reset;
+ dc->vmsd = &vmstate_cg3;
+ dc->props = cg3_properties;
+}
+
+static const TypeInfo cg3_info = {
+ .name = TYPE_CG3,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(CG3State),
+ .class_init = cg3_class_init,
+};
+
+static void cg3_register_types(void)
+{
+ type_register_static(&cg3_info);
+}
+
+type_init(cg3_register_types)
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 60eb936e0d..c8a2318d56 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -25,3 +25,4 @@ obj-$(CONFIG_SH4) += sh_intc.o
obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
+obj-$(CONFIG_S390_FLIC) += s390_flic.o
diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c
new file mode 100644
index 0000000000..b2ef3e3f8e
--- /dev/null
+++ b/hw/intc/s390_flic.c
@@ -0,0 +1,322 @@
+/*
+ * QEMU S390x KVM floating interrupt controller (flic)
+ *
+ * Copyright 2014 IBM Corp.
+ * Author(s): Jens Freimann <jfrei@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 <sys/ioctl.h>
+#include "qemu/error-report.h"
+#include "hw/sysbus.h"
+#include "sysemu/kvm.h"
+#include "migration/qemu-file.h"
+#include "hw/s390x/s390_flic.h"
+#include "trace.h"
+
+#define FLIC_SAVE_INITIAL_SIZE getpagesize()
+#define FLIC_FAILED (-1UL)
+#define FLIC_SAVEVM_VERSION 1
+
+void s390_flic_init(void)
+{
+ DeviceState *dev;
+ int r;
+
+ if (kvm_enabled()) {
+ dev = qdev_create(NULL, "s390-flic");
+ object_property_add_child(qdev_get_machine(), "s390-flic",
+ OBJECT(dev), NULL);
+ r = qdev_init(dev);
+ if (r) {
+ error_report("flic: couldn't create qdev");
+ }
+ }
+}
+
+/**
+ * flic_get_all_irqs - store all pending irqs in buffer
+ * @buf: pointer to buffer which is passed to kernel
+ * @len: length of buffer
+ * @flic: pointer to flic device state
+ *
+ * Returns: -ENOMEM if buffer is too small,
+ * -EINVAL if attr.group is invalid,
+ * -EFAULT if copying to userspace failed,
+ * on success return number of stored interrupts
+ */
+static int flic_get_all_irqs(KVMS390FLICState *flic,
+ void *buf, int len)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_GET_ALL_IRQS,
+ .addr = (uint64_t) buf,
+ .attr = len,
+ };
+ int rc;
+
+ rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
+
+ return rc == -1 ? -errno : rc;
+}
+
+static void flic_enable_pfault(KVMS390FLICState *flic)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_APF_ENABLE,
+ };
+ int rc;
+
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+
+ if (rc) {
+ fprintf(stderr, "flic: couldn't enable pfault\n");
+ }
+}
+
+static void flic_disable_wait_pfault(KVMS390FLICState *flic)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
+ };
+ int rc;
+
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+
+ if (rc) {
+ fprintf(stderr, "flic: couldn't disable pfault\n");
+ }
+}
+
+/** flic_enqueue_irqs - returns 0 on success
+ * @buf: pointer to buffer which is passed to kernel
+ * @len: length of buffer
+ * @flic: pointer to flic device state
+ *
+ * Returns: -EINVAL if attr.group is unknown
+ */
+static int flic_enqueue_irqs(void *buf, uint64_t len,
+ KVMS390FLICState *flic)
+{
+ int rc;
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_ENQUEUE,
+ .addr = (uint64_t) buf,
+ .attr = len,
+ };
+
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+
+ return rc ? -errno : 0;
+}
+
+/**
+ * __get_all_irqs - store all pending irqs in buffer
+ * @flic: pointer to flic device state
+ * @buf: pointer to pointer to a buffer
+ * @len: length of buffer
+ *
+ * Returns: return value of flic_get_all_irqs
+ * Note: Retry and increase buffer size until flic_get_all_irqs
+ * either returns a value >= 0 or a negative error code.
+ * -ENOMEM is an exception, which means the buffer is too small
+ * and we should try again. Other negative error codes can be
+ * -EFAULT and -EINVAL which we ignore at this point
+ */
+static int __get_all_irqs(KVMS390FLICState *flic,
+ void **buf, int len)
+{
+ int r;
+
+ do {
+ /* returns -ENOMEM if buffer is too small and number
+ * of queued interrupts on success */
+ r = flic_get_all_irqs(flic, *buf, len);
+ if (r >= 0) {
+ break;
+ }
+ len *= 2;
+ *buf = g_try_realloc(*buf, len);
+ if (!buf) {
+ return -ENOMEM;
+ }
+ } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
+
+ return r;
+}
+
+/**
+ * kvm_flic_save - Save pending floating interrupts
+ * @f: QEMUFile containing migration state
+ * @opaque: pointer to flic device state
+ *
+ * Note: Pass buf and len to kernel. Start with one page and
+ * increase until buffer is sufficient or maxium size is
+ * reached
+ */
+static void kvm_flic_save(QEMUFile *f, void *opaque)
+{
+ KVMS390FLICState *flic = opaque;
+ int len = FLIC_SAVE_INITIAL_SIZE;
+ void *buf;
+ int count;
+
+ flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
+
+ buf = g_try_malloc0(len);
+ if (!buf) {
+ /* Storing FLIC_FAILED into the count field here will cause the
+ * target system to fail when attempting to load irqs from the
+ * migration state */
+ error_report("flic: couldn't allocate memory");
+ qemu_put_be64(f, FLIC_FAILED);
+ return;
+ }
+
+ count = __get_all_irqs(flic, &buf, len);
+ if (count < 0) {
+ error_report("flic: couldn't retrieve irqs from kernel, rc %d",
+ count);
+ /* Storing FLIC_FAILED into the count field here will cause the
+ * target system to fail when attempting to load irqs from the
+ * migration state */
+ qemu_put_be64(f, FLIC_FAILED);
+ } else {
+ qemu_put_be64(f, count);
+ qemu_put_buffer(f, (uint8_t *) buf,
+ count * sizeof(struct kvm_s390_irq));
+ }
+ g_free(buf);
+}
+
+/**
+ * kvm_flic_load - Load pending floating interrupts
+ * @f: QEMUFile containing migration state
+ * @opaque: pointer to flic device state
+ * @version_id: version id for migration
+ *
+ * Returns: value of flic_enqueue_irqs, -EINVAL on error
+ * Note: Do nothing when no interrupts where stored
+ * in QEMUFile
+ */
+static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
+{
+ uint64_t len = 0;
+ uint64_t count = 0;
+ void *buf = NULL;
+ int r = 0;
+
+ if (version_id != FLIC_SAVEVM_VERSION) {
+ r = -EINVAL;
+ goto out;
+ }
+
+ flic_enable_pfault((struct KVMS390FLICState *) opaque);
+
+ count = qemu_get_be64(f);
+ len = count * sizeof(struct kvm_s390_irq);
+ if (count == FLIC_FAILED) {
+ r = -EINVAL;
+ goto out;
+ }
+ if (count == 0) {
+ r = 0;
+ goto out;
+ }
+ buf = g_try_malloc0(len);
+ if (!buf) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
+ r = -EINVAL;
+ goto out_free;
+ }
+ r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
+
+out_free:
+ g_free(buf);
+out:
+ return r;
+}
+
+static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
+{
+ KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
+ struct kvm_create_device cd = {0};
+ int ret;
+
+ flic_state->fd = -1;
+ if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
+ trace_flic_no_device_api(errno);
+ return;
+ }
+
+ cd.type = KVM_DEV_TYPE_FLIC;
+ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
+ if (ret < 0) {
+ trace_flic_create_device(errno);
+ return;
+ }
+ flic_state->fd = cd.fd;
+
+ /* Register savevm handler for floating interrupts */
+ register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
+ kvm_flic_load, (void *) flic_state);
+}
+
+static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
+{
+ KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
+
+ unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
+}
+
+static void kvm_s390_flic_reset(DeviceState *dev)
+{
+ KVMS390FLICState *flic = KVM_S390_FLIC(dev);
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_CLEAR_IRQS,
+ };
+ int rc = 0;
+
+ if (flic->fd == -1) {
+ return;
+ }
+
+ flic_disable_wait_pfault(flic);
+
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+ if (rc) {
+ trace_flic_reset_failed(errno);
+ }
+
+ flic_enable_pfault(flic);
+}
+
+static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = kvm_s390_flic_realize;
+ dc->unrealize = kvm_s390_flic_unrealize;
+ dc->reset = kvm_s390_flic_reset;
+}
+
+static const TypeInfo kvm_s390_flic_info = {
+ .name = TYPE_KVM_S390_FLIC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(KVMS390FLICState),
+ .class_init = kvm_s390_flic_class_init,
+};
+
+static void kvm_s390_flic_register_types(void)
+{
+ type_register_static(&kvm_s390_flic_info);
+}
+
+type_init(kvm_s390_flic_register_types)
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index a73c0b924a..0777a93916 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -21,13 +21,13 @@
#include "hw/s390x/sclp.h"
#include "hw/s390x/event-facility.h"
-typedef struct EventTypesBus {
+typedef struct SCLPEventsBus {
BusState qbus;
-} EventTypesBus;
+} SCLPEventsBus;
struct SCLPEventFacility {
- EventTypesBus sbus;
- DeviceState *qdev;
+ SysBusDevice parent_obj;
+ SCLPEventsBus sbus;
/* guest' receive mask */
unsigned int receive_mask;
};
@@ -291,7 +291,7 @@ static void sclp_events_bus_class_init(ObjectClass *klass, void *data)
{
}
-static const TypeInfo s390_sclp_events_bus_info = {
+static const TypeInfo sclp_events_bus_info = {
.name = TYPE_SCLP_EVENTS_BUS,
.parent = TYPE_BUS,
.class_init = sclp_events_bus_class_init,
@@ -299,7 +299,7 @@ static const TypeInfo s390_sclp_events_bus_info = {
static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
{
- switch (code) {
+ switch (code & SCLP_CMD_CODE_MASK) {
case SCLP_CMD_READ_EVENT_DATA:
read_event_data(ef, sccb);
break;
@@ -315,21 +315,26 @@ static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
}
}
-static int init_event_facility(S390SCLPDevice *sdev)
+static const VMStateDescription vmstate_event_facility = {
+ .name = "vmstate-event-facility",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(receive_mask, SCLPEventFacility),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int init_event_facility(SCLPEventFacility *event_facility)
{
- SCLPEventFacility *event_facility;
+ DeviceState *sdev = DEVICE(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 */
+ /* Spawn a new bus for SCLP events */
qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
- TYPE_SCLP_EVENTS_BUS, DEVICE(sdev), NULL);
+ TYPE_SCLP_EVENTS_BUS, sdev, NULL);
event_facility->sbus.qbus.allow_hotplug = 0;
- event_facility->qdev = (DeviceState *) sdev;
quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
if (!quiesce) {
@@ -346,43 +351,57 @@ static int init_event_facility(S390SCLPDevice *sdev)
static void reset_event_facility(DeviceState *dev)
{
- S390SCLPDevice *sdev = SCLP_S390_DEVICE(dev);
+ SCLPEventFacility *sdev = EVENT_FACILITY(dev);
- sdev->ef->receive_mask = 0;
+ sdev->receive_mask = 0;
}
static void init_event_facility_class(ObjectClass *klass, void *data)
{
- DeviceClass *dc = DEVICE_CLASS(klass);
- S390SCLPDeviceClass *k = SCLP_S390_DEVICE_CLASS(klass);
+ SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(sbdc);
+ SCLPEventFacilityClass *k = EVENT_FACILITY_CLASS(dc);
dc->reset = reset_event_facility;
+ dc->vmsd = &vmstate_event_facility;
k->init = init_event_facility;
+ k->command_handler = command_handler;
+ k->event_pending = event_pending;
}
-static const TypeInfo s390_sclp_event_facility_info = {
- .name = "s390-sclp-event-facility",
- .parent = TYPE_DEVICE_S390_SCLP,
- .instance_size = sizeof(S390SCLPDevice),
+static const TypeInfo sclp_event_facility_info = {
+ .name = TYPE_SCLP_EVENT_FACILITY,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SCLPEventFacility),
.class_init = init_event_facility_class,
+ .class_size = sizeof(SCLPEventFacilityClass),
};
-static int event_qdev_init(DeviceState *qdev)
+static void event_realize(DeviceState *qdev, Error **errp)
{
- SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
+ SCLPEvent *event = SCLP_EVENT(qdev);
SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
- return child->init(event);
+ if (child->init) {
+ int rc = child->init(event);
+ if (rc < 0) {
+ error_setg(errp, "SCLP event initialization failed.");
+ return;
+ }
+ }
}
-static int event_qdev_exit(DeviceState *qdev)
+static void event_unrealize(DeviceState *qdev, Error **errp)
{
- SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
+ SCLPEvent *event = SCLP_EVENT(qdev);
SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
if (child->exit) {
- child->exit(event);
+ int rc = child->exit(event);
+ if (rc < 0) {
+ error_setg(errp, "SCLP event exit failed.");
+ return;
+ }
}
- return 0;
}
static void event_class_init(ObjectClass *klass, void *data)
@@ -391,11 +410,11 @@ static void event_class_init(ObjectClass *klass, void *data)
dc->bus_type = TYPE_SCLP_EVENTS_BUS;
dc->unplug = qdev_simple_unplug_cb;
- dc->init = event_qdev_init;
- dc->exit = event_qdev_exit;
+ dc->realize = event_realize;
+ dc->unrealize = event_unrealize;
}
-static const TypeInfo s390_sclp_event_type_info = {
+static const TypeInfo sclp_event_type_info = {
.name = TYPE_SCLP_EVENT,
.parent = TYPE_DEVICE,
.instance_size = sizeof(SCLPEvent),
@@ -406,9 +425,9 @@ static const TypeInfo s390_sclp_event_type_info = {
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_register_static(&sclp_events_bus_info);
+ type_register_static(&sclp_event_facility_info);
+ type_register_static(&sclp_event_type_info);
}
type_init(register_types)
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 1a6397b88e..04fb1a8e05 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -95,7 +95,8 @@ static int s390_ipl_init(SysBusDevice *dev)
}
return 0;
} else {
- kernel_size = load_elf(ipl->kernel, NULL, NULL, NULL, NULL,
+ uint64_t pentry = KERN_IMAGE_START;
+ kernel_size = load_elf(ipl->kernel, NULL, NULL, &pentry, NULL,
NULL, 1, ELF_MACHINE, 0);
if (kernel_size == -1) {
kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
@@ -104,15 +105,19 @@ static int s390_ipl_init(SysBusDevice *dev)
fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel);
return -1;
}
- /* we have to overwrite values in the kernel image, which are "rom" */
- strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
-
/*
- * we can not rely on the ELF entry point, since up to 3.2 this
- * value was 0x800 (the SALIPL loader) and it wont work. For
- * all (Linux) cases 0x10000 (KERN_IMAGE_START) should be fine.
+ * Is it a Linux kernel (starting at 0x10000)? If yes, we fill in the
+ * kernel parameters here as well. Note: For old kernels (up to 3.2)
+ * we can not rely on the ELF entry point - it was 0x800 (the SALIPL
+ * loader) and it won't work. For this case we force it to 0x10000, too.
*/
- ipl->start_addr = KERN_IMAGE_START;
+ if (pentry == KERN_IMAGE_START || pentry == 0x800) {
+ ipl->start_addr = KERN_IMAGE_START;
+ /* Overwrite parameters in the kernel image, which are "rom" */
+ strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
+ } else {
+ ipl->start_addr = pentry;
+ }
}
if (ipl->initrd) {
ram_addr_t initrd_offset;
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 733d988871..0d4f6ae2f3 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -13,13 +13,14 @@
#include "exec/address-spaces.h"
#include "s390-virtio.h"
#include "hw/s390x/sclp.h"
+#include "hw/s390x/s390_flic.h"
#include "ioinst.h"
#include "css.h"
#include "virtio-ccw.h"
void io_subsystem_reset(void)
{
- DeviceState *css, *sclp;
+ DeviceState *css, *sclp, *flic;
css = DEVICE(object_resolve_path_type("", "virtual-css-bridge", NULL));
if (css) {
@@ -30,6 +31,10 @@ void io_subsystem_reset(void)
if (sclp) {
qdev_reset_all(sclp);
}
+ flic = DEVICE(object_resolve_path_type("", "s390-flic", NULL));
+ if (flic) {
+ qdev_reset_all(flic);
+ }
}
static int virtio_ccw_hcall_notify(const uint64_t *args)
@@ -99,6 +104,7 @@ static void ccw_init(QEMUMachineInitArgs *args)
s390_sclp_init();
s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
args->initrd_filename, "s390-ccw.img");
+ s390_flic_init();
/* register hypercalls */
virtio_ccw_register_hcalls();
diff --git a/hw/s390x/s390-virtio-hcall.c b/hw/s390x/s390-virtio-hcall.c
index ee626493c6..c7bdc2005d 100644
--- a/hw/s390x/s390-virtio-hcall.c
+++ b/hw/s390x/s390-virtio-hcall.c
@@ -26,11 +26,15 @@ void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn)
int s390_virtio_hypercall(CPUS390XState *env)
{
- s390_virtio_fn fn = s390_diag500_table[env->regs[1]];
-
- if (!fn) {
- return -EINVAL;
+ s390_virtio_fn fn;
+
+ if (env->regs[1] < MAX_DIAG_SUBCODES) {
+ fn = s390_diag500_table[env->regs[1]];
+ if (fn) {
+ env->regs[2] = fn(&env->regs[2]);
+ return 0;
+ }
}
- return fn(&env->regs[2]);
+ return -EINVAL;
}
diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c
index 9eeda97920..0f03fd18b9 100644
--- a/hw/s390x/s390-virtio.c
+++ b/hw/s390x/s390-virtio.c
@@ -36,6 +36,7 @@
#include "hw/s390x/s390-virtio-bus.h"
#include "hw/s390x/sclp.h"
+#include "hw/s390x/s390_flic.h"
#include "hw/s390x/s390-virtio.h"
//#define DEBUG_S390
@@ -251,6 +252,7 @@ static void s390_init(QEMUMachineInitArgs *args)
s390_sclp_init();
s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
args->initrd_filename, ZIPL_FILENAME);
+ s390_flic_init();
/* register hypercalls */
s390_virtio_register_hcalls();
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index 4e0c564c5c..d8ddf35e58 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -18,11 +18,12 @@
#include "sysemu/sysemu.h"
#include "hw/s390x/sclp.h"
+#include "hw/s390x/event-facility.h"
-static inline S390SCLPDevice *get_event_facility(void)
+static inline SCLPEventFacility *get_event_facility(void)
{
ObjectProperty *op = object_property_find(qdev_get_machine(),
- "s390-sclp-event-facility",
+ TYPE_SCLP_EVENT_FACILITY,
NULL);
assert(op);
return op->opaque;
@@ -89,9 +90,10 @@ static void sclp_read_cpu_info(SCCB *sccb)
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
}
-static void sclp_execute(SCCB *sccb, uint64_t code)
+static void sclp_execute(SCCB *sccb, uint32_t code)
{
- S390SCLPDevice *sdev = get_event_facility();
+ SCLPEventFacility *ef = get_event_facility();
+ SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
switch (code & SCLP_CMD_CODE_MASK) {
case SCLP_CMDW_READ_SCP_INFO:
@@ -102,12 +104,12 @@ static void sclp_execute(SCCB *sccb, uint64_t code)
sclp_read_cpu_info(sccb);
break;
default:
- sdev->sclp_command_handler(sdev->ef, sccb, code);
+ efc->command_handler(ef, sccb, code);
break;
}
}
-int sclp_service_call(uint32_t sccb, uint64_t code)
+int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
{
int r = 0;
SCCB work_sccb;
@@ -115,11 +117,16 @@ int sclp_service_call(uint32_t sccb, uint64_t code)
hwaddr sccb_len = sizeof(SCCB);
/* first some basic checks on program checks */
+ if (env->psw.mask & PSW_MASK_PSTATE) {
+ r = -PGM_PRIVILEGED;
+ goto out;
+ }
if (cpu_physical_memory_is_io(sccb)) {
r = -PGM_ADDRESSING;
goto out;
}
- if (sccb & ~0x7ffffff8ul) {
+ if ((sccb & ~0x1fffUL) == 0 || (sccb & ~0x1fffUL) == env->psa
+ || (sccb & ~0x7ffffff8UL) != 0) {
r = -PGM_SPECIFICATION;
goto out;
}
@@ -151,11 +158,13 @@ out:
void sclp_service_interrupt(uint32_t sccb)
{
- S390SCLPDevice *sdev = get_event_facility();
+ SCLPEventFacility *ef = get_event_facility();
+ SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
+
uint32_t param = sccb & ~3;
/* Indicate whether an event is still pending */
- param |= sdev->event_pending(sdev->ef) ? 1 : 0;
+ param |= efc->event_pending(ef) ? 1 : 0;
if (!param) {
/* No need to send an interrupt, there's nothing to be notified about */
@@ -168,47 +177,9 @@ void sclp_service_interrupt(uint32_t sccb)
void s390_sclp_init(void)
{
- DeviceState *dev = qdev_create(NULL, "s390-sclp-event-facility");
+ DeviceState *dev = qdev_create(NULL, TYPE_SCLP_EVENT_FACILITY);
- object_property_add_child(qdev_get_machine(), "s390-sclp-event-facility",
+ object_property_add_child(qdev_get_machine(), TYPE_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 const 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/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 50b89ad4aa..50a0acf1fe 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -909,7 +909,7 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
case VERIFY_16:
if ((buf[1] & 2) == 0) {
cmd->xfer = 0;
- } else if ((buf[1] & 4) == 1) {
+ } else if ((buf[1] & 4) != 0) {
cmd->xfer = 1;
}
cmd->xfer *= dev->blocksize;
@@ -1367,6 +1367,11 @@ const struct SCSISense sense_code_WRITE_PROTECTED = {
.key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
};
+/* Data Protection, Space Allocation Failed Write Protect */
+const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
+ .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
+};
+
/*
* scsi_build_sense
*
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index b4fadd2f24..48a28ae199 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -75,6 +75,8 @@ struct SCSIDiskState
bool media_event;
bool eject_request;
uint64_t wwn;
+ uint64_t port_wwn;
+ uint16_t port_index;
uint64_t max_unmap_size;
QEMUBH *bh;
char *version;
@@ -428,6 +430,9 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
case EINVAL:
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
break;
+ case ENOSPC:
+ scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED));
+ break;
default:
scsi_check_condition(r, SENSE_CODE(IO_ERROR));
break;
@@ -617,6 +622,24 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
stq_be_p(&outbuf[buflen], s->wwn);
buflen += 8;
}
+
+ if (s->port_wwn) {
+ outbuf[buflen++] = 0x61; // SAS / Binary
+ outbuf[buflen++] = 0x93; // PIV / Target port / NAA
+ outbuf[buflen++] = 0; // reserved
+ outbuf[buflen++] = 8;
+ stq_be_p(&outbuf[buflen], s->port_wwn);
+ buflen += 8;
+ }
+
+ if (s->port_index) {
+ outbuf[buflen++] = 0x61; // SAS / Binary
+ outbuf[buflen++] = 0x94; // PIV / Target port / relative target port
+ outbuf[buflen++] = 0; // reserved
+ outbuf[buflen++] = 4;
+ stw_be_p(&outbuf[buflen + 2], s->port_index);
+ buflen += 4;
+ }
break;
}
case 0xb0: /* block limits */
@@ -2536,6 +2559,8 @@ static Property scsi_hd_properties[] = {
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
SCSI_DISK_F_DPOFUA, false),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
+ DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
+ DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
DEFAULT_MAX_UNMAP_SIZE),
DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf),
@@ -2584,6 +2609,8 @@ static const TypeInfo scsi_hd_info = {
static Property scsi_cd_properties[] = {
DEFINE_SCSI_DISK_PROPERTIES(),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
+ DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
+ DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
DEFINE_PROP_END_OF_LIST(),
};
@@ -2647,6 +2674,8 @@ static Property scsi_disk_properties[] = {
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
SCSI_DISK_F_DPOFUA, false),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
+ DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
+ DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
DEFAULT_MAX_UNMAP_SIZE),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index f08b64e177..8d92e0da15 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -37,8 +37,6 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
#include <scsi/sg.h>
#include "block/scsi.h"
-#define SCSI_SENSE_BUF_SIZE 96
-
#define SG_ERR_DRIVER_TIMEOUT 0x06
#define SG_ERR_DRIVER_SENSE 0x08
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index c0c46d7f7c..e8bca390dd 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -60,7 +60,6 @@
#define VSCSI_MAX_SECTORS 4096
#define VSCSI_REQ_LIMIT 24
-#define SCSI_SENSE_BUF_SIZE 96
#define SRP_RSP_SENSE_DATA_LEN 18
typedef union vscsi_crq {
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 2957d90177..75adb68abc 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#include "hw/sysbus.h"
+#include "qemu/error-report.h"
#include "qemu/timer.h"
#include "hw/sparc/sun4m.h"
#include "hw/timer/m48t59.h"
@@ -561,6 +562,31 @@ static void tcx_init(hwaddr addr, int vram_size, int width,
}
}
+static void cg3_init(hwaddr addr, qemu_irq irq, int vram_size, int width,
+ int height, int depth)
+{
+ DeviceState *dev;
+ SysBusDevice *s;
+
+ dev = qdev_create(NULL, "cgthree");
+ qdev_prop_set_uint32(dev, "vram-size", vram_size);
+ qdev_prop_set_uint16(dev, "width", width);
+ qdev_prop_set_uint16(dev, "height", height);
+ qdev_prop_set_uint16(dev, "depth", depth);
+ qdev_prop_set_uint64(dev, "prom-addr", addr);
+ qdev_init_nofail(dev);
+ s = SYS_BUS_DEVICE(dev);
+
+ /* FCode ROM */
+ sysbus_mmio_map(s, 0, addr);
+ /* DAC */
+ sysbus_mmio_map(s, 1, addr + 0x400000ULL);
+ /* 8-bit plane */
+ sysbus_mmio_map(s, 2, addr + 0x800000ULL);
+
+ sysbus_connect_irq(s, 0, irq);
+}
+
/* NCR89C100/MACIO Internal ID register */
#define TYPE_MACIO_ID_REGISTER "macio_idreg"
@@ -914,13 +940,43 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
slavio_irq[16], iommu, &ledma_irq, 1);
if (graphic_depth != 8 && graphic_depth != 24) {
- fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
+ error_report("Unsupported depth: %d", graphic_depth);
exit (1);
}
num_vsimms = 0;
if (num_vsimms == 0) {
- tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
- graphic_depth);
+ if (vga_interface_type == VGA_CG3) {
+ if (graphic_depth != 8) {
+ error_report("Unsupported depth: %d", graphic_depth);
+ exit(1);
+ }
+
+ if (!(graphic_width == 1024 && graphic_height == 768) &&
+ !(graphic_width == 1152 && graphic_height == 900)) {
+ error_report("Unsupported resolution: %d x %d", graphic_width,
+ graphic_height);
+ exit(1);
+ }
+
+ /* sbus irq 5 */
+ cg3_init(hwdef->tcx_base, slavio_irq[11], 0x00100000,
+ graphic_width, graphic_height, graphic_depth);
+ } else {
+ /* If no display specified, default to TCX */
+ if (graphic_depth != 8 && graphic_depth != 24) {
+ error_report("Unsupported depth: %d", graphic_depth);
+ exit(1);
+ }
+
+ if (!(graphic_width == 1024 && graphic_height == 768)) {
+ error_report("Unsupported resolution: %d x %d",
+ graphic_width, graphic_height);
+ exit(1);
+ }
+
+ tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
+ graphic_depth);
+ }
}
for (i = num_vsimms; i < MAX_VSIMMS; i++) {
diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
index f75b914951..e4dcceaf23 100644
--- a/hw/timer/slavio_timer.c
+++ b/hw/timer/slavio_timer.c
@@ -51,7 +51,7 @@ typedef struct CPUTimerState {
ptimer_state *timer;
uint32_t count, counthigh, reached;
/* processor only */
- uint32_t running;
+ uint32_t run;
uint64_t limit;
} CPUTimerState;
@@ -177,7 +177,7 @@ static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr,
// only available in processor counter/timer
// read start/stop status
if (timer_index > 0) {
- ret = t->running;
+ ret = t->run;
} else {
ret = 0;
}
@@ -260,16 +260,15 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
case TIMER_STATUS:
if (slavio_timer_is_user(tc)) {
// start/stop user counter
- if ((val & 1) && !t->running) {
+ if (val & 1) {
trace_slavio_timer_mem_writel_status_start(timer_index);
ptimer_run(t->timer, 0);
- t->running = 1;
- } else if (!(val & 1) && t->running) {
+ } else {
trace_slavio_timer_mem_writel_status_stop(timer_index);
ptimer_stop(t->timer);
- t->running = 0;
}
}
+ t->run = val & 1;
break;
case TIMER_MODE:
if (timer_index == 0) {
@@ -284,8 +283,9 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
if (val & processor) { // counter -> user timer
qemu_irq_lower(curr_timer->irq);
// counters are always running
- ptimer_stop(curr_timer->timer);
- curr_timer->running = 0;
+ if (!curr_timer->run) {
+ ptimer_stop(curr_timer->timer);
+ }
// user timer limit is always the same
curr_timer->limit = TIMER_MAX_COUNT64;
ptimer_set_limit(curr_timer->timer,
@@ -296,13 +296,8 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
s->cputimer_mode |= processor;
trace_slavio_timer_mem_writel_mode_user(timer_index);
} else { // user timer -> counter
- // stop the user timer if it is running
- if (curr_timer->running) {
- ptimer_stop(curr_timer->timer);
- }
// start the counter
ptimer_run(curr_timer->timer, 0);
- curr_timer->running = 1;
// clear this processors user timer bit in config
// register
s->cputimer_mode &= ~processor;
@@ -340,7 +335,7 @@ static const VMStateDescription vmstate_timer = {
VMSTATE_UINT32(count, CPUTimerState),
VMSTATE_UINT32(counthigh, CPUTimerState),
VMSTATE_UINT32(reached, CPUTimerState),
- VMSTATE_UINT32(running, CPUTimerState),
+ VMSTATE_UINT32(run , CPUTimerState),
VMSTATE_PTIMER(timer, CPUTimerState),
VMSTATE_END_OF_LIST()
}
@@ -373,7 +368,7 @@ static void slavio_timer_reset(DeviceState *d)
ptimer_set_limit(curr_timer->timer,
LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
ptimer_run(curr_timer->timer, 0);
- curr_timer->running = 1;
+ curr_timer->run = 1;
}
}
s->cputimer_mode = 0;
diff --git a/include/hw/nvram/openbios_firmware_abi.h b/include/hw/nvram/openbios_firmware_abi.h
index 5e6e5d4d34..c66ee22685 100644
--- a/include/hw/nvram/openbios_firmware_abi.h
+++ b/include/hw/nvram/openbios_firmware_abi.h
@@ -62,6 +62,8 @@ Sun_init_header(struct Sun_nvram *header, const uint8_t *macaddr, int machine_id
header->type = 1;
header->machine_id = machine_id & 0xff;
memcpy(&header->macaddr, macaddr, 6);
+ memcpy(&header->hostid , &macaddr[3], 3);
+
/* Calculate checksum */
tmp = 0;
tmpptr = (uint8_t *)header;
diff --git a/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h
index 870edd46f6..6a062b668a 100644
--- a/include/hw/s390x/event-facility.h
+++ b/include/hw/s390x/event-facility.h
@@ -176,4 +176,23 @@ typedef struct SCLPEventClass {
bool (*can_handle_event)(uint8_t type);
} SCLPEventClass;
+#define TYPE_SCLP_EVENT_FACILITY "s390-sclp-event-facility"
+#define EVENT_FACILITY(obj) \
+ OBJECT_CHECK(SCLPEventFacility, (obj), TYPE_SCLP_EVENT_FACILITY)
+#define EVENT_FACILITY_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SCLPEventFacilityClass, (klass), \
+ TYPE_SCLP_EVENT_FACILITY)
+#define EVENT_FACILITY_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SCLPEventFacilityClass, (obj), \
+ TYPE_SCLP_EVENT_FACILITY)
+
+typedef struct SCLPEventFacility SCLPEventFacility;
+
+typedef struct SCLPEventFacilityClass {
+ DeviceClass parent_class;
+ int (*init)(SCLPEventFacility *ef);
+ void (*command_handler)(SCLPEventFacility *ef, SCCB *sccb, uint64_t code);
+ bool (*event_pending)(SCLPEventFacility *ef);
+} SCLPEventFacilityClass;
+
#endif
diff --git a/include/hw/s390x/s390_flic.h b/include/hw/s390x/s390_flic.h
new file mode 100644
index 0000000000..497b219e30
--- /dev/null
+++ b/include/hw/s390x/s390_flic.h
@@ -0,0 +1,33 @@
+/*
+ * QEMU S390x KVM floating interrupt controller (flic)
+ *
+ * Copyright 2014 IBM Corp.
+ * Author(s): Jens Freimann <jfrei@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.
+ */
+
+#ifndef __KVM_S390_FLIC_H
+#define __KVM_S390_FLIC_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_KVM_S390_FLIC "s390-flic"
+#define KVM_S390_FLIC(obj) \
+ OBJECT_CHECK(KVMS390FLICState, (obj), TYPE_KVM_S390_FLIC)
+
+typedef struct KVMS390FLICState {
+ SysBusDevice parent_obj;
+
+ uint32_t fd;
+} KVMS390FLICState;
+
+#ifdef CONFIG_KVM
+void s390_flic_init(void);
+#else
+static inline void s390_flic_init(void) { }
+#endif
+
+#endif /* __KVM_S390_FLIC_H */
diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h
index 35112d92b1..7ef16226df 100644
--- a/include/hw/s390x/sclp.h
+++ b/include/hw/s390x/sclp.h
@@ -161,30 +161,6 @@ 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);
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
index bf6da3d632..e5fc39d504 100644
--- a/include/hw/scsi/scsi.h
+++ b/include/hw/scsi/scsi.h
@@ -31,7 +31,7 @@ typedef struct SCSISense {
uint8_t ascq;
} SCSISense;
-#define SCSI_SENSE_BUF_SIZE 96
+#define SCSI_SENSE_BUF_SIZE 252
struct SCSICommand {
uint8_t buf[SCSI_CMD_BUF_SIZE];
@@ -223,6 +223,8 @@ extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
/* Data Protection, Write Protected */
extern const struct SCSISense sense_code_WRITE_PROTECTED;
+/* Data Protection, Space Allocation Failed Write Protect */
+extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
#define SENSE_CODE(x) sense_code_ ## x
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 495dae8c39..b90df9ada1 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -104,6 +104,7 @@ extern int autostart;
typedef enum {
VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL,
+ VGA_TCX, VGA_CG3,
} VGAInterfaceType;
extern int vga_interface_type;
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index d25da598ec..cb4c1eb8a0 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -16,6 +16,22 @@
#define __KVM_S390
+/* Device control API: s390-specific devices */
+#define KVM_DEV_FLIC_GET_ALL_IRQS 1
+#define KVM_DEV_FLIC_ENQUEUE 2
+#define KVM_DEV_FLIC_CLEAR_IRQS 3
+#define KVM_DEV_FLIC_APF_ENABLE 4
+#define KVM_DEV_FLIC_APF_DISABLE_WAIT 5
+/*
+ * We can have up to 4*64k pending subchannels + 8 adapter interrupts,
+ * as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts.
+ * There are also sclp and machine checks. This gives us
+ * sizeof(kvm_s390_irq)*(4*65536+8+64*64+1+1) = 72 * 266250 = 19170000
+ * Lets round up to 8192 pages.
+ */
+#define KVM_S390_MAX_FLOAT_IRQS 266250
+#define KVM_S390_FLIC_MAX_BUFFER 0x2000000
+
/* for KVM_GET_REGS and KVM_SET_REGS */
struct kvm_regs {
/* general purpose regs for s390 */
@@ -57,4 +73,7 @@ struct kvm_sync_regs {
#define KVM_REG_S390_EPOCHDIFF (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x2)
#define KVM_REG_S390_CPU_TIMER (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x3)
#define KVM_REG_S390_CLOCK_COMP (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x4)
+#define KVM_REG_S390_PFTOKEN (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x5)
+#define KVM_REG_S390_PFCOMPARE (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x6)
+#define KVM_REG_S390_PFSELECT (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x7)
#endif
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 77ad35cd67..e27a4b33cf 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -413,6 +413,8 @@ struct kvm_s390_psw {
#define KVM_S390_PROGRAM_INT 0xfffe0001u
#define KVM_S390_SIGP_SET_PREFIX 0xfffe0002u
#define KVM_S390_RESTART 0xfffe0003u
+#define KVM_S390_INT_PFAULT_INIT 0xfffe0004u
+#define KVM_S390_INT_PFAULT_DONE 0xfffe0005u
#define KVM_S390_MCHK 0xfffe1000u
#define KVM_S390_INT_VIRTIO 0xffff2603u
#define KVM_S390_INT_SERVICE 0xffff2401u
@@ -434,6 +436,69 @@ struct kvm_s390_interrupt {
__u64 parm64;
};
+struct kvm_s390_io_info {
+ __u16 subchannel_id;
+ __u16 subchannel_nr;
+ __u32 io_int_parm;
+ __u32 io_int_word;
+};
+
+struct kvm_s390_ext_info {
+ __u32 ext_params;
+ __u32 pad;
+ __u64 ext_params2;
+};
+
+struct kvm_s390_pgm_info {
+ __u64 trans_exc_code;
+ __u64 mon_code;
+ __u64 per_address;
+ __u32 data_exc_code;
+ __u16 code;
+ __u16 mon_class_nr;
+ __u8 per_code;
+ __u8 per_atmid;
+ __u8 exc_access_id;
+ __u8 per_access_id;
+ __u8 op_access_id;
+ __u8 pad[3];
+};
+
+struct kvm_s390_prefix_info {
+ __u32 address;
+};
+
+struct kvm_s390_extcall_info {
+ __u16 code;
+};
+
+struct kvm_s390_emerg_info {
+ __u16 code;
+};
+
+struct kvm_s390_mchk_info {
+ __u64 cr14;
+ __u64 mcic;
+ __u64 failing_storage_address;
+ __u32 ext_damage_code;
+ __u32 pad;
+ __u8 fixed_logout[16];
+};
+
+struct kvm_s390_irq {
+ __u64 type;
+ union {
+ struct kvm_s390_io_info io;
+ struct kvm_s390_ext_info ext;
+ struct kvm_s390_pgm_info pgm;
+ struct kvm_s390_emerg_info emerg;
+ struct kvm_s390_extcall_info extcall;
+ struct kvm_s390_prefix_info prefix;
+ struct kvm_s390_mchk_info mchk;
+ char reserved[64];
+ } u;
+};
+
/* for KVM_SET_GUEST_DEBUG */
#define KVM_GUESTDBG_ENABLE 0x00000001
@@ -855,6 +920,7 @@ struct kvm_device_attr {
#define KVM_DEV_VFIO_GROUP_ADD 1
#define KVM_DEV_VFIO_GROUP_DEL 2
#define KVM_DEV_TYPE_ARM_VGIC_V2 5
+#define KVM_DEV_TYPE_FLIC 6
/*
* ioctls for VM fds
diff --git a/pc-bios/QEMU,cgthree.bin b/pc-bios/QEMU,cgthree.bin
new file mode 100644
index 0000000000..6fec946207
--- /dev/null
+++ b/pc-bios/QEMU,cgthree.bin
Binary files differ
diff --git a/pc-bios/README b/pc-bios/README
index f1900686dc..5914200b23 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -11,8 +11,8 @@
firmware implementation. The goal is to implement a 100% IEEE
1275-1994 (referred to as Open Firmware) compliant firmware.
The included images for PowerPC (for 32 and 64 bit PPC CPUs),
- Sparc32 (including QEMU,tcx.bin) and Sparc64 are built from OpenBIOS SVN
- revision 1246.
+ Sparc32 (including QEMU,tcx.bin and QEMU,cgthree.bin) and Sparc64 are built
+ from OpenBIOS SVN revision 1246.
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index 6727f0ca39..f6223e77c2 100644
--- a/pc-bios/s390-ccw.img
+++ b/pc-bios/s390-ccw.img
Binary files differ
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index c5d533231b..5c33766533 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -10,7 +10,6 @@
#include "s390-ccw.h"
-struct subchannel_id blk_schid;
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
uint64_t boot_value;
@@ -23,13 +22,13 @@ void virtio_panic(const char *string)
static void virtio_setup(uint64_t dev_info)
{
+ struct subchannel_id blk_schid = { .one = 1 };
struct schib schib;
int i;
int r;
bool found = false;
bool check_devno = false;
uint16_t dev_no = -1;
- blk_schid.one = 1;
if (dev_info != -1) {
check_devno = true;
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 4d6e48fcbe..a46914dd68 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -124,6 +124,7 @@ static void vring_init(struct vring *vr, unsigned int num, void *p,
vr->used->flags = VRING_USED_F_NO_NOTIFY;
vr->used->idx = 0;
vr->used_idx = 0;
+ vr->next_idx = 0;
debug_print_addr("init vr", vr);
}
diff --git a/qapi-schema.json b/qapi-schema.json
index 1a5f93e100..193e7e4d3f 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -4483,10 +4483,11 @@
# Driver specific block device options for Quorum
#
# @blkverify: #optional true if the driver must print content mismatch
+# set to false by default
#
-# @children: the children block device to use
+# @children: the children block devices to use
#
-# @vote_threshold: the vote limit under which a read will fail
+# @vote-threshold: the vote limit under which a read will fail
#
# Since: 2.0
##
diff --git a/target-i386/cc_helper.c b/target-i386/cc_helper.c
index ee04092b4e..05dd12b5a7 100644
--- a/target-i386/cc_helper.c
+++ b/target-i386/cc_helper.c
@@ -103,7 +103,7 @@ target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1,
case CC_OP_EFLAGS:
return src1;
case CC_OP_CLR:
- return CC_Z;
+ return CC_Z | CC_P;
case CC_OP_MULB:
return compute_all_mulb(dst, src1);
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 6abcd23c48..0014acca7b 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -1261,6 +1261,9 @@ static inline void cpu_load_efer(CPUX86State *env, uint64_t val)
}
}
+/* fpu_helper.c */
+void cpu_set_mxcsr(CPUX86State *env, uint32_t val);
+
/* svm_helper.c */
void cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type,
uint64_t param);
diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c
index c0427fec7a..de7ba76a49 100644
--- a/target-i386/fpu_helper.c
+++ b/target-i386/fpu_helper.c
@@ -1179,7 +1179,7 @@ void helper_fxrstor(CPUX86State *env, target_ulong ptr, int data64)
if (env->cr[4] & CR4_OSFXSR_MASK) {
/* XXX: finish it */
- env->mxcsr = cpu_ldl_data(env, ptr + 0x18);
+ cpu_set_mxcsr(env, cpu_ldl_data(env, ptr + 0x18));
/* cpu_ldl_data(env, ptr + 0x1c); */
if (env->hflags & HF_CS64_MASK) {
nb_xmm_regs = 16;
@@ -1229,12 +1229,14 @@ floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper)
#define SSE_RC_CHOP 0x6000
#define SSE_FZ 0x8000
-static void update_sse_status(CPUX86State *env)
+void cpu_set_mxcsr(CPUX86State *env, uint32_t mxcsr)
{
int rnd_type;
+ env->mxcsr = mxcsr;
+
/* set rounding mode */
- switch (env->mxcsr & SSE_RC_MASK) {
+ switch (mxcsr & SSE_RC_MASK) {
default:
case SSE_RC_NEAR:
rnd_type = float_round_nearest_even;
@@ -1252,16 +1254,15 @@ static void update_sse_status(CPUX86State *env)
set_float_rounding_mode(rnd_type, &env->sse_status);
/* set denormals are zero */
- set_flush_inputs_to_zero((env->mxcsr & SSE_DAZ) ? 1 : 0, &env->sse_status);
+ set_flush_inputs_to_zero((mxcsr & SSE_DAZ) ? 1 : 0, &env->sse_status);
/* set flush to zero */
- set_flush_to_zero((env->mxcsr & SSE_FZ) ? 1 : 0, &env->fp_status);
+ set_flush_to_zero((mxcsr & SSE_FZ) ? 1 : 0, &env->fp_status);
}
void helper_ldmxcsr(CPUX86State *env, uint32_t val)
{
- env->mxcsr = val;
- update_sse_status(env);
+ cpu_set_mxcsr(env, val);
}
void helper_enter_mmx(CPUX86State *env)
diff --git a/target-i386/gdbstub.c b/target-i386/gdbstub.c
index 15bebeff89..d34e5355f7 100644
--- a/target-i386/gdbstub.c
+++ b/target-i386/gdbstub.c
@@ -222,7 +222,7 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return 4;
case IDX_MXCSR_REG:
- env->mxcsr = ldl_p(mem_buf);
+ cpu_set_mxcsr(env, ldl_p(mem_buf));
return 4;
}
}
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 5dd2450798..707ebd5ca0 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -748,7 +748,7 @@ static void gen_compute_eflags(DisasContext *s)
return;
}
if (s->cc_op == CC_OP_CLR) {
- tcg_gen_movi_tl(cpu_cc_src, CC_Z);
+ tcg_gen_movi_tl(cpu_cc_src, CC_Z | CC_P);
set_cc_op(s, CC_OP_EFLAGS);
return;
}
@@ -4284,22 +4284,48 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
if (is_xmm) {
op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
if (mod != 3) {
+ int sz = 4;
+
gen_lea_modrm(env, s, modrm);
op2_offset = offsetof(CPUX86State,xmm_t0);
- if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f && b != 0x5b) ||
- b == 0xc2)) {
- /* specific case for SSE single instructions */
+
+ switch (b) {
+ case 0x50 ... 0x5a:
+ case 0x5c ... 0x5f:
+ case 0xc2:
+ /* Most sse scalar operations. */
if (b1 == 2) {
- /* 32 bit access */
- gen_op_ld_v(s, MO_32, cpu_T[0], cpu_A0);
- tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0)));
+ sz = 2;
+ } else if (b1 == 3) {
+ sz = 3;
+ }
+ break;
+
+ case 0x2e: /* ucomis[sd] */
+ case 0x2f: /* comis[sd] */
+ if (b1 == 0) {
+ sz = 2;
} else {
- /* 64 bit access */
- gen_ldq_env_A0(s, offsetof(CPUX86State,
- xmm_t0.XMM_D(0)));
+ sz = 3;
}
- } else {
+ break;
+ }
+
+ switch (sz) {
+ case 2:
+ /* 32 bit access */
+ gen_op_ld_v(s, MO_32, cpu_T[0], cpu_A0);
+ tcg_gen_st32_tl(cpu_T[0], cpu_env,
+ offsetof(CPUX86State,xmm_t0.XMM_L(0)));
+ break;
+ case 3:
+ /* 64 bit access */
+ gen_ldq_env_A0(s, offsetof(CPUX86State, xmm_t0.XMM_D(0)));
+ break;
+ default:
+ /* 128 bit access */
gen_ldo_env_A0(s, op2_offset);
+ break;
}
} else {
rm = (modrm & 7) | REX_B(s);
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index ff57b806e4..1a8c1cc39f 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -83,6 +83,7 @@ static void s390_cpu_reset(CPUState *s)
S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
CPUS390XState *env = &cpu->env;
+ env->pfault_token = -1UL;
s390_del_running_cpu(cpu);
scc->parent_reset(s);
#if !defined(CONFIG_USER_ONLY)
@@ -105,6 +106,17 @@ static void s390_cpu_initial_reset(CPUState *s)
/* architectured initial values for CR 0 and 14 */
env->cregs[0] = CR0_RESET;
env->cregs[14] = CR14_RESET;
+
+ env->pfault_token = -1UL;
+
+#if defined(CONFIG_KVM)
+ /* Reset state inside the kernel that we cannot access yet from QEMU. */
+ if (kvm_enabled()) {
+ if (kvm_vcpu_ioctl(s, KVM_S390_INITIAL_RESET, NULL)) {
+ perror("Initial CPU reset failed");
+ }
+ }
+#endif
}
/* CPUClass:reset() */
@@ -123,6 +135,9 @@ static void s390_cpu_full_reset(CPUState *s)
/* architectured initial values for CR 0 and 14 */
env->cregs[0] = CR0_RESET;
env->cregs[14] = CR14_RESET;
+
+ env->pfault_token = -1UL;
+
/* set halted to 1 to make sure we can add the cpu in
* s390_ipl_cpu code, where CPUState::halted is set back to 0
* after incrementing the cpu counter */
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 6d46827990..effe84b102 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -122,6 +122,10 @@ typedef struct CPUS390XState {
uint64_t cputm;
uint32_t todpr;
+ uint64_t pfault_token;
+ uint64_t pfault_compare;
+ uint64_t pfault_select;
+
CPU_COMMON
/* reset does memset(0) up to here */
@@ -960,7 +964,7 @@ struct sysib_322 {
void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
target_ulong *raddr, int *flags);
-int sclp_service_call(uint32_t sccb, uint64_t code);
+int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code);
uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
uint64_t vr);
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index f60ccdc326..11feda9eb9 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -53,25 +53,28 @@
#define IPA0_B9 0xb900
#define IPA0_EB 0xeb00
-#define PRIV_SCLP_CALL 0x20
-#define PRIV_CSCH 0x30
-#define PRIV_HSCH 0x31
-#define PRIV_MSCH 0x32
-#define PRIV_SSCH 0x33
-#define PRIV_STSCH 0x34
-#define PRIV_TSCH 0x35
-#define PRIV_TPI 0x36
-#define PRIV_SAL 0x37
-#define PRIV_RSCH 0x38
-#define PRIV_STCRW 0x39
-#define PRIV_STCPS 0x3a
-#define PRIV_RCHP 0x3b
-#define PRIV_SCHM 0x3c
-#define PRIV_CHSC 0x5f
-#define PRIV_SIGA 0x74
-#define PRIV_XSCH 0x76
-#define PRIV_SQBS 0x8a
-#define PRIV_EQBS 0x9c
+#define PRIV_B2_SCLP_CALL 0x20
+#define PRIV_B2_CSCH 0x30
+#define PRIV_B2_HSCH 0x31
+#define PRIV_B2_MSCH 0x32
+#define PRIV_B2_SSCH 0x33
+#define PRIV_B2_STSCH 0x34
+#define PRIV_B2_TSCH 0x35
+#define PRIV_B2_TPI 0x36
+#define PRIV_B2_SAL 0x37
+#define PRIV_B2_RSCH 0x38
+#define PRIV_B2_STCRW 0x39
+#define PRIV_B2_STCPS 0x3a
+#define PRIV_B2_RCHP 0x3b
+#define PRIV_B2_SCHM 0x3c
+#define PRIV_B2_CHSC 0x5f
+#define PRIV_B2_SIGA 0x74
+#define PRIV_B2_XSCH 0x76
+
+#define PRIV_EB_SQBS 0x8a
+
+#define PRIV_B9_EQBS 0x9c
+
#define DIAG_IPL 0x308
#define DIAG_KVM_HYPERCALL 0x500
#define DIAG_KVM_BREAKPOINT 0x501
@@ -87,12 +90,14 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
};
static int cap_sync_regs;
+static int cap_async_pf;
static void *legacy_s390_alloc(size_t size);
int kvm_arch_init(KVMState *s)
{
cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS);
+ cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF);
if (!kvm_check_extension(s, KVM_CAP_S390_GMAP)
|| !kvm_check_extension(s, KVM_CAP_S390_COW)) {
phys_mem_set_alloc(legacy_s390_alloc);
@@ -178,6 +183,29 @@ int kvm_arch_put_registers(CPUState *cs, int level)
return ret;
}
+ if (cap_async_pf) {
+ reg.id = KVM_REG_S390_PFTOKEN;
+ reg.addr = (__u64)&(env->pfault_token);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+ if (ret < 0) {
+ return ret;
+ }
+
+ reg.id = KVM_REG_S390_PFCOMPARE;
+ reg.addr = (__u64)&(env->pfault_compare);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+ if (ret < 0) {
+ return ret;
+ }
+
+ reg.id = KVM_REG_S390_PFSELECT;
+ reg.addr = (__u64)&(env->pfault_select);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
if (cap_sync_regs &&
cs->kvm_run->kvm_valid_regs & KVM_SYNC_ACRS &&
cs->kvm_run->kvm_valid_regs & KVM_SYNC_CRS) {
@@ -282,6 +310,29 @@ int kvm_arch_get_registers(CPUState *cs)
return r;
}
+ if (cap_async_pf) {
+ reg.id = KVM_REG_S390_PFTOKEN;
+ reg.addr = (__u64)&(env->pfault_token);
+ r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+ if (r < 0) {
+ return r;
+ }
+
+ reg.id = KVM_REG_S390_PFCOMPARE;
+ reg.addr = (__u64)&(env->pfault_compare);
+ r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+ if (r < 0) {
+ return r;
+ }
+
+ reg.id = KVM_REG_S390_PFSELECT;
+ reg.addr = (__u64)&(env->pfault_select);
+ r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+ if (r < 0) {
+ return r;
+ }
+ }
+
return 0;
}
@@ -392,117 +443,128 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
uint16_t ipbh0)
{
CPUS390XState *env = &cpu->env;
- uint32_t sccb;
- uint64_t code;
+ uint64_t sccb;
+ uint32_t code;
int r = 0;
cpu_synchronize_state(CPU(cpu));
- if (env->psw.mask & PSW_MASK_PSTATE) {
- enter_pgmcheck(cpu, PGM_PRIVILEGED);
- return 0;
- }
sccb = env->regs[ipbh0 & 0xf];
code = env->regs[(ipbh0 & 0xf0) >> 4];
- r = sclp_service_call(sccb, code);
+ r = sclp_service_call(env, sccb, code);
if (r < 0) {
enter_pgmcheck(cpu, -r);
+ } else {
+ setcc(cpu, r);
}
- setcc(cpu, r);
return 0;
}
-static int kvm_handle_css_inst(S390CPU *cpu, struct kvm_run *run,
- uint8_t ipa0, uint8_t ipa1, uint8_t ipb)
+static int handle_b2(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
{
CPUS390XState *env = &cpu->env;
-
- if (ipa0 != 0xb2) {
- /* Not handled for now. */
- return -1;
- }
+ int rc = 0;
+ uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16;
cpu_synchronize_state(CPU(cpu));
switch (ipa1) {
- case PRIV_XSCH:
+ case PRIV_B2_XSCH:
ioinst_handle_xsch(cpu, env->regs[1]);
break;
- case PRIV_CSCH:
+ case PRIV_B2_CSCH:
ioinst_handle_csch(cpu, env->regs[1]);
break;
- case PRIV_HSCH:
+ case PRIV_B2_HSCH:
ioinst_handle_hsch(cpu, env->regs[1]);
break;
- case PRIV_MSCH:
+ case PRIV_B2_MSCH:
ioinst_handle_msch(cpu, env->regs[1], run->s390_sieic.ipb);
break;
- case PRIV_SSCH:
+ case PRIV_B2_SSCH:
ioinst_handle_ssch(cpu, env->regs[1], run->s390_sieic.ipb);
break;
- case PRIV_STCRW:
+ case PRIV_B2_STCRW:
ioinst_handle_stcrw(cpu, run->s390_sieic.ipb);
break;
- case PRIV_STSCH:
+ case PRIV_B2_STSCH:
ioinst_handle_stsch(cpu, env->regs[1], run->s390_sieic.ipb);
break;
- case PRIV_TSCH:
+ case PRIV_B2_TSCH:
/* We should only get tsch via KVM_EXIT_S390_TSCH. */
fprintf(stderr, "Spurious tsch intercept\n");
break;
- case PRIV_CHSC:
+ case PRIV_B2_CHSC:
ioinst_handle_chsc(cpu, run->s390_sieic.ipb);
break;
- case PRIV_TPI:
+ case PRIV_B2_TPI:
/* This should have been handled by kvm already. */
fprintf(stderr, "Spurious tpi intercept\n");
break;
- case PRIV_SCHM:
+ case PRIV_B2_SCHM:
ioinst_handle_schm(cpu, env->regs[1], env->regs[2],
run->s390_sieic.ipb);
break;
- case PRIV_RSCH:
+ case PRIV_B2_RSCH:
ioinst_handle_rsch(cpu, env->regs[1]);
break;
- case PRIV_RCHP:
+ case PRIV_B2_RCHP:
ioinst_handle_rchp(cpu, env->regs[1]);
break;
- case PRIV_STCPS:
+ case PRIV_B2_STCPS:
/* We do not provide this instruction, it is suppressed. */
break;
- case PRIV_SAL:
+ case PRIV_B2_SAL:
ioinst_handle_sal(cpu, env->regs[1]);
break;
- case PRIV_SIGA:
+ case PRIV_B2_SIGA:
/* Not provided, set CC = 3 for subchannel not operational */
setcc(cpu, 3);
break;
+ case PRIV_B2_SCLP_CALL:
+ rc = kvm_sclp_service_call(cpu, run, ipbh0);
+ break;
default:
- return -1;
+ rc = -1;
+ DPRINTF("KVM: unhandled PRIV: 0xb2%x\n", ipa1);
+ break;
}
- return 0;
+ return rc;
}
-static int handle_priv(S390CPU *cpu, struct kvm_run *run,
- uint8_t ipa0, uint8_t ipa1)
+static int handle_b9(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
{
int r = 0;
- uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16;
- uint8_t ipb = run->s390_sieic.ipb & 0xff;
- DPRINTF("KVM: PRIV: %d\n", ipa1);
switch (ipa1) {
- case PRIV_SCLP_CALL:
- r = kvm_sclp_service_call(cpu, run, ipbh0);
- break;
- default:
- r = kvm_handle_css_inst(cpu, run, ipa0, ipa1, ipb);
- if (r == -1) {
- DPRINTF("KVM: unhandled PRIV: 0x%x\n", ipa1);
- }
- break;
+ case PRIV_B9_EQBS:
+ /* just inject exception */
+ r = -1;
+ break;
+ default:
+ r = -1;
+ DPRINTF("KVM: unhandled PRIV: 0xb9%x\n", ipa1);
+ break;
+ }
+
+ return r;
+}
+
+static int handle_eb(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
+{
+ int r = 0;
+
+ switch (ipa1) {
+ case PRIV_EB_SQBS:
+ /* just inject exception */
+ r = -1;
+ break;
+ default:
+ r = -1;
+ DPRINTF("KVM: unhandled PRIV: 0xeb%x\n", ipa1);
+ break;
}
return r;
@@ -511,11 +573,16 @@ static int handle_priv(S390CPU *cpu, struct kvm_run *run,
static int handle_hypercall(S390CPU *cpu, struct kvm_run *run)
{
CPUS390XState *env = &cpu->env;
+ int ret;
cpu_synchronize_state(CPU(cpu));
- env->regs[2] = s390_virtio_hypercall(env);
+ ret = s390_virtio_hypercall(env);
+ if (ret == -EINVAL) {
+ enter_pgmcheck(cpu, PGM_SPECIFICATION);
+ return 0;
+ }
- return 0;
+ return ret;
}
static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run)
@@ -576,25 +643,22 @@ int kvm_s390_cpu_restart(S390CPU *cpu)
return 0;
}
-static int s390_cpu_initial_reset(S390CPU *cpu)
+static void sigp_initial_cpu_reset(void *arg)
{
- CPUState *cs = CPU(cpu);
- CPUS390XState *env = &cpu->env;
- int i;
+ CPUState *cpu = arg;
+ S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
- s390_del_running_cpu(cpu);
- if (kvm_vcpu_ioctl(cs, KVM_S390_INITIAL_RESET, NULL) < 0) {
- perror("cannot init reset vcpu");
- }
+ cpu_synchronize_state(cpu);
+ scc->initial_cpu_reset(cpu);
+}
- /* Manually zero out all registers */
- cpu_synchronize_state(cs);
- for (i = 0; i < 16; i++) {
- env->regs[i] = 0;
- }
+static void sigp_cpu_reset(void *arg)
+{
+ CPUState *cpu = arg;
+ S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
- DPRINTF("DONE: SIGP initial reset: %p\n", env);
- return 0;
+ cpu_synchronize_state(cpu);
+ scc->cpu_reset(cpu);
}
#define SIGP_ORDER_MASK 0x000000ff
@@ -628,10 +692,17 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
cc = kvm_s390_cpu_restart(target_cpu);
break;
case SIGP_SET_ARCH:
- /* make the caller panic */
- return -1;
+ *statusreg &= 0xffffffff00000000UL;
+ *statusreg |= SIGP_STAT_INVALID_PARAMETER;
+ cc = 1; /* status stored */
+ break;
case SIGP_INITIAL_CPU_RESET:
- cc = s390_cpu_initial_reset(target_cpu);
+ run_on_cpu(CPU(target_cpu), sigp_initial_cpu_reset, CPU(target_cpu));
+ cc = 0;
+ break;
+ case SIGP_CPU_RESET:
+ run_on_cpu(CPU(target_cpu), sigp_cpu_reset, CPU(target_cpu));
+ cc = 0;
break;
default:
DPRINTF("KVM: unknown SIGP: 0x%x\n", order_code);
@@ -656,9 +727,13 @@ static void handle_instruction(S390CPU *cpu, struct kvm_run *run)
run->s390_sieic.ipa, run->s390_sieic.ipb);
switch (ipa0) {
case IPA0_B2:
+ r = handle_b2(cpu, run, ipa1);
+ break;
case IPA0_B9:
+ r = handle_b9(cpu, run, ipa1);
+ break;
case IPA0_EB:
- r = handle_priv(cpu, run, ipa0 >> 8, ipa1);
+ r = handle_eb(cpu, run, ipa1);
break;
case IPA0_DIAG:
r = handle_diag(cpu, run, run->s390_sieic.ipb);
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index 10d04252d5..728456f295 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -93,7 +93,7 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
/* SCLP service call */
uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
{
- int r = sclp_service_call(r1, r2);
+ int r = sclp_service_call(env, r1, r2);
if (r < 0) {
program_interrupt(env, -r, 4);
return 0;
diff --git a/tests/qemu-iotests-quick.sh b/tests/qemu-iotests-quick.sh
index cf90de0b8b..c449e8ab4a 100755
--- a/tests/qemu-iotests-quick.sh
+++ b/tests/qemu-iotests-quick.sh
@@ -8,6 +8,7 @@ export QEMU_PROG="this_should_be_unused"
export QEMU_IMG_PROG="$(pwd)/qemu-img"
export QEMU_IO_PROG="$(pwd)/qemu-io"
+export QEMU_NBD_PROG="$(pwd)/qemu-nbd"
cd $SRC_PATH/tests/qemu-iotests
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
index f053f11942..b512d00cc8 100755
--- a/tests/qemu-iotests/081
+++ b/tests/qemu-iotests/081
@@ -56,6 +56,9 @@ function run_qemu()
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp | _filter_qemu_io
}
+test_quorum=$($QEMU_IMG --help|grep quorum)
+[ "$test_quorum" = "" ] && _supported_fmt quorum
+
quorum="file.driver=quorum,file.children.0.file.filename=$TEST_DIR/1.raw"
quorum="$quorum,file.children.1.file.filename=$TEST_DIR/2.raw"
quorum="$quorum,file.children.2.file.filename=$TEST_DIR/3.raw,file.vote-threshold=2"
diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out
index 4fe2f95f63..84aeb0c730 100644
--- a/tests/qemu-iotests/081.out
+++ b/tests/qemu-iotests/081.out
@@ -30,7 +30,7 @@ Testing: -drive file=TEST_DIR/2.IMGFMT,format=IMGFMT,if=none,id=drive2
QMP_VERSION
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "QUORUM_REPORT_BAD", "data": {"node-name": "", "ret": 0, "sectors-count": 20480, "sector-num": 0}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "QUORUM_REPORT_BAD", "data": {"node-name": "", "sectors-count": 20480, "sector-num": 0}}
read 10485760/10485760 bytes at offset 0
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": ""}
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 71e9a7462d..881079bdb9 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -203,7 +203,7 @@ _cleanup_test_img()
;;
rbd)
- rbd rm "$TEST_DIR/t.$IMGFMT" > /dev/null
+ rbd --no-progress rm "$TEST_DIR/t.$IMGFMT" > /dev/null
;;
sheepdog)
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index db127d924d..8dd8553035 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -58,30 +58,30 @@
049 rw auto
050 rw auto backing quick
051 rw auto
-052 rw auto backing
-053 rw auto
-054 rw auto
+052 rw auto backing quick
+053 rw auto quick
+054 rw auto quick
055 rw auto
056 rw auto backing
057 rw auto
-058 rw auto
-059 rw auto
-060 rw auto
-061 rw auto
-062 rw auto
-063 rw auto
-064 rw auto
+058 rw auto quick
+059 rw auto quick
+060 rw auto quick
+061 rw auto quick
+062 rw auto quick
+063 rw auto quick
+064 rw auto quick
065 rw auto
-066 rw auto
+066 rw auto quick
067 rw auto
068 rw auto
-069 rw auto
-070 rw auto
+069 rw auto quick
+070 rw auto quick
071 rw auto
-072 rw auto
-073 rw auto
-074 rw auto
-077 rw auto
+072 rw auto quick
+073 rw auto quick
+074 rw auto quick
+077 rw auto quick
079 rw auto
081 rw auto
082 rw auto quick
diff --git a/trace-events b/trace-events
index 580281d9ca..d86f98cb31 100644
--- a/trace-events
+++ b/trace-events
@@ -1162,6 +1162,11 @@ css_io_interrupt(int cssid, int ssid, int schid, uint32_t intparm, uint8_t isc,
virtio_ccw_interpret_ccw(int cssid, int ssid, int schid, int cmd_code) "VIRTIO-CCW: %x.%x.%04x: interpret command %x"
virtio_ccw_new_device(int cssid, int ssid, int schid, int devno, const char *devno_mode) "VIRTIO-CCW: add subchannel %x.%x.%04x, devno %04x (%s)"
+# hw/intc/s390_flic.c
+flic_create_device(int err) "flic: create device failed %d"
+flic_no_device_api(int err) "flic: no Device Contral API support %d"
+flic_reset_failed(int err) "flic: reset failed %d"
+
# migration.c
migrate_set_state(int new_state) "new state %d"
diff --git a/vl.c b/vl.c
index 1d27b34301..52ee67e4be 100644
--- a/vl.c
+++ b/vl.c
@@ -2031,6 +2031,16 @@ static bool qxl_vga_available(void)
return object_class_by_name("qxl-vga");
}
+static bool tcx_vga_available(void)
+{
+ return object_class_by_name("SUNW,tcx");
+}
+
+static bool cg3_vga_available(void)
+{
+ return object_class_by_name("cgthree");
+}
+
static void select_vgahw (const char *p)
{
const char *opts;
@@ -2066,6 +2076,20 @@ static void select_vgahw (const char *p)
fprintf(stderr, "Error: QXL VGA not available\n");
exit(0);
}
+ } else if (strstart(p, "tcx", &opts)) {
+ if (tcx_vga_available()) {
+ vga_interface_type = VGA_TCX;
+ } else {
+ fprintf(stderr, "Error: TCX framebuffer not available\n");
+ exit(0);
+ }
+ } else if (strstart(p, "cg3", &opts)) {
+ if (cg3_vga_available()) {
+ vga_interface_type = VGA_CG3;
+ } else {
+ fprintf(stderr, "Error: CG3 framebuffer not available\n");
+ exit(0);
+ }
} else if (!strstart(p, "none", &opts)) {
invalid_vga:
fprintf(stderr, "Unknown vga type: %s\n", p);