diff options
51 files changed, 806 insertions, 433 deletions
@@ -1 +1 @@ -1.0.92 +1.0.93 diff --git a/audio/audio.c b/audio/audio.c index bd9237e9d3..583ee51eab 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1775,10 +1775,12 @@ static void audio_atexit (void) HWVoiceOut *hwo = NULL; HWVoiceIn *hwi = NULL; - while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) { + while ((hwo = audio_pcm_hw_find_any_out (hwo))) { SWVoiceCap *sc; - hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE); + if (hwo->enabled) { + hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE); + } hwo->pcm_ops->fini_out (hwo); for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) { @@ -1791,8 +1793,10 @@ static void audio_atexit (void) } } - while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) { - hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE); + while ((hwi = audio_pcm_hw_find_any_in (hwi))) { + if (hwi->enabled) { + hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE); + } hwi->pcm_ops->fini_in (hwi); } diff --git a/audio/mixeng.c b/audio/mixeng.c index 5446be674f..02a9d9fb92 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -33,7 +33,8 @@ #define ENDIAN_CONVERT(v) (v) /* Signed 8 bit */ -#define IN_T int8_t +#define BSIZE 8 +#define ITYPE int #define IN_MIN SCHAR_MIN #define IN_MAX SCHAR_MAX #define SIGNED @@ -42,25 +43,29 @@ #undef SIGNED #undef IN_MAX #undef IN_MIN -#undef IN_T +#undef BSIZE +#undef ITYPE #undef SHIFT /* Unsigned 8 bit */ -#define IN_T uint8_t +#define BSIZE 8 +#define ITYPE uint #define IN_MIN 0 #define IN_MAX UCHAR_MAX #define SHIFT 8 #include "mixeng_template.h" #undef IN_MAX #undef IN_MIN -#undef IN_T +#undef BSIZE +#undef ITYPE #undef SHIFT #undef ENDIAN_CONVERT #undef ENDIAN_CONVERSION /* Signed 16 bit */ -#define IN_T int16_t +#define BSIZE 16 +#define ITYPE int #define IN_MIN SHRT_MIN #define IN_MAX SHRT_MAX #define SIGNED @@ -78,11 +83,13 @@ #undef SIGNED #undef IN_MAX #undef IN_MIN -#undef IN_T +#undef BSIZE +#undef ITYPE #undef SHIFT /* Unsigned 16 bit */ -#define IN_T uint16_t +#define BSIZE 16 +#define ITYPE uint #define IN_MIN 0 #define IN_MAX USHRT_MAX #define SHIFT 16 @@ -98,11 +105,13 @@ #undef ENDIAN_CONVERSION #undef IN_MAX #undef IN_MIN -#undef IN_T +#undef BSIZE +#undef ITYPE #undef SHIFT /* Signed 32 bit */ -#define IN_T int32_t +#define BSIZE 32 +#define ITYPE int #define IN_MIN INT32_MIN #define IN_MAX INT32_MAX #define SIGNED @@ -120,11 +129,13 @@ #undef SIGNED #undef IN_MAX #undef IN_MIN -#undef IN_T +#undef BSIZE +#undef ITYPE #undef SHIFT /* Unsigned 32 bit */ -#define IN_T uint32_t +#define BSIZE 32 +#define ITYPE uint #define IN_MIN 0 #define IN_MAX UINT32_MAX #define SHIFT 32 @@ -140,7 +151,8 @@ #undef ENDIAN_CONVERSION #undef IN_MAX #undef IN_MIN -#undef IN_T +#undef BSIZE +#undef ITYPE #undef SHIFT t_sample *mixeng_conv[2][2][2][3] = { diff --git a/audio/mixeng_template.h b/audio/mixeng_template.h index e644c231ad..30849a62a1 100644 --- a/audio/mixeng_template.h +++ b/audio/mixeng_template.h @@ -31,7 +31,8 @@ #define HALF (IN_MAX >> 1) #endif -#define ET glue (ENDIAN_CONVERSION, glue (_, IN_T)) +#define ET glue (ENDIAN_CONVERSION, glue (glue (glue (_, ITYPE), BSIZE), _t)) +#define IN_T glue (glue (ITYPE, BSIZE), _t) #ifdef FLOAT_MIXENG static mixeng_real inline glue (conv_, ET) (IN_T v) @@ -150,3 +151,4 @@ static void glue (glue (clip_, ET), _from_mono) #undef ET #undef HALF +#undef IN_T diff --git a/block/iscsi.c b/block/iscsi.c index d37c4ee171..22888a0845 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -25,10 +25,12 @@ #include "config-host.h" #include <poll.h> +#include <arpa/inet.h> #include "qemu-common.h" #include "qemu-error.h" #include "block_int.h" #include "trace.h" +#include "hw/scsi-defs.h" #include <iscsi/iscsi.h> #include <iscsi/scsi-lowlevel.h> @@ -37,8 +39,10 @@ typedef struct IscsiLun { struct iscsi_context *iscsi; int lun; + enum scsi_inquiry_peripheral_device_type type; int block_size; - unsigned long num_blocks; + uint64_t num_blocks; + int events; } IscsiLun; typedef struct IscsiAIOCB { @@ -104,11 +108,27 @@ static void iscsi_set_events(IscsiLun *iscsilun) { struct iscsi_context *iscsi = iscsilun->iscsi; + int ev; - qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process_read, - (iscsi_which_events(iscsi) & POLLOUT) - ? iscsi_process_write : NULL, - iscsi_process_flush, iscsilun); + /* We always register a read handler. */ + ev = POLLIN; + ev |= iscsi_which_events(iscsi); + if (ev != iscsilun->events) { + qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), + iscsi_process_read, + (ev & POLLOUT) ? iscsi_process_write : NULL, + iscsi_process_flush, + iscsilun); + + } + + /* If we just added an event, the callback might be delayed + * unless we call qemu_notify_event(). + */ + if (ev & ~iscsilun->events) { + qemu_notify_event(); + } + iscsilun->events = ev; } static void @@ -161,12 +181,12 @@ iscsi_readv_writev_bh_cb(void *p) static void -iscsi_aio_write10_cb(struct iscsi_context *iscsi, int status, +iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status, void *command_data, void *opaque) { IscsiAIOCB *acb = opaque; - trace_iscsi_aio_write10_cb(iscsi, status, acb, acb->canceled); + trace_iscsi_aio_write16_cb(iscsi, status, acb, acb->canceled); g_free(acb->buf); @@ -179,7 +199,7 @@ iscsi_aio_write10_cb(struct iscsi_context *iscsi, int status, acb->status = 0; if (status < 0) { - error_report("Failed to write10 data to iSCSI lun. %s", + error_report("Failed to write16 data to iSCSI lun. %s", iscsi_get_error(iscsi)); acb->status = -EIO; } @@ -204,12 +224,9 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, struct iscsi_context *iscsi = iscsilun->iscsi; IscsiAIOCB *acb; size_t size; - int fua = 0; - - /* set FUA on writes when cache mode is write through */ - if (!(bs->open_flags & BDRV_O_CACHE_WB)) { - fua = 1; - } + uint32_t num_sectors; + uint64_t lba; + struct iscsi_data data; acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque); trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb); @@ -219,18 +236,44 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, acb->canceled = 0; - /* XXX we should pass the iovec to write10 to avoid the extra copy */ + /* XXX we should pass the iovec to write16 to avoid the extra copy */ /* this will allow us to get rid of 'buf' completely */ size = nb_sectors * BDRV_SECTOR_SIZE; acb->buf = g_malloc(size); qemu_iovec_to_buffer(acb->qiov, acb->buf); - acb->task = iscsi_write10_task(iscsi, iscsilun->lun, acb->buf, size, - sector_qemu2lun(sector_num, iscsilun), - fua, 0, iscsilun->block_size, - iscsi_aio_write10_cb, acb); + + + acb->task = malloc(sizeof(struct scsi_task)); if (acb->task == NULL) { - error_report("iSCSI: Failed to send write10 command. %s", - iscsi_get_error(iscsi)); + error_report("iSCSI: Failed to allocate task for scsi WRITE16 " + "command. %s", iscsi_get_error(iscsi)); + qemu_aio_release(acb); + return NULL; + } + memset(acb->task, 0, sizeof(struct scsi_task)); + + acb->task->xfer_dir = SCSI_XFER_WRITE; + acb->task->cdb_size = 16; + acb->task->cdb[0] = 0x8a; + if (!(bs->open_flags & BDRV_O_CACHE_WB)) { + /* set FUA on writes when cache mode is write through */ + acb->task->cdb[1] |= 0x04; + } + lba = sector_qemu2lun(sector_num, iscsilun); + *(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32); + *(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff); + num_sectors = size / iscsilun->block_size; + *(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors); + acb->task->expxferlen = size; + + data.data = acb->buf; + data.size = size; + + if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task, + iscsi_aio_write16_cb, + &data, + acb) != 0) { + scsi_free_scsi_task(acb->task); g_free(acb->buf); qemu_aio_release(acb); return NULL; @@ -242,12 +285,12 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, } static void -iscsi_aio_read10_cb(struct iscsi_context *iscsi, int status, +iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status, void *command_data, void *opaque) { IscsiAIOCB *acb = opaque; - trace_iscsi_aio_read10_cb(iscsi, status, acb, acb->canceled); + trace_iscsi_aio_read16_cb(iscsi, status, acb, acb->canceled); if (acb->canceled != 0) { qemu_aio_release(acb); @@ -258,7 +301,7 @@ iscsi_aio_read10_cb(struct iscsi_context *iscsi, int status, acb->status = 0; if (status != 0) { - error_report("Failed to read10 data from iSCSI lun. %s", + error_report("Failed to read16 data from iSCSI lun. %s", iscsi_get_error(iscsi)); acb->status = -EIO; } @@ -277,8 +320,10 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num, IscsiLun *iscsilun = bs->opaque; struct iscsi_context *iscsi = iscsilun->iscsi; IscsiAIOCB *acb; - size_t qemu_read_size, lun_read_size; + size_t qemu_read_size; int i; + uint64_t lba; + uint32_t num_sectors; qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors; @@ -303,16 +348,44 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num, acb->read_offset = bdrv_offset % iscsilun->block_size; } - lun_read_size = (qemu_read_size + iscsilun->block_size - + acb->read_offset - 1) - / iscsilun->block_size * iscsilun->block_size; - acb->task = iscsi_read10_task(iscsi, iscsilun->lun, - sector_qemu2lun(sector_num, iscsilun), - lun_read_size, iscsilun->block_size, - iscsi_aio_read10_cb, acb); + num_sectors = (qemu_read_size + iscsilun->block_size + + acb->read_offset - 1) + / iscsilun->block_size; + + acb->task = malloc(sizeof(struct scsi_task)); if (acb->task == NULL) { - error_report("iSCSI: Failed to send read10 command. %s", - iscsi_get_error(iscsi)); + error_report("iSCSI: Failed to allocate task for scsi READ16 " + "command. %s", iscsi_get_error(iscsi)); + qemu_aio_release(acb); + return NULL; + } + memset(acb->task, 0, sizeof(struct scsi_task)); + + acb->task->xfer_dir = SCSI_XFER_READ; + lba = sector_qemu2lun(sector_num, iscsilun); + acb->task->expxferlen = qemu_read_size; + + switch (iscsilun->type) { + case TYPE_DISK: + acb->task->cdb_size = 16; + acb->task->cdb[0] = 0x88; + *(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32); + *(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff); + *(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors); + break; + default: + acb->task->cdb_size = 10; + acb->task->cdb[0] = 0x28; + *(uint32_t *)&acb->task->cdb[2] = htonl(lba); + *(uint16_t *)&acb->task->cdb[7] = htons(num_sectors); + break; + } + + if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task, + iscsi_aio_read16_cb, + NULL, + acb) != 0) { + scsi_free_scsi_task(acb->task); qemu_aio_release(acb); return NULL; } @@ -491,6 +564,98 @@ iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status, } static void +iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status, + void *command_data, void *opaque) +{ + struct IscsiTask *itask = opaque; + struct scsi_readcapacity10 *rc10; + struct scsi_task *task = command_data; + + if (status != 0) { + error_report("iSCSI: Failed to read capacity of iSCSI lun. %s", + iscsi_get_error(iscsi)); + itask->status = 1; + itask->complete = 1; + scsi_free_scsi_task(task); + return; + } + + rc10 = scsi_datain_unmarshall(task); + if (rc10 == NULL) { + error_report("iSCSI: Failed to unmarshall readcapacity10 data."); + itask->status = 1; + itask->complete = 1; + scsi_free_scsi_task(task); + return; + } + + itask->iscsilun->block_size = rc10->block_size; + itask->iscsilun->num_blocks = rc10->lba + 1; + itask->bs->total_sectors = itask->iscsilun->num_blocks * + itask->iscsilun->block_size / BDRV_SECTOR_SIZE ; + + itask->status = 0; + itask->complete = 1; + scsi_free_scsi_task(task); +} + +static void +iscsi_inquiry_cb(struct iscsi_context *iscsi, int status, void *command_data, + void *opaque) +{ + struct IscsiTask *itask = opaque; + struct scsi_task *task = command_data; + struct scsi_inquiry_standard *inq; + + if (status != 0) { + itask->status = 1; + itask->complete = 1; + scsi_free_scsi_task(task); + return; + } + + inq = scsi_datain_unmarshall(task); + if (inq == NULL) { + error_report("iSCSI: Failed to unmarshall inquiry data."); + itask->status = 1; + itask->complete = 1; + scsi_free_scsi_task(task); + return; + } + + itask->iscsilun->type = inq->periperal_device_type; + + scsi_free_scsi_task(task); + + switch (itask->iscsilun->type) { + case TYPE_DISK: + task = iscsi_readcapacity16_task(iscsi, itask->iscsilun->lun, + iscsi_readcapacity16_cb, opaque); + if (task == NULL) { + error_report("iSCSI: failed to send readcapacity16 command."); + itask->status = 1; + itask->complete = 1; + return; + } + break; + case TYPE_ROM: + task = iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun, + 0, 0, + iscsi_readcapacity10_cb, opaque); + if (task == NULL) { + error_report("iSCSI: failed to send readcapacity16 command."); + itask->status = 1; + itask->complete = 1; + return; + } + break; + default: + itask->status = 0; + itask->complete = 1; + } +} + +static void iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data, void *opaque) { @@ -503,10 +668,11 @@ iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data, return; } - task = iscsi_readcapacity16_task(iscsi, itask->iscsilun->lun, - iscsi_readcapacity16_cb, opaque); + task = iscsi_inquiry_task(iscsi, itask->iscsilun->lun, + 0, 0, 36, + iscsi_inquiry_cb, opaque); if (task == NULL) { - error_report("iSCSI: failed to send readcapacity16 command."); + error_report("iSCSI: failed to send inquiry command."); itask->status = 1; itask->complete = 1; return; diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 10c22fe12b..4b3345b11b 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -762,7 +762,6 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset, uint64_t *host_offset, unsigned int *nb_clusters) { BDRVQcowState *s = bs->opaque; - int64_t cluster_offset; QCowL2Meta *old_alloc; trace_qcow2_do_alloc_clusters_offset(qemu_coroutine_self(), guest_offset, @@ -808,17 +807,21 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset, /* Allocate new clusters */ trace_qcow2_cluster_alloc_phys(qemu_coroutine_self()); if (*host_offset == 0) { - cluster_offset = qcow2_alloc_clusters(bs, *nb_clusters * s->cluster_size); + int64_t cluster_offset = + qcow2_alloc_clusters(bs, *nb_clusters * s->cluster_size); + if (cluster_offset < 0) { + return cluster_offset; + } + *host_offset = cluster_offset; + return 0; } else { - cluster_offset = *host_offset; - *nb_clusters = qcow2_alloc_clusters_at(bs, cluster_offset, *nb_clusters); - } - - if (cluster_offset < 0) { - return cluster_offset; + int ret = qcow2_alloc_clusters_at(bs, *host_offset, *nb_clusters); + if (ret < 0) { + return ret; + } + *nb_clusters = ret; + return 0; } - *host_offset = cluster_offset; - return 0; } /* diff --git a/block/qcow2.c b/block/qcow2.c index 655799c6a0..c2e49cded3 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -919,7 +919,8 @@ int qcow2_update_header(BlockDriverState *bs) ret = sizeof(*header); break; default: - return -EINVAL; + ret = -EINVAL; + goto fail; } buf += ret; diff --git a/block/sheepdog.c b/block/sheepdog.c index e01d371680..6d52277a89 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -468,7 +468,7 @@ static int connect_to_sdog(const char *addr, const char *port) if (ret) { error_report("unable to get address info %s, %s", addr, strerror(errno)); - return -1; + return -errno; } for (res = res0; res; res = res->ai_next) { @@ -495,7 +495,7 @@ static int connect_to_sdog(const char *addr, const char *port) dprintf("connected to %s:%s\n", addr, port); goto success; } - fd = -1; + fd = -errno; error_report("failed connect to %s:%s", addr, port); success: freeaddrinfo(res0); @@ -510,12 +510,13 @@ static int send_req(int sockfd, SheepdogReq *hdr, void *data, ret = qemu_send_full(sockfd, hdr, sizeof(*hdr), 0); if (ret < sizeof(*hdr)) { error_report("failed to send a req, %s", strerror(errno)); - return ret; + return -errno; } ret = qemu_send_full(sockfd, data, *wlen, 0); if (ret < *wlen) { error_report("failed to send a req, %s", strerror(errno)); + ret = -errno; } return ret; @@ -553,6 +554,7 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data, ret = qemu_recv_full(sockfd, hdr, sizeof(*hdr), 0); if (ret < sizeof(*hdr)) { error_report("failed to get a rsp, %s", strerror(errno)); + ret = -errno; goto out; } @@ -564,6 +566,7 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data, ret = qemu_recv_full(sockfd, data, *rlen, 0); if (ret < *rlen) { error_report("failed to get the data, %s", strerror(errno)); + ret = -errno; goto out; } } @@ -587,6 +590,7 @@ static int do_co_req(int sockfd, SheepdogReq *hdr, void *data, ret = qemu_co_recv(sockfd, hdr, sizeof(*hdr)); if (ret < sizeof(*hdr)) { error_report("failed to get a rsp, %s", strerror(errno)); + ret = -errno; goto out; } @@ -598,6 +602,7 @@ static int do_co_req(int sockfd, SheepdogReq *hdr, void *data, ret = qemu_co_recv(sockfd, data, *rlen); if (ret < *rlen) { error_report("failed to get the data, %s", strerror(errno)); + ret = -errno; goto out; } } @@ -787,7 +792,7 @@ static int get_sheep_fd(BDRVSheepdogState *s) fd = connect_to_sdog(s->addr, s->port); if (fd < 0) { error_report("%s", strerror(errno)); - return -1; + return fd; } socket_set_nonblock(fd); @@ -796,7 +801,7 @@ static int get_sheep_fd(BDRVSheepdogState *s) if (ret) { error_report("%s", strerror(errno)); closesocket(fd); - return -1; + return -errno; } qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request, s); @@ -883,7 +888,7 @@ static int find_vdi_name(BDRVSheepdogState *s, char *filename, uint32_t snapid, fd = connect_to_sdog(s->addr, s->port); if (fd < 0) { - return -1; + return fd; } memset(buf, 0, sizeof(buf)); @@ -904,14 +909,17 @@ static int find_vdi_name(BDRVSheepdogState *s, char *filename, uint32_t snapid, ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen); if (ret) { - ret = -1; goto out; } if (rsp->result != SD_RES_SUCCESS) { error_report("cannot get vdi info, %s, %s %d %s", sd_strerror(rsp->result), filename, snapid, tag); - ret = -1; + if (rsp->result == SD_RES_NO_VDI) { + ret = -ENOENT; + } else { + ret = -EIO; + } goto out; } *vid = rsp->vdi_id; @@ -980,7 +988,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, if (ret < 0) { qemu_co_mutex_unlock(&s->lock); error_report("failed to send a req, %s", strerror(errno)); - return -EIO; + return -errno; } if (wlen) { @@ -988,7 +996,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, if (ret < 0) { qemu_co_mutex_unlock(&s->lock); error_report("failed to send a data, %s", strerror(errno)); - return -EIO; + return -errno; } } @@ -1038,7 +1046,7 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies, ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen); if (ret) { error_report("failed to send a request to the sheep"); - return -1; + return ret; } switch (rsp->result) { @@ -1046,7 +1054,7 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies, return 0; default: error_report("%s", sd_strerror(rsp->result)); - return -1; + return -EIO; } } @@ -1082,10 +1090,12 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags) memset(vdi, 0, sizeof(vdi)); memset(tag, 0, sizeof(tag)); if (parse_vdiname(s, filename, vdi, &snapid, tag) < 0) { + ret = -EINVAL; goto out; } s->fd = get_sheep_fd(s); if (s->fd < 0) { + ret = s->fd; goto out; } @@ -1099,11 +1109,12 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags) s->flush_fd = connect_to_sdog(s->addr, s->port); if (s->flush_fd < 0) { error_report("failed to connect"); + ret = s->flush_fd; goto out; } } - if (snapid) { + if (snapid || tag[0] != '\0') { dprintf("%" PRIx32 " snapshot inode was open.\n", vid); s->is_snapshot = 1; } @@ -1111,6 +1122,7 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags) fd = connect_to_sdog(s->addr, s->port); if (fd < 0) { error_report("failed to connect"); + ret = fd; goto out; } @@ -1139,7 +1151,7 @@ out: closesocket(s->fd); } g_free(buf); - return -1; + return ret; } static int do_sd_create(char *filename, int64_t vdi_size, @@ -1154,7 +1166,7 @@ static int do_sd_create(char *filename, int64_t vdi_size, fd = connect_to_sdog(addr, port); if (fd < 0) { - return -EIO; + return fd; } memset(buf, 0, sizeof(buf)); @@ -1177,7 +1189,7 @@ static int do_sd_create(char *filename, int64_t vdi_size, closesocket(fd); if (ret) { - return -EIO; + return ret; } if (rsp->result != SD_RES_SUCCESS) { @@ -1237,24 +1249,26 @@ out: static int sd_create(const char *filename, QEMUOptionParameter *options) { - int ret; + int ret = 0; uint32_t vid = 0, base_vid = 0; int64_t vdi_size = 0; char *backing_file = NULL; - BDRVSheepdogState s; + BDRVSheepdogState *s; char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN]; uint32_t snapid; int prealloc = 0; const char *vdiname; + s = g_malloc0(sizeof(BDRVSheepdogState)); + strstart(filename, "sheepdog:", &vdiname); - memset(&s, 0, sizeof(s)); memset(vdi, 0, sizeof(vdi)); memset(tag, 0, sizeof(tag)); - if (parse_vdiname(&s, vdiname, vdi, &snapid, tag) < 0) { + if (parse_vdiname(s, vdiname, vdi, &snapid, tag) < 0) { error_report("invalid filename"); - return -EINVAL; + ret = -EINVAL; + goto out; } while (options && options->name) { @@ -1270,7 +1284,8 @@ static int sd_create(const char *filename, QEMUOptionParameter *options) } else { error_report("Invalid preallocation mode: '%s'", options->value.s); - return -EINVAL; + ret = -EINVAL; + goto out; } } options++; @@ -1278,7 +1293,8 @@ static int sd_create(const char *filename, QEMUOptionParameter *options) if (vdi_size > SD_MAX_VDI_SIZE) { error_report("too big image size"); - return -EINVAL; + ret = -EINVAL; + goto out; } if (backing_file) { @@ -1290,31 +1306,37 @@ static int sd_create(const char *filename, QEMUOptionParameter *options) drv = bdrv_find_protocol(backing_file); if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) { error_report("backing_file must be a sheepdog image"); - return -EINVAL; + ret = -EINVAL; + goto out; } ret = bdrv_file_open(&bs, backing_file, 0); - if (ret < 0) - return -EIO; + if (ret < 0) { + goto out; + } s = bs->opaque; if (!is_snapshot(&s->inode)) { error_report("cannot clone from a non snapshot vdi"); bdrv_delete(bs); - return -EINVAL; + ret = -EINVAL; + goto out; } base_vid = s->inode.vdi_id; bdrv_delete(bs); } - ret = do_sd_create(vdi, vdi_size, base_vid, &vid, 0, s.addr, s.port); + ret = do_sd_create(vdi, vdi_size, base_vid, &vid, 0, s->addr, s->port); if (!prealloc || ret) { - return ret; + goto out; } - return sd_prealloc(filename); + ret = sd_prealloc(filename); +out: + g_free(s); + return ret; } static void sd_close(BlockDriverState *bs) @@ -1379,7 +1401,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset) fd = connect_to_sdog(s->addr, s->port); if (fd < 0) { - return -EIO; + return fd; } /* we don't need to update entire object */ @@ -1391,10 +1413,9 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset) if (ret < 0) { error_report("failed to update an inode."); - return -EIO; } - return 0; + return ret; } /* @@ -1464,6 +1485,7 @@ static int sd_create_branch(BDRVSheepdogState *s) fd = connect_to_sdog(s->addr, s->port); if (fd < 0) { error_report("failed to connect"); + ret = fd; goto out; } @@ -1606,8 +1628,9 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num, if (bs->growable && sector_num + nb_sectors > bs->total_sectors) { /* TODO: shouldn't block here */ - if (sd_truncate(bs, (sector_num + nb_sectors) * SECTOR_SIZE) < 0) { - return -EIO; + ret = sd_truncate(bs, (sector_num + nb_sectors) * SECTOR_SIZE); + if (ret < 0) { + return ret; } bs->total_sectors = sector_num + nb_sectors; } @@ -1724,7 +1747,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) /* refresh inode. */ fd = connect_to_sdog(s->addr, s->port); if (fd < 0) { - ret = -EIO; + ret = fd; goto cleanup; } @@ -1732,7 +1755,6 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) s->inode.nr_copies, datalen, 0, 0, s->cache_enabled); if (ret < 0) { error_report("failed to write snapshot's inode."); - ret = -EIO; goto cleanup; } @@ -1741,7 +1763,6 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) if (ret < 0) { error_report("failed to create inode for snapshot. %s", strerror(errno)); - ret = -EIO; goto cleanup; } @@ -1752,7 +1773,6 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) if (ret < 0) { error_report("failed to read new inode info. %s", strerror(errno)); - ret = -EIO; goto cleanup; } @@ -1773,7 +1793,7 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) char *buf = NULL; uint32_t vid; uint32_t snapid = 0; - int ret = -ENOENT, fd; + int ret = 0, fd; old_s = g_malloc(sizeof(BDRVSheepdogState)); @@ -1791,13 +1811,13 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) ret = find_vdi_name(s, vdi, snapid, tag, &vid, 1); if (ret) { error_report("Failed to find_vdi_name"); - ret = -ENOENT; goto out; } fd = connect_to_sdog(s->addr, s->port); if (fd < 0) { error_report("failed to connect"); + ret = fd; goto out; } @@ -1808,7 +1828,6 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) closesocket(fd); if (ret) { - ret = -ENOENT; goto out; } @@ -1861,6 +1880,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) fd = connect_to_sdog(s->addr, s->port); if (fd < 0) { + ret = fd; goto out; } @@ -1888,6 +1908,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) fd = connect_to_sdog(s->addr, s->port); if (fd < 0) { error_report("failed to connect"); + ret = fd; goto out; } @@ -1925,6 +1946,10 @@ out: g_free(vdi_inuse); + if (ret < 0) { + return ret; + } + return found; } @@ -1940,8 +1965,7 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data, fd = connect_to_sdog(s->addr, s->port); if (fd < 0) { - ret = -EIO; - goto cleanup; + return fd; } while (size) { @@ -1965,7 +1989,6 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data, if (ret < 0) { error_report("failed to save vmstate %s", strerror(errno)); - ret = -EIO; goto cleanup; } @@ -2831,6 +2831,21 @@ if compile_prog "" "" ; then linux_magic_h=yes fi +######################################## +# check if environ is declared + +has_environ=no +cat > $TMPC << EOF +#include <unistd.h> +int main(void) { + environ = environ; + return 0; +} +EOF +if compile_prog "" "" ; then + has_environ=yes +fi + ########################################## # End of CC checks # After here, no more $cc or $ld runs @@ -3342,6 +3357,10 @@ if test "$linux_magic_h" = "yes" ; then echo "CONFIG_LINUX_MAGIC_H=y" >> $config_host_mak fi +if test "$has_environ" = "yes" ; then + echo "CONFIG_HAS_ENVIRON=y" >> $config_host_mak +fi + # USB host support case "$usb" in linux) diff --git a/exec-all.h b/exec-all.h index c1b7e1f263..9bda7f7354 100644 --- a/exec-all.h +++ b/exec-all.h @@ -96,6 +96,8 @@ void QEMU_NORETURN cpu_loop_exit(CPUArchState *env1); int page_unprotect(target_ulong address, uintptr_t pc, void *puc); void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, int is_cpu_write_access); +void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end, + int is_cpu_write_access); #if !defined(CONFIG_USER_ONLY) /* cputlb.c */ void tlb_flush_page(CPUArchState *env, target_ulong addr); @@ -1075,6 +1075,23 @@ TranslationBlock *tb_gen_code(CPUArchState *env, return tb; } +/* + * invalidate all TBs which intersect with the target physical pages + * starting in range [start;end[. NOTE: start and end may refer to + * different physical pages. 'is_cpu_write_access' should be true if called + * from a real cpu write access: the virtual CPU will exit the current + * TB if code is modified inside this TB. + */ +void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end, + int is_cpu_write_access) +{ + while (start < end) { + tb_invalidate_phys_page_range(start, end, is_cpu_write_access); + start &= TARGET_PAGE_MASK; + start += TARGET_PAGE_SIZE; + } +} + /* invalidate all TBs which intersect with the target physical page starting in range [start;end[. NOTE: start and end must refer to the same physical page. 'is_cpu_write_access' should be true if called diff --git a/hw/es1370.c b/hw/es1370.c index f19cef31a6..573f747362 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -410,7 +410,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) if ((old_fmt != new_fmt) || (old_freq != new_freq)) { d->shift = (new_fmt & 1) + (new_fmt >> 1); - ldebug ("channel %d, freq = %d, nchannels %d, fmt %d, shift %d\n", + ldebug ("channel %zu, freq = %d, nchannels %d, fmt %d, shift %d\n", i, new_freq, 1 << (new_fmt & 1), @@ -578,7 +578,7 @@ IO_WRITE_PROTO (es1370_writel) d++; case ES1370_REG_DAC1_SCOUNT: d->scount = (val & 0xffff) | (d->scount & ~0xffff); - ldebug ("chan %d CURR_SAMP_CT %d, SAMP_CT %d\n", + ldebug ("chan %td CURR_SAMP_CT %d, SAMP_CT %d\n", d - &s->chan[0], val >> 16, (val & 0xffff)); break; @@ -588,7 +588,7 @@ IO_WRITE_PROTO (es1370_writel) d++; case ES1370_REG_DAC1_FRAMEADR: d->frame_addr = val; - ldebug ("chan %d frame address %#x\n", d - &s->chan[0], val); + ldebug ("chan %td frame address %#x\n", d - &s->chan[0], val); break; case ES1370_REG_PHANTOM_FRAMECNT: @@ -605,7 +605,7 @@ IO_WRITE_PROTO (es1370_writel) case ES1370_REG_DAC1_FRAMECNT: d->frame_cnt = val; d->leftover = 0; - ldebug ("chan %d frame count %d, buffer size %d\n", + ldebug ("chan %td frame count %d, buffer size %d\n", d - &s->chan[0], val >> 16, val & 0xffff); break; @@ -745,9 +745,10 @@ IO_READ_PROTO (es1370_readl) { uint32_t size = ((d->frame_cnt & 0xffff) + 1) << 2; uint32_t curr = ((d->frame_cnt >> 16) + 1) << 2; - if (curr > size) + if (curr > size) { dolog ("read framecnt curr %d, size %d %d\n", curr, size, curr > size); + } } #endif break; @@ -179,12 +179,14 @@ static void fd_revalidate(FDrive *drv) FDriveRate rate; FLOPPY_DPRINTF("revalidate\n"); - if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) { + if (drv->bs != NULL) { ro = bdrv_is_read_only(drv->bs); bdrv_get_floppy_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect, drv->drive, &drive, &rate); - if (nb_heads != 0 && max_track != 0 && last_sect != 0) { - FLOPPY_DPRINTF("User defined disk (%d %d %d)", + if (!bdrv_is_inserted(drv->bs)) { + FLOPPY_DPRINTF("No disk in drive\n"); + } else if (nb_heads != 0 && max_track != 0 && last_sect != 0) { + FLOPPY_DPRINTF("User defined disk (%d %d %d)\n", nb_heads - 1, max_track, last_sect); } else { FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n", nb_heads, @@ -201,7 +203,7 @@ static void fd_revalidate(FDrive *drv) drv->drive = drive; drv->media_rate = rate; } else { - FLOPPY_DPRINTF("No disk in drive\n"); + FLOPPY_DPRINTF("No drive connected\n"); drv->last_sect = 0; drv->max_track = 0; drv->flags &= ~FDISK_DBL_SIDES; @@ -709,7 +711,7 @@ static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0) FDrive *cur_drv; /* A seek clears the disk change line (if a disk is inserted) */ cur_drv = get_cur_drv(fdctrl); - if (cur_drv->max_track) { + if (cur_drv->bs != NULL && bdrv_is_inserted(cur_drv->bs)) { cur_drv->media_changed = 0; } } @@ -1878,7 +1880,7 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl) } fd_init(drive); - fd_revalidate(drive); + fdctrl_change_cb(drive, 0); if (drive->bs) { bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive); } diff --git a/hw/loader.c b/hw/loader.c index 415cdce534..7d64113e7f 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -103,7 +103,7 @@ ssize_t read_targphys(const char *name, /* return the size or -1 if error */ int load_image_targphys(const char *filename, - target_phys_addr_t addr, int max_sz) + target_phys_addr_t addr, uint64_t max_sz) { int size; diff --git a/hw/loader.h b/hw/loader.h index fbcaba9f0c..6da291e31f 100644 --- a/hw/loader.h +++ b/hw/loader.h @@ -4,7 +4,8 @@ /* loader.c */ int get_image_size(const char *filename); int load_image(const char *filename, uint8_t *addr); /* deprecated */ -int load_image_targphys(const char *filename, target_phys_addr_t, int max_sz); +int load_image_targphys(const char *filename, target_phys_addr_t, + uint64_t max_sz); int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr, int big_endian, int elf_machine, @@ -383,7 +383,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, if (floppy) { fdc_get_bs(fd, floppy); for (i = 0; i < 2; i++) { - if (fd[i] && bdrv_is_inserted(fd[i])) { + if (fd[i]) { bdrv_get_floppy_geometry_hint(fd[i], &nb_heads, &max_track, &last_sect, FDRIVE_DRV_NONE, &fd_type[i], &rate); diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index c5545dcd37..b7b5597c62 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -753,10 +753,12 @@ static void set_mac(Object *obj, Visitor *v, void *opaque, } mac->a[i] = strtol(str+pos, &p, 16); } + g_free(str); return; inval: error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); + g_free(str); } PropertyInfo qdev_prop_macaddr = { @@ -825,7 +827,7 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, uint32_t *ptr = qdev_get_prop_ptr(dev, prop); unsigned int slot, fn, n; Error *local_err = NULL; - char *str = (char *)""; + char *str; if (dev->state != DEV_STATE_CREATED) { error_set(errp, QERR_PERMISSION_DENIED); @@ -848,10 +850,12 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, goto invalid; } *ptr = slot << 3 | fn; + g_free(str); return; invalid: error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); + g_free(str); } static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 63ccd5c35a..1d38a8f5c5 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -163,8 +163,7 @@ static int s390_virtio_blk_init(VirtIOS390Device *dev) { VirtIODevice *vdev; - vdev = virtio_blk_init((DeviceState *)dev, &dev->block, - &dev->block_serial); + vdev = virtio_blk_init((DeviceState *)dev, &dev->blk); if (!vdev) { return -1; } @@ -400,8 +399,11 @@ static TypeInfo s390_virtio_net = { }; static Property s390_virtio_blk_properties[] = { - DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block), - DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial), + DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, blk.conf), + DEFINE_PROP_STRING("serial", VirtIOS390Device, blk.serial), +#ifdef __linux__ + DEFINE_PROP_BIT("scsi", VirtIOS390Device, blk.scsi, 0, true), +#endif DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h index 49e6c462df..4b99d02298 100644 --- a/hw/s390-virtio-bus.h +++ b/hw/s390-virtio-bus.h @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "virtio-blk.h" #include "virtio-net.h" #include "virtio-serial.h" #include "virtio-scsi.h" @@ -64,8 +65,7 @@ struct VirtIOS390Device { ram_addr_t feat_offs; uint8_t feat_len; VirtIODevice *vdev; - BlockConf block; - char *block_serial; + VirtIOBlkConf blk; NICConf nic; uint32_t host_features; virtio_serial_conf serial; diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 8ab9bcda86..f10f3ec25c 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -1561,7 +1561,7 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size) return 0; } -const VMStateInfo vmstate_info_scsi_requests = { +static const VMStateInfo vmstate_info_scsi_requests = { .name = "scsi-requests", .get = get_scsi_requests, .put = put_scsi_requests, diff --git a/hw/sun4u.c b/hw/sun4u.c index fe3313890d..517bdb818d 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -67,7 +67,6 @@ #define KERNEL_LOAD_ADDR 0x00404000 #define CMDLINE_ADDR 0x003ff000 -#define INITRD_LOAD_ADDR 0x00300000 #define PROM_SIZE_MAX (4 * 1024 * 1024) #define PROM_VADDR 0x000ffd00000ULL #define APB_SPECIAL_BASE 0x1fe00000000ULL @@ -181,14 +180,18 @@ static int sun4u_NVRAM_set_params(M48t59State *nvram, uint16_t NVRAM_size, return 0; } -static unsigned long sun4u_load_kernel(const char *kernel_filename, - const char *initrd_filename, - ram_addr_t RAM_size, long *initrd_size) + +static uint64_t sun4u_load_kernel(const char *kernel_filename, + const char *initrd_filename, + ram_addr_t RAM_size, uint64_t *initrd_size, + uint64_t *initrd_addr, uint64_t *kernel_addr, + uint64_t *kernel_entry) { int linux_boot; unsigned int i; long kernel_size; uint8_t *ptr; + uint64_t kernel_top; linux_boot = (kernel_filename != NULL); @@ -201,29 +204,34 @@ static unsigned long sun4u_load_kernel(const char *kernel_filename, #else bswap_needed = 0; #endif - kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, - NULL, NULL, 1, ELF_MACHINE, 0); - if (kernel_size < 0) + kernel_size = load_elf(kernel_filename, NULL, NULL, kernel_entry, + kernel_addr, &kernel_top, 1, ELF_MACHINE, 0); + if (kernel_size < 0) { + *kernel_addr = KERNEL_LOAD_ADDR; + *kernel_entry = KERNEL_LOAD_ADDR; kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR, RAM_size - KERNEL_LOAD_ADDR, bswap_needed, TARGET_PAGE_SIZE); - if (kernel_size < 0) + } + if (kernel_size < 0) { kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR, RAM_size - KERNEL_LOAD_ADDR); + } if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); } - - /* load initrd */ + /* load initrd above kernel */ *initrd_size = 0; if (initrd_filename) { + *initrd_addr = TARGET_PAGE_ALIGN(kernel_top); + *initrd_size = load_image_targphys(initrd_filename, - INITRD_LOAD_ADDR, - RAM_size - INITRD_LOAD_ADDR); - if (*initrd_size < 0) { + *initrd_addr, + RAM_size - *initrd_addr); + if ((int)*initrd_size < 0) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); exit(1); @@ -231,9 +239,9 @@ static unsigned long sun4u_load_kernel(const char *kernel_filename, } if (*initrd_size > 0) { for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { - ptr = rom_ptr(KERNEL_LOAD_ADDR + i); + ptr = rom_ptr(*kernel_addr + i); if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */ - stl_p(ptr + 24, INITRD_LOAD_ADDR + KERNEL_LOAD_ADDR - 0x4000); + stl_p(ptr + 24, *initrd_addr + *kernel_addr); stl_p(ptr + 28, *initrd_size); break; } @@ -788,7 +796,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, CPUSPARCState *env; M48t59State *nvram; unsigned int i; - long initrd_size, kernel_size; + uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry; PCIBus *pci_bus, *pci_bus2, *pci_bus3; ISABus *isa_bus; qemu_irq *ivec_irqs, *pbm_irqs; @@ -845,13 +853,15 @@ static void sun4uv_init(MemoryRegion *address_space_mem, nvram = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59); initrd_size = 0; + initrd_addr = 0; kernel_size = sun4u_load_kernel(kernel_filename, initrd_filename, - ram_size, &initrd_size); + ram_size, &initrd_size, &initrd_addr, + &kernel_addr, &kernel_entry); sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", RAM_size, boot_devices, - KERNEL_LOAD_ADDR, kernel_size, + kernel_addr, kernel_size, kernel_cmdline, - INITRD_LOAD_ADDR, initrd_size, + initrd_addr, initrd_size, /* XXX: need an option to load a NVRAM image */ 0, graphic_width, graphic_height, graphic_depth, @@ -861,8 +871,8 @@ static void sun4uv_init(MemoryRegion *address_space_mem, fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); + fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_entry); + fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); if (kernel_cmdline) { fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline) + 1); @@ -872,8 +882,8 @@ static void sun4uv_init(MemoryRegion *address_space_mem, } else { fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0); } - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR); - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); + fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); + fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_devices[0]); fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width); diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index ce9d2c9759..075ed87e37 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -211,11 +211,15 @@ static void virtio_balloon_save(QEMUFile *f, void *opaque) static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id) { VirtIOBalloon *s = opaque; + int ret; if (version_id != 1) return -EINVAL; - virtio_load(&s->vdev, f); + ret = virtio_load(&s->vdev, f); + if (ret) { + return ret; + } s->num_pages = qemu_get_be32(f); s->actual = qemu_get_be32(f); diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 49990f8efe..f9e1896ea9 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -29,7 +29,7 @@ typedef struct VirtIOBlock void *rq; QEMUBH *bh; BlockConf *conf; - char *serial; + VirtIOBlkConf *blk; unsigned short sector_mask; DeviceState *qdev; } VirtIOBlock; @@ -145,20 +145,12 @@ static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s) return req; } -#ifdef __linux__ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) { - struct sg_io_hdr hdr; int ret; - int status; + int status = VIRTIO_BLK_S_OK; int i; - if ((req->dev->vdev.guest_features & (1 << VIRTIO_BLK_F_SCSI)) == 0) { - virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP); - g_free(req); - return; - } - /* * We require at least one output segment each for the virtio_blk_outhdr * and the SCSI command block. @@ -173,20 +165,26 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) } /* - * No support for bidirection commands yet. + * The scsi inhdr is placed in the second-to-last input segment, just + * before the regular inhdr. */ - if (req->elem.out_num > 2 && req->elem.in_num > 3) { - virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP); - g_free(req); - return; + req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base; + + if (!req->dev->blk->scsi) { + status = VIRTIO_BLK_S_UNSUPP; + goto fail; } /* - * The scsi inhdr is placed in the second-to-last input segment, just - * before the regular inhdr. + * No support for bidirection commands yet. */ - req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base; + if (req->elem.out_num > 2 && req->elem.in_num > 3) { + status = VIRTIO_BLK_S_UNSUPP; + goto fail; + } +#ifdef __linux__ + struct sg_io_hdr hdr; memset(&hdr, 0, sizeof(struct sg_io_hdr)); hdr.interface_id = 'S'; hdr.cmd_len = req->elem.out_sg[1].iov_len; @@ -230,12 +228,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) ret = bdrv_ioctl(req->dev->bs, SG_IO, &hdr); if (ret) { status = VIRTIO_BLK_S_UNSUPP; - hdr.status = ret; - hdr.resid = hdr.dxfer_len; - } else if (hdr.status) { - status = VIRTIO_BLK_S_IOERR; - } else { - status = VIRTIO_BLK_S_OK; + goto fail; } /* @@ -258,14 +251,16 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req) virtio_blk_req_complete(req, status); g_free(req); -} #else -static void virtio_blk_handle_scsi(VirtIOBlockReq *req) -{ - virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP); + abort(); +#endif + +fail: + /* Just put anything nonzero so that the ioctl fails in the guest. */ + stl_p(&req->scsi->errors, 255); + virtio_blk_req_complete(req, status); g_free(req); } -#endif /* __linux__ */ typedef struct MultiReqBuffer { BlockRequest blkreq[32]; @@ -394,7 +389,7 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req, * terminated by '\0' only when shorter than buffer. */ strncpy(req->elem.in_sg[0].iov_base, - s->serial ? s->serial : "", + s->blk->serial ? s->blk->serial : "", MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES)); virtio_blk_req_complete(req, VIRTIO_BLK_S_OK); g_free(req); @@ -509,6 +504,7 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features) features |= (1 << VIRTIO_BLK_F_GEOMETRY); features |= (1 << VIRTIO_BLK_F_TOPOLOGY); features |= (1 << VIRTIO_BLK_F_BLK_SIZE); + features |= (1 << VIRTIO_BLK_F_SCSI); if (bdrv_enable_write_cache(s->bs)) features |= (1 << VIRTIO_BLK_F_WCACHE); @@ -537,11 +533,16 @@ static void virtio_blk_save(QEMUFile *f, void *opaque) static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id) { VirtIOBlock *s = opaque; + int ret; if (version_id != 2) return -EINVAL; - virtio_load(&s->vdev, f); + ret = virtio_load(&s->vdev, f); + if (ret) { + return ret; + } + while (qemu_get_sbyte(f)) { VirtIOBlockReq *req = virtio_blk_alloc_request(s); qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem)); @@ -568,28 +569,27 @@ static const BlockDevOps virtio_block_ops = { .resize_cb = virtio_blk_resize, }; -VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, - char **serial) +VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk) { VirtIOBlock *s; int cylinders, heads, secs; static int virtio_blk_id; DriveInfo *dinfo; - if (!conf->bs) { + if (!blk->conf.bs) { error_report("drive property not set"); return NULL; } - if (!bdrv_is_inserted(conf->bs)) { + if (!bdrv_is_inserted(blk->conf.bs)) { error_report("Device needs media, but drive is empty"); return NULL; } - if (!*serial) { + if (!blk->serial) { /* try to fall back to value set with legacy -drive serial=... */ - dinfo = drive_get_by_blockdev(conf->bs); + dinfo = drive_get_by_blockdev(blk->conf.bs); if (*dinfo->serial) { - *serial = strdup(dinfo->serial); + blk->serial = strdup(dinfo->serial); } } @@ -600,9 +600,9 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, s->vdev.get_config = virtio_blk_update_config; s->vdev.get_features = virtio_blk_get_features; s->vdev.reset = virtio_blk_reset; - s->bs = conf->bs; - s->conf = conf; - s->serial = *serial; + s->bs = blk->conf.bs; + s->conf = &blk->conf; + s->blk = blk; s->rq = NULL; s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1; bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs); @@ -614,10 +614,10 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, register_savevm(dev, "virtio-blk", virtio_blk_id++, 2, virtio_blk_save, virtio_blk_load, s); bdrv_set_dev_ops(s->bs, &virtio_block_ops, s); - bdrv_set_buffer_alignment(s->bs, conf->logical_block_size); + bdrv_set_buffer_alignment(s->bs, s->conf->logical_block_size); bdrv_iostatus_enable(s->bs); - add_boot_device_path(conf->bootindex, dev, "/disk@0,0"); + add_boot_device_path(s->conf->bootindex, dev, "/disk@0,0"); return &s->vdev; } @@ -626,5 +626,6 @@ void virtio_blk_exit(VirtIODevice *vdev) { VirtIOBlock *s = to_virtio_blk(vdev); unregister_savevm(s->qdev, "virtio-blk", s); + blockdev_mark_auto_del(s->bs); virtio_cleanup(vdev); } diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h index 244dce45aa..d7850012bd 100644 --- a/hw/virtio-blk.h +++ b/hw/virtio-blk.h @@ -97,12 +97,14 @@ struct virtio_scsi_inhdr uint32_t residual; }; -#ifdef __linux__ -#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \ - DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \ - DEFINE_PROP_BIT("scsi", _state, _field, VIRTIO_BLK_F_SCSI, true) -#else +struct VirtIOBlkConf +{ + BlockConf conf; + char *serial; + uint32_t scsi; +}; + #define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \ DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) -#endif + #endif diff --git a/hw/virtio-net.c b/hw/virtio-net.c index bc5e3a83d1..3f190d417e 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -891,11 +891,15 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) { VirtIONet *n = opaque; int i; + int ret; if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) return -EINVAL; - virtio_load(&n->vdev, f); + ret = virtio_load(&n->vdev, f); + if (ret) { + return ret; + } qemu_get_buffer(f, n->mac, ETH_ALEN); n->tx_waiting = qemu_get_be32(f); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 4a4413d52c..79b86f1aad 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -491,7 +491,7 @@ static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val) virtio_config_writel(proxy->vdev, addr, val); } -const MemoryRegionPortio virtio_portio[] = { +static const MemoryRegionPortio virtio_portio[] = { { 0, 0x10000, 1, .write = virtio_pci_config_writeb, }, { 0, 0x10000, 2, .write = virtio_pci_config_writew, }, { 0, 0x10000, 4, .write = virtio_pci_config_writel, }, @@ -697,8 +697,7 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev) proxy->class_code != PCI_CLASS_STORAGE_OTHER) proxy->class_code = PCI_CLASS_STORAGE_SCSI; - vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block, - &proxy->block_serial); + vdev = virtio_blk_init(&pci_dev->qdev, &proxy->blk); if (!vdev) { return -1; } @@ -726,7 +725,6 @@ static int virtio_blk_exit_pci(PCIDevice *pci_dev) virtio_pci_stop_ioeventfd(proxy); virtio_blk_exit(proxy->vdev); - blockdev_mark_auto_del(proxy->block.bs); return virtio_exit_pci(pci_dev); } @@ -814,8 +812,11 @@ static int virtio_balloon_exit_pci(PCIDevice *pci_dev) static Property virtio_blk_properties[] = { DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block), - DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial), + DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, blk.conf), + DEFINE_PROP_STRING("serial", VirtIOPCIProxy, blk.serial), +#ifdef __linux__ + DEFINE_PROP_BIT("scsi", VirtIOPCIProxy, blk.scsi, 0, true), +#endif DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features), diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index e5604282e5..889e59e421 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -15,6 +15,7 @@ #ifndef QEMU_VIRTIO_PCI_H #define QEMU_VIRTIO_PCI_H +#include "virtio-blk.h" #include "virtio-net.h" #include "virtio-serial.h" #include "virtio-scsi.h" @@ -32,8 +33,7 @@ typedef struct { uint32_t flags; uint32_t class_code; uint32_t nvectors; - BlockConf block; - char *block_serial; + VirtIOBlkConf blk; NICConf nic; uint32_t host_features; #ifdef CONFIG_LINUX diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index e8328f4652..5e39ce93c4 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -564,7 +564,12 @@ static void virtio_scsi_save(QEMUFile *f, void *opaque) static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id) { VirtIOSCSI *s = opaque; - virtio_load(&s->vdev, f); + int ret; + + ret = virtio_load(&s->vdev, f); + if (ret) { + return ret; + } return 0; } diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index ffbdfc2de1..72287d10ce 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -637,13 +637,17 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) VirtIOSerialPort *port; uint32_t max_nr_ports, nr_active_ports, ports_map; unsigned int i; + int ret; if (version_id > 3) { return -EINVAL; } /* The virtio device */ - virtio_load(&s->vdev, f); + ret = virtio_load(&s->vdev, f); + if (ret) { + return ret; + } if (version_id < 2) { return 0; diff --git a/hw/virtio.h b/hw/virtio.h index 0aef7d1bc0..85aabe53d8 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -191,8 +191,8 @@ void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding, void *opaque); /* Base devices. */ -VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, - char **serial); +typedef struct VirtIOBlkConf VirtIOBlkConf; +VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk); struct virtio_net_conf; VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, struct virtio_net_conf *net); diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 7125d1cd4b..d9468fea90 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -573,6 +573,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, page_dump(stdout); printf("\n"); #endif + tb_invalidate_phys_range(start, start + len, 0); mmap_unlock(); return start; fail: @@ -675,8 +676,10 @@ int target_munmap(abi_ulong start, abi_ulong len) } } - if (ret == 0) + if (ret == 0) { page_set_flags(start, start + len, 0); + tb_invalidate_phys_range(start, start + len, 0); + } mmap_unlock(); return ret; } @@ -754,6 +757,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, page_set_flags(old_addr, old_addr + old_size, 0); page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); } + tb_invalidate_phys_range(new_addr, new_addr + new_size, 0); mmap_unlock(); return new_addr; } diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json index 692b570675..d4055d262a 100644 --- a/qapi-schema-guest.json +++ b/qapi-schema-guest.json @@ -126,16 +126,19 @@ # @guest-shutdown: # # Initiate guest-activated shutdown. Note: this is an asynchronous -# shutdown request, with no guaruntee of successful shutdown. Errors -# will be logged to guest's syslog. +# shutdown request, with no guarantee of successful shutdown. # # @mode: #optional "halt", "powerdown" (default), or "reboot" # -# Returns: Nothing on success +# This command does NOT return a response on success. Success condition +# is indicated by the VM exiting with a zero exit status or, when +# running with --no-shutdown, by issuing the query-status QMP command +# to confirm the VM status is "shutdown". # # Since: 0.15.0 ## -{ 'command': 'guest-shutdown', 'data': { '*mode': 'str' } } +{ 'command': 'guest-shutdown', 'data': { '*mode': 'str' }, + 'success-response': 'no' } ## # @guest-file-open: @@ -359,17 +362,21 @@ # For the best results it's strongly recommended to have the pm-utils # package installed in the guest. # -# Returns: nothing on success +# This command does NOT return a response on success. There is a high chance +# the command succeeded if the VM exits with a zero exit status or, when +# running with --no-shutdown, by issuing the query-status QMP command to +# to confirm the VM status is "shutdown". However, the VM could also exit +# (or set its status to "shutdown") due to other reasons. +# +# The following errors may be returned: # If suspend to disk is not supported, Unsupported # -# Notes: o This is an asynchronous request. There's no guarantee a response -# will be sent -# o It's strongly recommended to issue the guest-sync command before -# sending commands when the guest resumes +# Notes: It's strongly recommended to issue the guest-sync command before +# sending commands when the guest resumes # # Since: 1.1 ## -{ 'command': 'guest-suspend-disk' } +{ 'command': 'guest-suspend-disk', 'success-response': 'no' } ## # @guest-suspend-ram @@ -387,17 +394,21 @@ # command. Thus, it's *required* to query QEMU for the presence of the # 'system_wakeup' command before issuing guest-suspend-ram. # -# Returns: nothing on success +# This command does NOT return a response on success. There are two options +# to check for success: +# 1. Wait for the SUSPEND QMP event from QEMU +# 2. Issue the query-status QMP command to confirm the VM status is +# "suspended" +# +# The following errors may be returned: # If suspend to ram is not supported, Unsupported # -# Notes: o This is an asynchronous request. There's no guarantee a response -# will be sent -# o It's strongly recommended to issue the guest-sync command before -# sending commands when the guest resumes +# Notes: It's strongly recommended to issue the guest-sync command before +# sending commands when the guest resumes # # Since: 1.1 ## -{ 'command': 'guest-suspend-ram' } +{ 'command': 'guest-suspend-ram', 'success-response': 'no' } ## # @guest-suspend-hybrid @@ -410,17 +421,21 @@ # command. Thus, it's *required* to query QEMU for the presence of the # 'system_wakeup' command before issuing guest-suspend-hybrid. # -# Returns: nothing on success +# This command does NOT return a response on success. There are two options +# to check for success: +# 1. Wait for the SUSPEND QMP event from QEMU +# 2. Issue the query-status QMP command to confirm the VM status is +# "suspended" +# +# The following errors may be returned: # If hybrid suspend is not supported, Unsupported # -# Notes: o This is an asynchronous request. There's no guarantee a response -# will be sent -# o It's strongly recommended to issue the guest-sync command before -# sending commands when the guest resumes +# Notes: It's strongly recommended to issue the guest-sync command before +# sending commands when the guest resumes # # Since: 1.1 ## -{ 'command': 'guest-suspend-hybrid' } +{ 'command': 'guest-suspend-hybrid', 'success-response': 'no' } ## # @GuestIpAddressType: diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h index 431ddbb337..b0f64ba1ee 100644 --- a/qapi/qmp-core.h +++ b/qapi/qmp-core.h @@ -25,16 +25,24 @@ typedef enum QmpCommandType QCT_NORMAL, } QmpCommandType; +typedef enum QmpCommandOptions +{ + QCO_NO_OPTIONS = 0x0, + QCO_NO_SUCCESS_RESP = 0x1, +} QmpCommandOptions; + typedef struct QmpCommand { const char *name; QmpCommandType type; QmpCommandFunc *fn; + QmpCommandOptions options; QTAILQ_ENTRY(QmpCommand) node; bool enabled; } QmpCommand; -void qmp_register_command(const char *name, QmpCommandFunc *fn); +void qmp_register_command(const char *name, QmpCommandFunc *fn, + QmpCommandOptions options); QmpCommand *qmp_find_command(const char *name); QObject *qmp_dispatch(QObject *request); void qmp_disable_command(const char *name); diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index 43f640a95e..122c1a29ba 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -94,8 +94,12 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp) switch (cmd->type) { case QCT_NORMAL: cmd->fn(args, &ret, errp); - if (!error_is_set(errp) && ret == NULL) { - ret = QOBJECT(qdict_new()); + if (!error_is_set(errp)) { + if (cmd->options & QCO_NO_SUCCESS_RESP) { + g_assert(!ret); + } else if (!ret) { + ret = QOBJECT(qdict_new()); + } } break; } diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c index 43d5cdeb64..5414613377 100644 --- a/qapi/qmp-registry.c +++ b/qapi/qmp-registry.c @@ -17,7 +17,8 @@ static QTAILQ_HEAD(QmpCommandList, QmpCommand) qmp_commands = QTAILQ_HEAD_INITIALIZER(qmp_commands); -void qmp_register_command(const char *name, QmpCommandFunc *fn) +void qmp_register_command(const char *name, QmpCommandFunc *fn, + QmpCommandOptions options) { QmpCommand *cmd = g_malloc0(sizeof(*cmd)); @@ -25,6 +26,7 @@ void qmp_register_command(const char *name, QmpCommandFunc *fn) cmd->type = QCT_NORMAL; cmd->fn = fn; cmd->enabled = true; + cmd->options = options; QTAILQ_INSERT_TAIL(&qmp_commands, cmd, node); } @@ -104,16 +104,9 @@ static void quit_handler(int sig) } #ifndef _WIN32 -/* reap _all_ terminated children */ -static void child_handler(int sig) -{ - int status; - while (waitpid(-1, &status, WNOHANG) > 0) /* NOTHING */; -} - static gboolean register_signal_handlers(void) { - struct sigaction sigact, sigact_chld; + struct sigaction sigact; int ret; memset(&sigact, 0, sizeof(struct sigaction)); @@ -130,15 +123,24 @@ static gboolean register_signal_handlers(void) return false; } - memset(&sigact_chld, 0, sizeof(struct sigaction)); - sigact_chld.sa_handler = child_handler; - sigact_chld.sa_flags = SA_NOCLDSTOP; - ret = sigaction(SIGCHLD, &sigact_chld, NULL); - if (ret == -1) { - g_error("error configuring signal handler: %s", strerror(errno)); + return true; +} + +/* TODO: use this in place of all post-fork() fclose(std*) callers */ +void reopen_fd_to_null(int fd) +{ + int nullfd; + + nullfd = open("/dev/null", O_RDWR); + if (nullfd < 0) { + return; } - return true; + dup2(nullfd, fd); + + if (nullfd != fd) { + close(nullfd); + } } #endif @@ -167,7 +169,7 @@ static void usage(const char *cmd) " -h, --help display this help and exit\n" "\n" "Report bugs to <mdroth@linux.vnet.ibm.com>\n" - , cmd, QGA_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT, + , cmd, QEMU_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT, QGA_STATEDIR_DEFAULT); } @@ -428,9 +430,9 @@ static void become_daemon(const char *pidfile) goto fail; } - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); + reopen_fd_to_null(STDIN_FILENO); + reopen_fd_to_null(STDOUT_FILENO); + reopen_fd_to_null(STDERR_FILENO); return; fail: @@ -488,8 +490,6 @@ static void process_command(GAState *s, QDict *req) g_warning("error sending response: %s", strerror(ret)); } qobject_decref(rsp); - } else { - g_warning("error getting response"); } } @@ -729,7 +729,7 @@ int main(int argc, char **argv) log_level = G_LOG_LEVEL_MASK; break; case 'V': - printf("QEMU Guest Agent %s\n", QGA_VERSION); + printf("QEMU Guest Agent %s\n", QEMU_VERSION); return 0; case 'd': daemonize = 1; @@ -836,12 +836,13 @@ int main(int argc, char **argv) become_daemon(pid_filepath); } if (log_filepath) { - s->log_file = fopen(log_filepath, "a"); - if (!s->log_file) { + FILE *log_file = fopen(log_filepath, "a"); + if (!log_file) { g_critical("unable to open specified log file: %s", strerror(errno)); goto out_bad; } + s->log_file = log_file; } } diff --git a/qemu-img.texi b/qemu-img.texi index b2ca3a542c..6fc3c28e0d 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -159,6 +159,24 @@ It can be used without an accessible old backing file, i.e. you can use it to fix an image whose backing file has already been moved/renamed. @end table +You can use @code{rebase} to perform a ``diff'' operation on two +disk images. This can be useful when you have copied or cloned +a guest, and you want to get back to a thin image on top of a +template or base image. + +Say that @code{base.img} has been cloned as @code{modified.img} by +copying it, and that the @code{modified.img} guest has run so there +are now some changes compared to @code{base.img}. To construct a thin +image called @code{diff.qcow2} that contains just the differences, do: + +@example +qemu-img create -f qcow2 -b modified.img diff.qcow2 +qemu-img rebase -b base.img diff.qcow2 +@end example + +At this point, @code{modified.img} can be discarded, since +@code{base.img + diff.qcow2} contains the same information. + @item resize @var{filename} [+ | -]@var{size} Change the disk image as if it had been created with @var{size}. diff --git a/qga/commands-posix.c b/qga/commands-posix.c index e448431c66..dab3bf9c98 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -14,12 +14,17 @@ #include <glib.h> #include <sys/types.h> #include <sys/ioctl.h> +#include <sys/wait.h> #include "qga/guest-agent-core.h" #include "qga-qmp-commands.h" #include "qerror.h" #include "qemu-queue.h" #include "host-utils.h" +#ifndef CONFIG_HAS_ENVIRON +extern char **environ; +#endif + #if defined(__linux__) #include <mntent.h> #include <linux/fs.h> @@ -27,36 +32,17 @@ #include <arpa/inet.h> #include <sys/socket.h> #include <net/if.h> -#include <sys/wait.h> #if defined(__linux__) && defined(FIFREEZE) #define CONFIG_FSFREEZE #endif #endif -#if defined(__linux__) -/* TODO: use this in place of all post-fork() fclose(std*) callers */ -static void reopen_fd_to_null(int fd) -{ - int nullfd; - - nullfd = open("/dev/null", O_RDWR); - if (nullfd < 0) { - return; - } - - dup2(nullfd, fd); - - if (nullfd != fd) { - close(nullfd); - } -} -#endif /* defined(__linux__) */ - void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) { - int ret; const char *shutdown_flag; + pid_t rpid, pid; + int status; slog("guest-shutdown called, mode: %s", mode); if (!has_mode || strcmp(mode, "powerdown") == 0) { @@ -71,23 +57,30 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) return; } - ret = fork(); - if (ret == 0) { + pid = fork(); + if (pid == 0) { /* child, start the shutdown */ setsid(); - fclose(stdin); - fclose(stdout); - fclose(stderr); - - ret = execl("/sbin/shutdown", "shutdown", shutdown_flag, "+0", - "hypervisor initiated shutdown", (char*)NULL); - if (ret) { - slog("guest-shutdown failed: %s", strerror(errno)); - } - exit(!!ret); - } else if (ret < 0) { - error_set(err, QERR_UNDEFINED_ERROR); + reopen_fd_to_null(0); + reopen_fd_to_null(1); + reopen_fd_to_null(2); + + execle("/sbin/shutdown", "shutdown", shutdown_flag, "+0", + "hypervisor initiated shutdown", (char*)NULL, environ); + _exit(EXIT_FAILURE); + } else if (pid < 0) { + goto exit_err; + } + + do { + rpid = waitpid(pid, &status, 0); + } while (rpid == -1 && errno == EINTR); + if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) { + return; } + +exit_err: + error_set(err, QERR_UNDEFINED_ERROR); } typedef struct GuestFileHandle { @@ -531,117 +524,88 @@ static void guest_fsfreeze_cleanup(void) #define SUSPEND_SUPPORTED 0 #define SUSPEND_NOT_SUPPORTED 1 -/** - * This function forks twice and the information about the mode support - * status is passed to the qemu-ga process via a pipe. - * - * This approach allows us to keep the way we reap terminated children - * in qemu-ga quite simple. - */ static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg, const char *sysfile_str, Error **err) { - pid_t pid; - ssize_t ret; char *pmutils_path; - int status, pipefds[2]; - - if (pipe(pipefds) < 0) { - error_set(err, QERR_UNDEFINED_ERROR); - return; - } + pid_t pid, rpid; + int status; pmutils_path = g_find_program_in_path(pmutils_bin); pid = fork(); if (!pid) { - struct sigaction act; - - memset(&act, 0, sizeof(act)); - act.sa_handler = SIG_DFL; - sigaction(SIGCHLD, &act, NULL); + char buf[32]; /* hopefully big enough */ + ssize_t ret; + int fd; setsid(); - close(pipefds[0]); reopen_fd_to_null(0); reopen_fd_to_null(1); reopen_fd_to_null(2); - pid = fork(); - if (!pid) { - int fd; - char buf[32]; /* hopefully big enough */ - - if (pmutils_path) { - execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ); - } - - /* - * If we get here either pm-utils is not installed or execle() has - * failed. Let's try the manual method if the caller wants it. - */ - - if (!sysfile_str) { - _exit(SUSPEND_NOT_SUPPORTED); - } - - fd = open(LINUX_SYS_STATE_FILE, O_RDONLY); - if (fd < 0) { - _exit(SUSPEND_NOT_SUPPORTED); - } + if (pmutils_path) { + execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ); + } - ret = read(fd, buf, sizeof(buf)-1); - if (ret <= 0) { - _exit(SUSPEND_NOT_SUPPORTED); - } - buf[ret] = '\0'; + /* + * If we get here either pm-utils is not installed or execle() has + * failed. Let's try the manual method if the caller wants it. + */ - if (strstr(buf, sysfile_str)) { - _exit(SUSPEND_SUPPORTED); - } + if (!sysfile_str) { + _exit(SUSPEND_NOT_SUPPORTED); + } + fd = open(LINUX_SYS_STATE_FILE, O_RDONLY); + if (fd < 0) { _exit(SUSPEND_NOT_SUPPORTED); } - if (pid > 0) { - wait(&status); - } else { - status = SUSPEND_NOT_SUPPORTED; + ret = read(fd, buf, sizeof(buf)-1); + if (ret <= 0) { + _exit(SUSPEND_NOT_SUPPORTED); } + buf[ret] = '\0'; - ret = write(pipefds[1], &status, sizeof(status)); - if (ret != sizeof(status)) { - _exit(EXIT_FAILURE); + if (strstr(buf, sysfile_str)) { + _exit(SUSPEND_SUPPORTED); } - _exit(EXIT_SUCCESS); + _exit(SUSPEND_NOT_SUPPORTED); } - close(pipefds[1]); g_free(pmutils_path); if (pid < 0) { - error_set(err, QERR_UNDEFINED_ERROR); - goto out; - } - - ret = read(pipefds[0], &status, sizeof(status)); - if (ret == sizeof(status) && WIFEXITED(status) && - WEXITSTATUS(status) == SUSPEND_SUPPORTED) { - goto out; + goto undef_err; + } + + do { + rpid = waitpid(pid, &status, 0); + } while (rpid == -1 && errno == EINTR); + if (rpid == pid && WIFEXITED(status)) { + switch (WEXITSTATUS(status)) { + case SUSPEND_SUPPORTED: + return; + case SUSPEND_NOT_SUPPORTED: + error_set(err, QERR_UNSUPPORTED); + return; + default: + goto undef_err; + } } - error_set(err, QERR_UNSUPPORTED); - -out: - close(pipefds[0]); +undef_err: + error_set(err, QERR_UNDEFINED_ERROR); } static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, Error **err) { - pid_t pid; char *pmutils_path; + pid_t rpid, pid; + int status; pmutils_path = g_find_program_in_path(pmutils_bin); @@ -683,9 +647,18 @@ static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, g_free(pmutils_path); if (pid < 0) { - error_set(err, QERR_UNDEFINED_ERROR); + goto exit_err; + } + + do { + rpid = waitpid(pid, &status, 0); + } while (rpid == -1 && errno == EINTR); + if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) { return; } + +exit_err: + error_set(err, QERR_UNDEFINED_ERROR); } void qmp_guest_suspend_disk(Error **err) diff --git a/qga/commands.c b/qga/commands.c index 5bcceaae34..46b0b083bc 100644 --- a/qga/commands.c +++ b/qga/commands.c @@ -52,7 +52,7 @@ struct GuestAgentInfo *qmp_guest_info(Error **err) GuestAgentCommandInfoList *cmd_info_list; char **cmd_list_head, **cmd_list; - info->version = g_strdup(QGA_VERSION); + info->version = g_strdup(QEMU_VERSION); cmd_list_head = cmd_list = qmp_get_command_list(); if (*cmd_list_head == NULL) { diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h index bbb8b9b125..49a7abee95 100644 --- a/qga/guest-agent-core.h +++ b/qga/guest-agent-core.h @@ -13,7 +13,6 @@ #include "qapi/qmp-core.h" #include "qemu-common.h" -#define QGA_VERSION "1.0" #define QGA_READ_COUNT_DEFAULT 4096 typedef struct GAState GAState; @@ -35,3 +34,7 @@ void ga_set_response_delimited(GAState *s); bool ga_is_frozen(GAState *s); void ga_set_frozen(GAState *s); void ga_unset_frozen(GAState *s); + +#ifndef _WIN32 +void reopen_fd_to_null(int fd); +#endif diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 0b4f0a0fe1..9eed40e18a 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -291,14 +291,24 @@ out: return ret +def option_value_matches(opt, val, cmd): + if opt in cmd and cmd[opt] == val: + return True + return False + def gen_registry(commands): registry="" push_indent() for cmd in commands: + options = 'QCO_NO_OPTIONS' + if option_value_matches('success-response', 'no', cmd): + options = 'QCO_NO_SUCCESS_RESP' + registry += mcgen(''' -qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s); +qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s); ''', - name=cmd['command'], c_name=c_fun(cmd['command'])) + name=cmd['command'], c_name=c_fun(cmd['command']), + opts=options) pop_indent() ret = mcgen(''' static void qmp_init_marshal(void) diff --git a/slirp/ip.h b/slirp/ip.h index 88c903fccd..e2ee5e304c 100644 --- a/slirp/ip.h +++ b/slirp/ip.h @@ -34,18 +34,14 @@ #define _IP_H_ #ifdef HOST_WORDS_BIGENDIAN -# ifndef NTOHL -# define NTOHL(d) -# endif -# ifndef NTOHS -# define NTOHS(d) -# endif -# ifndef HTONL -# define HTONL(d) -# endif -# ifndef HTONS -# define HTONS(d) -# endif +# undef NTOHL +# undef NTOHS +# undef HTONL +# undef HTONS +# define NTOHL(d) +# define NTOHS(d) +# define HTONL(d) +# define HTONS(d) #else # ifndef NTOHL # define NTOHL(d) ((d) = ntohl((d))) diff --git a/slirp/tcp.h b/slirp/tcp.h index 82996031e0..2e2b4033a6 100644 --- a/slirp/tcp.h +++ b/slirp/tcp.h @@ -79,20 +79,23 @@ struct tcphdr { #define TCPOPT_EOL 0 #define TCPOPT_NOP 1 #define TCPOPT_MAXSEG 2 -#define TCPOLEN_MAXSEG 4 #define TCPOPT_WINDOW 3 -#define TCPOLEN_WINDOW 3 #define TCPOPT_SACK_PERMITTED 4 /* Experimental */ -#define TCPOLEN_SACK_PERMITTED 2 #define TCPOPT_SACK 5 /* Experimental */ #define TCPOPT_TIMESTAMP 8 -#define TCPOLEN_TIMESTAMP 10 -#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ #define TCPOPT_TSTAMP_HDR \ (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) #endif +#ifndef TCPOLEN_MAXSEG +#define TCPOLEN_MAXSEG 4 +#define TCPOLEN_WINDOW 3 +#define TCPOLEN_SACK_PERMITTED 2 +#define TCPOLEN_TIMESTAMP 10 +#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ +#endif + /* * Default maximum segment size for TCP. * With an IP MSS of 576, this is 536, diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c index 779314bf9a..8aa3d90470 100644 --- a/slirp/tcp_output.c +++ b/slirp/tcp_output.c @@ -47,6 +47,7 @@ static const u_char tcp_outflags[TCP_NSTATES] = { }; +#undef MAX_TCPOPTLEN #define MAX_TCPOPTLEN 32 /* max # bytes that go in options */ /* diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index 742b3957c0..a362938e41 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -743,7 +743,7 @@ static void dec_bit(DisasContext *dc) unsigned int op; int mem_index = cpu_mmu_index(dc->env); - op = dc->ir & ((1 << 8) - 1); + op = dc->ir & ((1 << 9) - 1); switch (op) { case 0x21: /* src. */ @@ -825,6 +825,16 @@ static void dec_bit(DisasContext *dc) gen_helper_clz(cpu_R[dc->rd], cpu_R[dc->ra]); } break; + case 0x1e0: + /* swapb */ + LOG_DIS("swapb r%d r%d\n", dc->rd, dc->ra); + tcg_gen_bswap32_i32(cpu_R[dc->rd], cpu_R[dc->ra]); + break; + case 0x1e1: + /*swaph */ + LOG_DIS("swaph r%d r%d\n", dc->rd, dc->ra); + tcg_gen_rotri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 16); + break; default: cpu_abort(dc->env, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n", dc->pc, op, dc->rd, dc->ra, dc->rb); diff --git a/target-mips/translate.c b/target-mips/translate.c index f5297b0392..0c563eedfa 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -6099,7 +6099,7 @@ static void gen_compute_branch1 (CPUMIPSState *env, DisasContext *ctx, uint32_t TCGv_i32 t1 = tcg_temp_new_i32(); tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc)); tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1)); - tcg_gen_nor_i32(t0, t0, t1); + tcg_gen_nand_i32(t0, t0, t1); tcg_temp_free_i32(t1); tcg_gen_andi_i32(t0, t0, 1); tcg_gen_extu_i32_tl(bcond, t0); @@ -6123,11 +6123,11 @@ static void gen_compute_branch1 (CPUMIPSState *env, DisasContext *ctx, uint32_t TCGv_i32 t1 = tcg_temp_new_i32(); tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc)); tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1)); - tcg_gen_or_i32(t0, t0, t1); + tcg_gen_and_i32(t0, t0, t1); tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+2)); - tcg_gen_or_i32(t0, t0, t1); + tcg_gen_and_i32(t0, t0, t1); tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+3)); - tcg_gen_nor_i32(t0, t0, t1); + tcg_gen_nand_i32(t0, t0, t1); tcg_temp_free_i32(t1); tcg_gen_andi_i32(t0, t0, 1); tcg_gen_extu_i32_tl(bcond, t0); diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c index 4cde48d2fd..d26569715b 100644 --- a/tcg/ppc/tcg-target.c +++ b/tcg/ppc/tcg-target.c @@ -24,7 +24,11 @@ static uint8_t *tb_ret_addr; -#ifdef _CALL_DARWIN +#if defined _CALL_DARWIN || defined __APPLE__ +#define TCG_TARGET_CALL_DARWIN +#endif + +#ifdef TCG_TARGET_CALL_DARWIN #define LINKAGE_AREA_SIZE 24 #define LR_OFFSET 8 #elif defined _CALL_AIX @@ -99,7 +103,7 @@ static const int tcg_target_reg_alloc_order[] = { TCG_REG_R29, TCG_REG_R30, TCG_REG_R31, -#ifdef _CALL_DARWIN +#ifdef TCG_TARGET_CALL_DARWIN TCG_REG_R2, #endif TCG_REG_R3, @@ -110,7 +114,7 @@ static const int tcg_target_reg_alloc_order[] = { TCG_REG_R8, TCG_REG_R9, TCG_REG_R10, -#ifndef _CALL_DARWIN +#ifndef TCG_TARGET_CALL_DARWIN TCG_REG_R11, #endif TCG_REG_R12, @@ -140,7 +144,7 @@ static const int tcg_target_call_oarg_regs[2] = { }; static const int tcg_target_callee_save_regs[] = { -#ifdef _CALL_DARWIN +#ifdef TCG_TARGET_CALL_DARWIN TCG_REG_R11, TCG_REG_R13, #endif @@ -1965,7 +1969,7 @@ static void tcg_target_init(TCGContext *s) tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); tcg_regset_set32(tcg_target_call_clobber_regs, 0, (1 << TCG_REG_R0) | -#ifdef _CALL_DARWIN +#ifdef TCG_TARGET_CALL_DARWIN (1 << TCG_REG_R2) | #endif (1 << TCG_REG_R3) | @@ -1983,7 +1987,7 @@ static void tcg_target_init(TCGContext *s) tcg_regset_clear(s->reserved_regs); tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0); tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1); -#ifndef _CALL_DARWIN +#ifndef TCG_TARGET_CALL_DARWIN tcg_regset_set_reg(s->reserved_regs, TCG_REG_R2); #endif #ifdef _CALL_SYSV diff --git a/tests/Makefile b/tests/Makefile index 20e4da9fb2..ab7f667009 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -18,8 +18,8 @@ check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh # All QTests for now are POSIX-only, but the dependencies are # really in libqtest, not in the testcases themselves. -check-qtest-i386-y = tests/rtc-test$(EXESUF) check-qtest-i386-y = tests/fdc-test$(EXESUF) +check-qtest-i386-y += tests/rtc-test$(EXESUF) check-qtest-x86_64-y = $(check-qtest-i386-y) check-qtest-sparc-y = tests/m48t59-test$(EXESUF) check-qtest-sparc64-y = tests/m48t59-test$(EXESUF) @@ -68,7 +68,7 @@ tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marsh tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y) tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y) -tests/fdc-test$(EXESUF): tests/fdc-test.o tests/libqtest.o +tests/fdc-test$(EXESUF): tests/fdc-test.o tests/libqtest.o $(trace-obj-y) # QTest rules diff --git a/tests/fdc-test.c b/tests/fdc-test.c index 5b5dd7481f..22d24ac7dc 100644 --- a/tests/fdc-test.c +++ b/tests/fdc-test.c @@ -63,6 +63,12 @@ char test_image[] = "/tmp/qtest.XXXXXX"; #define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask)) #define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0) +static uint8_t base = 0x70; + +enum { + CMOS_FLOPPY = 0x10, +}; + static void floppy_send(uint8_t byte) { uint8_t msr; @@ -108,34 +114,43 @@ static void send_step_pulse(void) cyl = (cyl + 1) % 4; } -static void test_media_change(void) +static uint8_t cmos_read(uint8_t reg) { - uint8_t dir; + outb(base + 0, reg); + return inb(base + 1); +} - /* Media changed bit must be up-to-date after step pulse. Do two SEEKs - * because we may already happen to be on the right cylinder initially. */ - send_step_pulse(); - send_step_pulse(); - dir = inb(FLOPPY_BASE + reg_dir); - assert_bit_clear(dir, DSKCHG); +static void test_cmos(void) +{ + uint8_t cmos; - /* Eject the floppy and check that DSKCHG is set. Reading it out doesn't - * reset the bit. */ - qmp("{'execute':'eject', 'arguments':{ 'device':'floppy0' }}"); - qmp(""); /* ignore event */ + cmos = cmos_read(CMOS_FLOPPY); + g_assert(cmos == 0x40); +} +static void test_no_media_on_start(void) +{ + uint8_t dir; + + /* Media changed bit must be set all time after start if there is + * no media in drive. */ dir = inb(FLOPPY_BASE + reg_dir); assert_bit_set(dir, DSKCHG); dir = inb(FLOPPY_BASE + reg_dir); assert_bit_set(dir, DSKCHG); - + send_step_pulse(); send_step_pulse(); dir = inb(FLOPPY_BASE + reg_dir); assert_bit_set(dir, DSKCHG); dir = inb(FLOPPY_BASE + reg_dir); assert_bit_set(dir, DSKCHG); +} + +static void test_media_change(void) +{ + uint8_t dir; - /* And then insert it again. DSKCHK should not be reset until a step pulse + /* Insert media in drive. DSKCHK should not be reset until a step pulse * is sent. */ qmp("{'execute':'change', 'arguments':{ 'device':'floppy0', " "'target': '%s' }}", test_image); @@ -152,6 +167,22 @@ static void test_media_change(void) assert_bit_clear(dir, DSKCHG); dir = inb(FLOPPY_BASE + reg_dir); assert_bit_clear(dir, DSKCHG); + + /* Eject the floppy and check that DSKCHG is set. Reading it out doesn't + * reset the bit. */ + qmp("{'execute':'eject', 'arguments':{ 'device':'floppy0' }}"); + qmp(""); /* ignore event */ + + dir = inb(FLOPPY_BASE + reg_dir); + assert_bit_set(dir, DSKCHG); + dir = inb(FLOPPY_BASE + reg_dir); + assert_bit_set(dir, DSKCHG); + + send_step_pulse(); + dir = inb(FLOPPY_BASE + reg_dir); + assert_bit_set(dir, DSKCHG); + dir = inb(FLOPPY_BASE + reg_dir); + assert_bit_set(dir, DSKCHG); } int main(int argc, char **argv) @@ -177,12 +208,12 @@ int main(int argc, char **argv) /* Run the tests */ g_test_init(&argc, &argv, NULL); - cmdline = g_strdup_printf("-vnc none " - "-drive file=%s,if=floppy,cache=writeback ", - test_image); + cmdline = g_strdup_printf("-vnc none "); qtest_start(cmdline); qtest_irq_intercept_in(global_qtest, "ioapic"); + qtest_add_func("/fdc/cmos", test_cmos); + qtest_add_func("/fdc/no_media_on_start", test_no_media_on_start); qtest_add_func("/fdc/media_change", test_media_change); ret = g_test_run(); diff --git a/tests/qemu-iotests/035 b/tests/qemu-iotests/035 index 56616a1b7d..9d2d3472e7 100755 --- a/tests/qemu-iotests/035 +++ b/tests/qemu-iotests/035 @@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 . ./common.rc . ./common.filter -_supported_fmt generic +_supported_fmt qcow2 _supported_proto generic _supported_os Linux diff --git a/trace-events b/trace-events index 87cb96cabf..45c6bc1271 100644 --- a/trace-events +++ b/trace-events @@ -602,9 +602,9 @@ escc_kbd_command(int val) "Command %d" escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=%01x" # block/iscsi.c -iscsi_aio_write10_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d" +iscsi_aio_write16_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d" iscsi_aio_writev(void *iscsi, int64_t sector_num, int nb_sectors, void *opaque, void *acb) "iscsi %p sector_num %"PRId64" nb_sectors %d opaque %p acb %p" -iscsi_aio_read10_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d" +iscsi_aio_read16_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d" iscsi_aio_readv(void *iscsi, int64_t sector_num, int nb_sectors, void *opaque, void *acb) "iscsi %p sector_num %"PRId64" nb_sectors %d opaque %p acb %p" # hw/esp.c |