summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2009-09-14 07:07:28 -0300
committerMarcelo Tosatti <mtosatti@redhat.com>2009-09-14 07:07:28 -0300
commit8ee4a93637fd50121edbe2d50ae965da2fcfa949 (patch)
treee4fa00ce41d91206f26a4406364e7b9cef831495
parentMerge commit '9453c5bc2634fdbdd05450034c21a58806d366a4' into upstream-merge (diff)
parentram: remove support for loading v1 (diff)
downloadqemu-kvm-8ee4a93637fd50121edbe2d50ae965da2fcfa949.tar.gz
qemu-kvm-8ee4a93637fd50121edbe2d50ae965da2fcfa949.tar.bz2
qemu-kvm-8ee4a93637fd50121edbe2d50ae965da2fcfa949.zip
Merge commit '1a621c8dc9e4dcc9d385bdd2c24c5b5dbfd0ebe4' into upstream-merge
* commit '1a621c8dc9e4dcc9d385bdd2c24c5b5dbfd0ebe4': (51 commits) ram: remove support for loading v1 move mux focus field from CharDriverState to MuxDriver monitor: fix muxing qdev: add parser for chardev properties Allow -serial chardev:<name> convert udp chardev to QemuOpts. convert mux chardev to QemuOpts. convert vc chardev to QemuOpts. convert tty + parport chardevs to QemuOpts. convert windows console chardev to QemuOpts. convert braille chardev to QemuOpts. convert msmouse chardev to QemuOpts. convert stdio chardev to QemuOpts. convert pty chardev to QemuOpts. convert unix+tcp chardevs to QemuOpts. sockets: add inet_listen_opts sockets: add inet_connect_opts sockets: add unix_*_opts for windows. sockets: add unix_listen_opts sockets: add unix_connect_opts ... Conflicts: vl.c Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r--audio/fmodaudio.c15
-rw-r--r--block.c238
-rw-r--r--block.h18
-rw-r--r--block/cow.c2
-rw-r--r--block/raw-posix-aio.h3
-rw-r--r--block/raw-posix.c19
-rw-r--r--block_int.h11
-rw-r--r--console.c47
-rw-r--r--console.h2
-rw-r--r--cpu-all.h2
-rw-r--r--cutils.c41
-rw-r--r--hw/baum.c2
-rw-r--r--hw/baum.h2
-rw-r--r--hw/cs4231a.c9
-rw-r--r--hw/gus.c21
-rw-r--r--hw/ide/core.c23
-rw-r--r--hw/mc146818rtc.c43
-rw-r--r--hw/mips_jazz.c2
-rw-r--r--hw/mips_malta.c2
-rw-r--r--hw/mips_r4k.c6
-rw-r--r--hw/msmouse.c2
-rw-r--r--hw/msmouse.h2
-rw-r--r--hw/pc.c2
-rw-r--r--hw/pc.h3
-rw-r--r--hw/pckbd.c22
-rw-r--r--hw/ppc_prep.c4
-rw-r--r--hw/qdev-properties.c11
-rw-r--r--hw/sb16.c10
-rw-r--r--hw/scsi-disk.c4
-rw-r--r--hw/virtio-blk.c80
-rw-r--r--hw/virtio-blk.h4
-rw-r--r--hw/virtio-pci.c14
-rw-r--r--hw/virtio.c3
-rw-r--r--hw/wdt_i6300esb.c8
-rw-r--r--linux-user/syscall.c2
-rw-r--r--monitor.c35
-rwxr-xr-x[-rw-r--r--]pc-bios/openbios-ppcbin291436 -> 295636 bytes
-rw-r--r--posix-aio-compat.c19
-rw-r--r--qemu-char.c466
-rw-r--r--qemu-char.h6
-rw-r--r--qemu-common.h2
-rw-r--r--qemu-config.c64
-rw-r--r--qemu-config.h6
-rw-r--r--qemu-doc.texi14
-rw-r--r--qemu-option.c46
-rw-r--r--qemu-option.h1
-rw-r--r--qemu-options.hx2
-rw-r--r--qemu-sockets.c439
-rw-r--r--qemu_socket.h7
-rw-r--r--target-microblaze/op_helper.c20
-rw-r--r--target-microblaze/translate.c57
-rw-r--r--tcg/x86_64/tcg-target.c31
-rw-r--r--usb-linux.c12
-rw-r--r--vl.c54
54 files changed, 1446 insertions, 514 deletions
diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c
index ab6a24212..e852e9e43 100644
--- a/audio/fmodaudio.c
+++ b/audio/fmodaudio.c
@@ -47,7 +47,6 @@ static struct {
int freq;
int nb_channels;
int bufsize;
- int threshold;
int broken_adc;
} conf = {
.nb_samples = 2048 * 2,
@@ -239,9 +238,7 @@ static int fmod_run_out (HWVoiceOut *hw)
return 0;
}
- if (!hw->pending_disable
- && nb_live
- && (conf.threshold && live <= conf.threshold)) {
+ if (!hw->pending_disable && nb_live) {
ldebug ("live=%d nb_live=%d\n", live, nb_live);
return 0;
}
@@ -664,15 +661,7 @@ static struct audio_option fmod_options[] = {
.tag = AUD_OPT_INT,
.valp = &conf.bufsize,
.descr = "(undocumented)"
- }
-#if 0
- {
- .name = "THRESHOLD",
- .tag = AUD_OPT_INT,
- .valp = &conf.threshold,
- .descr = "(undocumented)"
- }
-#endif
+ },
{ /* End of list */ }
};
diff --git a/block.c b/block.c
index 033957daf..0c6a97bc9 100644
--- a/block.c
+++ b/block.c
@@ -54,6 +54,8 @@ static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
+static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque);
static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
@@ -138,6 +140,10 @@ void bdrv_register(BlockDriver *bdrv)
bdrv->bdrv_read = bdrv_read_em;
bdrv->bdrv_write = bdrv_write_em;
}
+
+ if (!bdrv->bdrv_aio_flush)
+ bdrv->bdrv_aio_flush = bdrv_aio_flush_em;
+
bdrv->next = first_drv;
first_drv = bdrv;
}
@@ -408,6 +414,16 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
}
bs->drv = drv;
bs->opaque = qemu_mallocz(drv->instance_size);
+
+ /*
+ * Yes, BDRV_O_NOCACHE aka O_DIRECT means we have to present a
+ * write cache to the guest. We do need the fdatasync to flush
+ * out transactions for block allocations, and we maybe have a
+ * volatile write cache in our backing device to deal with.
+ */
+ if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
+ bs->enable_write_cache = 1;
+
/* Note: for compatibility, we open disk image files as RDWR, and
RDONLY as fallback */
if (!(flags & BDRV_O_FILE))
@@ -918,6 +934,11 @@ int bdrv_is_sg(BlockDriverState *bs)
return bs->sg;
}
+int bdrv_enable_write_cache(BlockDriverState *bs)
+{
+ return bs->enable_write_cache;
+}
+
/* XXX: no longer used */
void bdrv_set_change_cb(BlockDriverState *bs,
void (*change_cb)(void *opaque), void *opaque)
@@ -1354,6 +1375,204 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
return ret;
}
+
+typedef struct MultiwriteCB {
+ int error;
+ int num_requests;
+ int num_callbacks;
+ struct {
+ BlockDriverCompletionFunc *cb;
+ void *opaque;
+ QEMUIOVector *free_qiov;
+ void *free_buf;
+ } callbacks[];
+} MultiwriteCB;
+
+static void multiwrite_user_cb(MultiwriteCB *mcb)
+{
+ int i;
+
+ for (i = 0; i < mcb->num_callbacks; i++) {
+ mcb->callbacks[i].cb(mcb->callbacks[i].opaque, mcb->error);
+ qemu_free(mcb->callbacks[i].free_qiov);
+ qemu_free(mcb->callbacks[i].free_buf);
+ }
+}
+
+static void multiwrite_cb(void *opaque, int ret)
+{
+ MultiwriteCB *mcb = opaque;
+
+ if (ret < 0) {
+ mcb->error = ret;
+ multiwrite_user_cb(mcb);
+ }
+
+ mcb->num_requests--;
+ if (mcb->num_requests == 0) {
+ if (mcb->error == 0) {
+ multiwrite_user_cb(mcb);
+ }
+ qemu_free(mcb);
+ }
+}
+
+static int multiwrite_req_compare(const void *a, const void *b)
+{
+ return (((BlockRequest*) a)->sector - ((BlockRequest*) b)->sector);
+}
+
+/*
+ * Takes a bunch of requests and tries to merge them. Returns the number of
+ * requests that remain after merging.
+ */
+static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
+ int num_reqs, MultiwriteCB *mcb)
+{
+ int i, outidx;
+
+ // Sort requests by start sector
+ qsort(reqs, num_reqs, sizeof(*reqs), &multiwrite_req_compare);
+
+ // Check if adjacent requests touch the same clusters. If so, combine them,
+ // filling up gaps with zero sectors.
+ outidx = 0;
+ for (i = 1; i < num_reqs; i++) {
+ int merge = 0;
+ int64_t oldreq_last = reqs[outidx].sector + reqs[outidx].nb_sectors;
+
+ // This handles the cases that are valid for all block drivers, namely
+ // exactly sequential writes and overlapping writes.
+ if (reqs[i].sector <= oldreq_last) {
+ merge = 1;
+ }
+
+ // The block driver may decide that it makes sense to combine requests
+ // even if there is a gap of some sectors between them. In this case,
+ // the gap is filled with zeros (therefore only applicable for yet
+ // unused space in format like qcow2).
+ if (!merge && bs->drv->bdrv_merge_requests) {
+ merge = bs->drv->bdrv_merge_requests(bs, &reqs[outidx], &reqs[i]);
+ }
+
+ if (merge) {
+ size_t size;
+ QEMUIOVector *qiov = qemu_mallocz(sizeof(*qiov));
+ qemu_iovec_init(qiov,
+ reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1);
+
+ // Add the first request to the merged one. If the requests are
+ // overlapping, drop the last sectors of the first request.
+ size = (reqs[i].sector - reqs[outidx].sector) << 9;
+ qemu_iovec_concat(qiov, reqs[outidx].qiov, size);
+
+ // We might need to add some zeros between the two requests
+ if (reqs[i].sector > oldreq_last) {
+ size_t zero_bytes = (reqs[i].sector - oldreq_last) << 9;
+ uint8_t *buf = qemu_blockalign(bs, zero_bytes);
+ memset(buf, 0, zero_bytes);
+ qemu_iovec_add(qiov, buf, zero_bytes);
+ mcb->callbacks[i].free_buf = buf;
+ }
+
+ // Add the second request
+ qemu_iovec_concat(qiov, reqs[i].qiov, reqs[i].qiov->size);
+
+ reqs[outidx].nb_sectors += reqs[i].nb_sectors;
+ reqs[outidx].qiov = qiov;
+
+ mcb->callbacks[i].free_qiov = reqs[outidx].qiov;
+ } else {
+ outidx++;
+ reqs[outidx].sector = reqs[i].sector;
+ reqs[outidx].nb_sectors = reqs[i].nb_sectors;
+ reqs[outidx].qiov = reqs[i].qiov;
+ }
+ }
+
+ return outidx + 1;
+}
+
+/*
+ * Submit multiple AIO write requests at once.
+ *
+ * On success, the function returns 0 and all requests in the reqs array have
+ * been submitted. In error case this function returns -1, and any of the
+ * requests may or may not be submitted yet. In particular, this means that the
+ * callback will be called for some of the requests, for others it won't. The
+ * caller must check the error field of the BlockRequest to wait for the right
+ * callbacks (if error != 0, no callback will be called).
+ *
+ * The implementation may modify the contents of the reqs array, e.g. to merge
+ * requests. However, the fields opaque and error are left unmodified as they
+ * are used to signal failure for a single request to the caller.
+ */
+int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
+{
+ BlockDriverAIOCB *acb;
+ MultiwriteCB *mcb;
+ int i;
+
+ if (num_reqs == 0) {
+ return 0;
+ }
+
+ // Create MultiwriteCB structure
+ mcb = qemu_mallocz(sizeof(*mcb) + num_reqs * sizeof(*mcb->callbacks));
+ mcb->num_requests = 0;
+ mcb->num_callbacks = num_reqs;
+
+ for (i = 0; i < num_reqs; i++) {
+ mcb->callbacks[i].cb = reqs[i].cb;
+ mcb->callbacks[i].opaque = reqs[i].opaque;
+ }
+
+ // Check for mergable requests
+ num_reqs = multiwrite_merge(bs, reqs, num_reqs, mcb);
+
+ // Run the aio requests
+ for (i = 0; i < num_reqs; i++) {
+ acb = bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov,
+ reqs[i].nb_sectors, multiwrite_cb, mcb);
+
+ if (acb == NULL) {
+ // We can only fail the whole thing if no request has been
+ // submitted yet. Otherwise we'll wait for the submitted AIOs to
+ // complete and report the error in the callback.
+ if (mcb->num_requests == 0) {
+ reqs[i].error = EIO;
+ goto fail;
+ } else {
+ mcb->error = EIO;
+ break;
+ }
+ } else {
+ mcb->num_requests++;
+ }
+ }
+
+ return 0;
+
+fail:
+ free(mcb);
+ return -1;
+}
+
+BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BlockDriver *drv = bs->drv;
+
+ if (!drv)
+ return NULL;
+
+ /*
+ * Note that unlike bdrv_flush the driver is reponsible for flushing a
+ * backing image if it exists.
+ */
+ return drv->bdrv_aio_flush(bs, cb, opaque);
+}
+
void bdrv_aio_cancel(BlockDriverAIOCB *acb)
{
acb->pool->cancel(acb);
@@ -1444,6 +1663,25 @@ static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
}
+static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BlockDriverAIOCBSync *acb;
+
+ acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
+ acb->is_write = 1; /* don't bounce in the completion hadler */
+ acb->qiov = NULL;
+ acb->bounce = NULL;
+ acb->ret = 0;
+
+ if (!acb->bh)
+ acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+
+ bdrv_flush(bs);
+ qemu_bh_schedule(acb->bh);
+ return &acb->common;
+}
+
/**************************************************************/
/* sync block device emulation */
diff --git a/block.h b/block.h
index 28bf35709..a966afb09 100644
--- a/block.h
+++ b/block.h
@@ -85,8 +85,25 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque);
void bdrv_aio_cancel(BlockDriverAIOCB *acb);
+typedef struct BlockRequest {
+ /* Fields to be filled by multiwrite caller */
+ int64_t sector;
+ int nb_sectors;
+ QEMUIOVector *qiov;
+ BlockDriverCompletionFunc *cb;
+ void *opaque;
+
+ /* Filled by multiwrite implementation */
+ int error;
+} BlockRequest;
+
+int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs,
+ int num_reqs);
+
/* sg packet commands */
int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf);
BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
@@ -120,6 +137,7 @@ int bdrv_get_translation_hint(BlockDriverState *bs);
int bdrv_is_removable(BlockDriverState *bs);
int bdrv_is_read_only(BlockDriverState *bs);
int bdrv_is_sg(BlockDriverState *bs);
+int bdrv_enable_write_cache(BlockDriverState *bs);
int bdrv_is_inserted(BlockDriverState *bs);
int bdrv_media_changed(BlockDriverState *bs);
int bdrv_is_locked(BlockDriverState *bs);
diff --git a/block/cow.c b/block/cow.c
index 84818f103..a70854e63 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -258,7 +258,7 @@ static int cow_create(const char *filename, QEMUOptionParameter *options)
static void cow_flush(BlockDriverState *bs)
{
BDRVCowState *s = bs->opaque;
- fsync(s->fd);
+ qemu_fdatasync(s->fd);
}
static QEMUOptionParameter cow_create_options[] = {
diff --git a/block/raw-posix-aio.h b/block/raw-posix-aio.h
index 244bc8b79..a2d4348ee 100644
--- a/block/raw-posix-aio.h
+++ b/block/raw-posix-aio.h
@@ -17,8 +17,9 @@
#define QEMU_AIO_READ 0x0001
#define QEMU_AIO_WRITE 0x0002
#define QEMU_AIO_IOCTL 0x0004
+#define QEMU_AIO_FLUSH 0x0008
#define QEMU_AIO_TYPE_MASK \
- (QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL)
+ (QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH)
/* AIO flags */
#define QEMU_AIO_MISALIGNED 0x1000
diff --git a/block/raw-posix.c b/block/raw-posix.c
index f9792d911..dfc4a316e 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -576,6 +576,18 @@ static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
cb, opaque, QEMU_AIO_WRITE);
}
+static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BDRVRawState *s = bs->opaque;
+
+ if (fd_open(bs) < 0)
+ return NULL;
+
+ return paio_submit(bs, s->aio_ctx, s->fd, 0, NULL, 0,
+ cb, opaque, QEMU_AIO_FLUSH);
+}
+
static void raw_close(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
@@ -725,7 +737,7 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
static void raw_flush(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
- fsync(s->fd);
+ qemu_fdatasync(s->fd);
}
@@ -751,6 +763,7 @@ static BlockDriver bdrv_raw = {
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
+ .bdrv_aio_flush = raw_aio_flush,
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
@@ -1004,6 +1017,7 @@ static BlockDriver bdrv_host_device = {
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
+ .bdrv_aio_flush = raw_aio_flush,
.bdrv_read = raw_read,
.bdrv_write = raw_write,
@@ -1098,6 +1112,7 @@ static BlockDriver bdrv_host_floppy = {
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
+ .bdrv_aio_flush = raw_aio_flush,
.bdrv_read = raw_read,
.bdrv_write = raw_write,
@@ -1178,6 +1193,7 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
+ .bdrv_aio_flush = raw_aio_flush,
.bdrv_read = raw_read,
.bdrv_write = raw_write,
@@ -1297,6 +1313,7 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
+ .bdrv_aio_flush = raw_aio_flush,
.bdrv_read = raw_read,
.bdrv_write = raw_write,
diff --git a/block_int.h b/block_int.h
index 0902fd473..8e72abee0 100644
--- a/block_int.h
+++ b/block_int.h
@@ -69,6 +69,14 @@ struct BlockDriver {
BlockDriverAIOCB *(*bdrv_aio_writev)(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
+ BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque);
+
+ int (*bdrv_aio_multiwrite)(BlockDriverState *bs, BlockRequest *reqs,
+ int num_reqs);
+ int (*bdrv_merge_requests)(BlockDriverState *bs, BlockRequest* a,
+ BlockRequest *b);
+
const char *protocol_name;
int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
@@ -152,6 +160,9 @@ struct BlockDriverState {
/* the memory alignment required for the buffers handled by this driver */
int buffer_alignment;
+ /* do we need to tell the quest if we have a volatile write cache? */
+ int enable_write_cache;
+
/* NOTE: the following infos are only hints for real hardware
drivers. They are not used by the block driver */
int cyls, heads, secs, translation;
diff --git a/console.c b/console.c
index d55e0fdc0..9bbef593b 100644
--- a/console.c
+++ b/console.c
@@ -1317,16 +1317,31 @@ void console_color_init(DisplayState *ds)
static int n_text_consoles;
static CharDriverState *text_consoles[128];
-static char *text_console_strs[128];
+static QemuOpts *text_console_opts[128];
-static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const char *p)
+static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpts *opts)
{
TextConsole *s;
unsigned width;
unsigned height;
static int color_inited;
- s = new_console(ds, (p == NULL) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
+ width = qemu_opt_get_number(opts, "width", 0);
+ if (width == 0)
+ width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
+
+ height = qemu_opt_get_number(opts, "height", 0);
+ if (height == 0)
+ height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
+
+ if (width == 0 || height == 0) {
+ s = new_console(ds, TEXT_CONSOLE);
+ width = ds_get_width(s->ds);
+ height = ds_get_height(s->ds);
+ } else {
+ s = new_console(ds, TEXT_CONSOLE_FIXED_SIZE);
+ }
+
if (!s) {
free(chr);
return;
@@ -1350,23 +1365,6 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const c
s->total_height = DEFAULT_BACKSCROLL;
s->x = 0;
s->y = 0;
- width = ds_get_width(s->ds);
- height = ds_get_height(s->ds);
- if (p != NULL) {
- width = strtoul(p, (char **)&p, 10);
- if (*p == 'C') {
- p++;
- width *= FONT_WIDTH;
- }
- if (*p == 'x') {
- p++;
- height = strtoul(p, (char **)&p, 10);
- if (*p == 'C') {
- p++;
- height *= FONT_HEIGHT;
- }
- }
- }
s->g_width = width;
s->g_height = height;
@@ -1391,7 +1389,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const c
chr->init(chr);
}
-CharDriverState *text_console_init(const char *p)
+CharDriverState *text_console_init(QemuOpts *opts)
{
CharDriverState *chr;
@@ -1402,7 +1400,7 @@ CharDriverState *text_console_init(const char *p)
exit(1);
}
text_consoles[n_text_consoles] = chr;
- text_console_strs[n_text_consoles] = p ? qemu_strdup(p) : NULL;
+ text_console_opts[n_text_consoles] = opts;
n_text_consoles++;
return chr;
@@ -1413,8 +1411,9 @@ void text_consoles_set_display(DisplayState *ds)
int i;
for (i = 0; i < n_text_consoles; i++) {
- text_console_do_init(text_consoles[i], ds, text_console_strs[i]);
- qemu_free(text_console_strs[i]);
+ text_console_do_init(text_consoles[i], ds, text_console_opts[i]);
+ qemu_opts_del(text_console_opts[i]);
+ text_console_opts[i] = NULL;
}
n_text_consoles = 0;
diff --git a/console.h b/console.h
index c8922e4f4..9615f5636 100644
--- a/console.h
+++ b/console.h
@@ -303,7 +303,7 @@ void vga_hw_text_update(console_ch_t *chardata);
int is_graphic_console(void);
int is_fixedsize_console(void);
-CharDriverState *text_console_init(const char *p);
+CharDriverState *text_console_init(QemuOpts *opts);
void text_consoles_set_display(DisplayState *ds);
void console_select(unsigned int index);
void console_color_init(DisplayState *ds);
diff --git a/cpu-all.h b/cpu-all.h
index 135af3f5a..93000ffd2 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -1022,7 +1022,7 @@ static inline int64_t cpu_get_real_ticks (void)
static inline int64_t cpu_get_real_ticks(void)
{
-#if __mips_isa_rev >= 2
+#if defined(__mips_isa_rev) && __mips_isa_rev >= 2
uint32_t count;
static uint32_t cyc_per_count = 0;
diff --git a/cutils.c b/cutils.c
index c8d532623..7163d3a36 100644
--- a/cutils.c
+++ b/cutils.c
@@ -115,6 +115,22 @@ int qemu_fls(int i)
return 32 - clz32(i);
}
+/*
+ * Make sure data goes on disk, but if possible do not bother to
+ * write out the inode just for timestamp updates.
+ *
+ * Unfortunately even in 2009 many operating systems do not support
+ * fdatasync and have to fall back to fsync.
+ */
+int qemu_fdatasync(int fd)
+{
+#ifdef _POSIX_SYNCHRONIZED_IO
+ return fdatasync(fd);
+#else
+ return fsync(fd);
+#endif
+}
+
/* io vectors */
void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint)
@@ -151,6 +167,31 @@ void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
++qiov->niov;
}
+/*
+ * Copies iovecs from src to the end dst until src is completely copied or the
+ * total size of the copied iovec reaches size. The size of the last copied
+ * iovec is changed in order to fit the specified total size if it isn't a
+ * perfect fit already.
+ */
+void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t size)
+{
+ int i;
+ size_t done;
+
+ assert(dst->nalloc != -1);
+
+ done = 0;
+ for (i = 0; (i < src->niov) && (done != size); i++) {
+ if (done + src->iov[i].iov_len > size) {
+ qemu_iovec_add(dst, src->iov[i].iov_base, size - done);
+ break;
+ } else {
+ qemu_iovec_add(dst, src->iov[i].iov_base, src->iov[i].iov_len);
+ }
+ done += src->iov[i].iov_len;
+ }
+}
+
void qemu_iovec_destroy(QEMUIOVector *qiov)
{
assert(qiov->nalloc != -1);
diff --git a/hw/baum.c b/hw/baum.c
index b47ea34c4..a23e685d7 100644
--- a/hw/baum.c
+++ b/hw/baum.c
@@ -563,7 +563,7 @@ static void baum_chr_read(void *opaque)
}
}
-CharDriverState *chr_baum_init(void)
+CharDriverState *chr_baum_init(QemuOpts *opts)
{
BaumDriverState *baum;
CharDriverState *chr;
diff --git a/hw/baum.h b/hw/baum.h
index ac34b3042..39ca4b12d 100644
--- a/hw/baum.h
+++ b/hw/baum.h
@@ -26,4 +26,4 @@
USBDevice *usb_baum_init(void);
/* char device */
-CharDriverState *chr_baum_init(void);
+CharDriverState *chr_baum_init(QemuOpts *opts);
diff --git a/hw/cs4231a.c b/hw/cs4231a.c
index 91ee2aa2c..e03c5d242 100644
--- a/hw/cs4231a.c
+++ b/hw/cs4231a.c
@@ -659,12 +659,13 @@ static int cs4231a_initfn (ISADevice *dev)
int cs4231a_init (qemu_irq *pic)
{
- isa_create_simple("cs4231a");
+ isa_create_simple ("cs4231a");
return 0;
}
static ISADeviceInfo cs4231a_info = {
.qdev.name = "cs4231a",
+ .qdev.desc = "Crystal Semiconductor CS4231A",
.qdev.size = sizeof (CSState),
.init = cs4231a_initfn,
.qdev.props = (Property[]) {
@@ -675,8 +676,8 @@ static ISADeviceInfo cs4231a_info = {
},
};
-static void cs4231a_register(void)
+static void cs4231a_register (void)
{
- isa_qdev_register(&cs4231a_info);
+ isa_qdev_register (&cs4231a_info);
}
-device_init(cs4231a_register)
+device_init (cs4231a_register)
diff --git a/hw/gus.c b/hw/gus.c
index b41095e11..3df10e29e 100644
--- a/hw/gus.c
+++ b/hw/gus.c
@@ -46,13 +46,6 @@
#define IO_WRITE_PROTO(name) \
static void name (void *opaque, uint32_t nport, uint32_t val)
-static struct {
- int port;
- int irq;
- int dma;
- int freq;
-} conf = {0x240, 7, 3, 44100};
-
typedef struct GUSState {
ISADevice dev;
GUSEmuState emu;
@@ -300,11 +293,11 @@ static int gus_initfn (ISADevice *dev)
register_ioport_read (s->port + 0x100, 8, 1, gus_readb, s);
register_ioport_read (s->port + 0x100, 8, 2, gus_readw, s);
- DMA_register_channel (conf.dma, GUS_read_DMA, s);
+ DMA_register_channel (s->emu.gusdma, GUS_read_DMA, s);
s->emu.himemaddr = s->himem;
s->emu.gusdatapos = s->emu.himemaddr + 1024 * 1024 + 32;
s->emu.opaque = s;
- isa_init_irq(dev, &s->pic, s->emu.gusirq);
+ isa_init_irq (dev, &s->pic, s->emu.gusirq);
AUD_set_active_out (s->voice, 1);
@@ -314,13 +307,13 @@ static int gus_initfn (ISADevice *dev)
int GUS_init (qemu_irq *pic)
{
- isa_create_simple("gus");
+ isa_create_simple ("gus");
return 0;
}
static ISADeviceInfo gus_info = {
.qdev.name = "gus",
- .qdev.desc = "Creative Sound Blaster 16",
+ .qdev.desc = "Gravis Ultrasound GF1",
.qdev.size = sizeof (GUSState),
.init = gus_initfn,
.qdev.props = (Property[]) {
@@ -332,8 +325,8 @@ static ISADeviceInfo gus_info = {
},
};
-static void gus_register(void)
+static void gus_register (void)
{
- isa_qdev_register(&gus_info);
+ isa_qdev_register (&gus_info);
}
-device_init(gus_register)
+device_init (gus_register)
diff --git a/hw/ide/core.c b/hw/ide/core.c
index fe5bd172a..87d5cdf6e 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -148,8 +148,11 @@ static void ide_identify(IDEState *s)
put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
/* 14=set to 1, 1=SMART self test, 0=SMART error logging */
put_le16(p + 84, (1 << 14) | 0);
- /* 14 = NOP supported, 0=SMART feature set enabled */
- put_le16(p + 85, (1 << 14) | 1);
+ /* 14 = NOP supported, 5=WCACHE enabled, 0=SMART feature set enabled */
+ if (bdrv_enable_write_cache(s->bs))
+ put_le16(p + 85, (1 << 14) | (1 << 5) | 1);
+ else
+ put_le16(p + 85, (1 << 14) | 1);
/* 13=flush_cache_ext,12=flush_cache,10=lba48 */
put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
/* 14=set to 1, 1=smart self test, 0=smart error logging */
@@ -768,6 +771,16 @@ static void ide_atapi_cmd_check_status(IDEState *s)
ide_set_irq(s->bus);
}
+static void ide_flush_cb(void *opaque, int ret)
+{
+ IDEState *s = opaque;
+
+ /* XXX: how do we signal I/O errors here? */
+
+ s->status = READY_STAT | SEEK_STAT;
+ ide_set_irq(s->bus);
+}
+
static inline void cpu_to_ube16(uint8_t *buf, int val)
{
buf[0] = val >> 8;
@@ -1966,9 +1979,9 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
case WIN_FLUSH_CACHE:
case WIN_FLUSH_CACHE_EXT:
if (s->bs)
- bdrv_flush(s->bs);
- s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s->bus);
+ bdrv_aio_flush(s->bs, ide_flush_cb, s);
+ else
+ ide_flush_cb(s, 0);
break;
case WIN_STANDBY:
case WIN_STANDBY2:
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 5f1760c58..a1ff9baa3 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -63,10 +63,11 @@
#define REG_C_AF 0x20
struct RTCState {
+ ISADevice dev;
uint8_t cmos_data[128];
uint8_t cmos_index;
struct tm current_tm;
- int base_year;
+ int32_t base_year;
qemu_irq irq;
qemu_irq sqw_irq;
int it_shift;
@@ -589,20 +590,19 @@ static void rtc_reset(void *opaque)
#endif
}
-RTCState *rtc_init_sqw(int base, qemu_irq irq, qemu_irq sqw_irq, int base_year)
+static int rtc_initfn(ISADevice *dev)
{
- RTCState *s;
+ RTCState *s = DO_UPCAST(RTCState, dev, dev);
+ int base = 0x70;
+ int isairq = 8;
- s = qemu_mallocz(sizeof(RTCState));
+ isa_init_irq(dev, &s->irq, isairq);
- s->irq = irq;
- s->sqw_irq = sqw_irq;
s->cmos_data[RTC_REG_A] = 0x26;
s->cmos_data[RTC_REG_B] = 0x02;
s->cmos_data[RTC_REG_C] = 0x00;
s->cmos_data[RTC_REG_D] = 0x80;
- s->base_year = base_year;
rtc_set_date_from_host(s);
s->periodic_timer = qemu_new_timer(vm_clock,
@@ -628,14 +628,35 @@ RTCState *rtc_init_sqw(int base, qemu_irq irq, qemu_irq sqw_irq, int base_year)
register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s);
#endif
qemu_register_reset(rtc_reset, s);
-
- return s;
+ return 0;
}
-RTCState *rtc_init(int base, qemu_irq irq, int base_year)
+RTCState *rtc_init(int base_year)
+{
+ ISADevice *dev;
+
+ dev = isa_create("mc146818rtc");
+ qdev_prop_set_int32(&dev->qdev, "base_year", base_year);
+ qdev_init(&dev->qdev);
+ return DO_UPCAST(RTCState, dev, dev);
+}
+
+static ISADeviceInfo mc146818rtc_info = {
+ .qdev.name = "mc146818rtc",
+ .qdev.size = sizeof(RTCState),
+ .qdev.no_user = 1,
+ .init = rtc_initfn,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void mc146818rtc_register(void)
{
- return rtc_init_sqw(base, irq, NULL, base_year);
+ isa_qdev_register(&mc146818rtc_info);
}
+device_init(mc146818rtc_register)
/* Memory mapped interface */
static uint32_t cmos_mm_readb (void *opaque, target_phys_addr_t addr)
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 1cbd947fe..d62a584a9 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -241,7 +241,7 @@ void mips_jazz_init (ram_addr_t ram_size,
fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds);
/* Real time clock */
- rtc_init(0x70, i8259[8], 1980);
+ rtc_init(1980);
s_rtc = cpu_register_io_memory(rtc_read, rtc_write, env);
cpu_register_physical_memory(0x80004000, 0x00001000, s_rtc);
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 32c7102f7..25e32bf73 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -923,7 +923,7 @@ void mips_malta_init (ram_addr_t ram_size,
/* Super I/O */
isa_dev = isa_create_simple("i8042");
- rtc_state = rtc_init(0x70, isa_reserve_irq(8), 2000);
+ rtc_state = rtc_init(2000);
serial_init(0x3f8, isa_reserve_irq(4), 115200, serial_hds[0]);
serial_init(0x2f8, isa_reserve_irq(3), 115200, serial_hds[1]);
if (parallel_hds[0])
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index aacb256dc..d801417f5 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -241,8 +241,10 @@ void mips_r4k_init (ram_addr_t ram_size,
/* The PIC is attached to the MIPS CPU INT0 pin */
i8259 = i8259_init(env->irq[2]);
+ isa_bus_new(NULL);
+ isa_bus_irqs(i8259);
- rtc_state = rtc_init(0x70, i8259[8], 2000);
+ rtc_state = rtc_init(2000);
/* Register 64 KB of ISA IO space at 0x14000000 */
isa_mmio_init(0x14000000, 0x00010000);
@@ -276,7 +278,7 @@ void mips_r4k_init (ram_addr_t ram_size,
hd[MAX_IDE_DEVS * i],
hd[MAX_IDE_DEVS * i + 1]);
- i8042_init(i8259[1], i8259[12], 0x60);
+ isa_create_simple("i8042");
}
static QEMUMachine mips_machine = {
diff --git a/hw/msmouse.c b/hw/msmouse.c
index 69356a535..05f893ca9 100644
--- a/hw/msmouse.c
+++ b/hw/msmouse.c
@@ -64,7 +64,7 @@ static void msmouse_chr_close (struct CharDriverState *chr)
qemu_free (chr);
}
-CharDriverState *qemu_chr_open_msmouse(void)
+CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
{
CharDriverState *chr;
diff --git a/hw/msmouse.h b/hw/msmouse.h
index 947afd990..456cb2142 100644
--- a/hw/msmouse.h
+++ b/hw/msmouse.h
@@ -1,2 +1,2 @@
/* msmouse.c */
-CharDriverState *qemu_chr_open_msmouse(void);
+CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts);
diff --git a/hw/pc.c b/hw/pc.c
index a202755c6..6e1b4550b 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1332,7 +1332,7 @@ static void pc_init1(ram_addr_t ram_size,
}
}
- rtc_state = rtc_init(0x70, isa_reserve_irq(8), 2000);
+ rtc_state = rtc_init(2000);
qemu_register_boot_set(pc_boot_set, rtc_state);
diff --git a/hw/pc.h b/hw/pc.h
index a90ef87f3..3b58e5ffa 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -87,8 +87,7 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
typedef struct RTCState RTCState;
-RTCState *rtc_init(int base, qemu_irq irq, int base_year);
-RTCState *rtc_init_sqw(int base, qemu_irq irq, qemu_irq sqw_irq, int base_year);
+RTCState *rtc_init(int base_year);
RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
int base_year);
void rtc_set_memory(RTCState *s, int addr, int val);
diff --git a/hw/pckbd.c b/hw/pckbd.c
index 5acf4a633..3d573c2ee 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -362,28 +362,6 @@ static int kbd_load(QEMUFile* f, void* opaque, int version_id)
return 0;
}
-void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base)
-{
- KBDState *s = &kbd_state;
-
- s->irq_kbd = kbd_irq;
- s->irq_mouse = mouse_irq;
-
- kbd_reset(s);
- register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s);
- register_ioport_read(io_base, 1, 1, kbd_read_data, s);
- register_ioport_write(io_base, 1, 1, kbd_write_data, s);
- register_ioport_read(io_base + 4, 1, 1, kbd_read_status, s);
- register_ioport_write(io_base + 4, 1, 1, kbd_write_command, s);
-
- s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
- s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
-#ifdef TARGET_I386
- vmmouse_init(s->mouse);
-#endif
- qemu_register_reset(kbd_reset, s);
-}
-
/* Memory mapped interface */
static uint32_t kbd_mm_readb (void *opaque, target_phys_addr_t addr)
{
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index cde235ae2..19301467f 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -680,7 +680,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
pci_vga_init(pci_bus, 0, 0);
// openpic = openpic_init(0x00000000, 0xF0000000, 1);
// pit = pit_init(0x40, i8259[0]);
- rtc_init(0x70, i8259[8], 2000);
+ rtc_init(2000);
serial_init(0x3f8, i8259[4], 115200, serial_hds[0]);
nb_nics1 = nb_nics;
@@ -711,7 +711,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
hd[2 * i],
hd[2 * i + 1]);
}
- i8042_init(i8259[1], i8259[12], 0x60);
+ isa_create_simple("i8042");
DMA_init(1);
// SB16_init();
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 28b2716b0..2ecb58df2 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -193,6 +193,16 @@ PropertyInfo qdev_prop_drive = {
/* --- character device --- */
+static int parse_chr(DeviceState *dev, Property *prop, const char *str)
+{
+ CharDriverState **ptr = qdev_get_prop_ptr(dev, prop);
+
+ *ptr = qemu_chr_find(str);
+ if (*ptr == NULL)
+ return -1;
+ return 0;
+}
+
static int print_chr(DeviceState *dev, Property *prop, char *dest, size_t len)
{
CharDriverState **ptr = qdev_get_prop_ptr(dev, prop);
@@ -208,6 +218,7 @@ PropertyInfo qdev_prop_chr = {
.name = "chr",
.type = PROP_TYPE_CHR,
.size = sizeof(CharDriverState*),
+ .parse = parse_chr,
.print = print_chr,
};
diff --git a/hw/sb16.c b/hw/sb16.c
index 41055795c..38c5b7277 100644
--- a/hw/sb16.c
+++ b/hw/sb16.c
@@ -869,7 +869,7 @@ static void reset (SB16State *s)
s->v2x6 = 0;
s->cmd = -1;
- dsp_out_data(s, 0xaa);
+ dsp_out_data (s, 0xaa);
speaker (s, 0);
control (s, 0);
legacy_reset (s);
@@ -1440,7 +1440,7 @@ static int sb16_initfn (ISADevice *dev)
int SB16_init (qemu_irq *pic)
{
- isa_create_simple("sb16");
+ isa_create_simple ("sb16");
return 0;
}
@@ -1459,8 +1459,8 @@ static ISADeviceInfo sb16_info = {
},
};
-static void sb16_register(void)
+static void sb16_register (void)
{
- isa_qdev_register(&sb16_info);
+ isa_qdev_register (&sb16_info);
}
-device_init(sb16_register)
+device_init (sb16_register)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index ffc2654bf..de8e314b1 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -709,7 +709,9 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
memset(p,0,20);
p[0] = 8;
p[1] = 0x12;
- p[2] = 4; /* WCE */
+ if (bdrv_enable_write_cache(s->dinfo->bdrv)) {
+ p[2] = 4; /* WCE */
+ }
p += 20;
}
if ((page == 0x3f || page == 0x2a)
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index c1602460b..2d6d71afa 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -27,6 +27,7 @@ typedef struct VirtIOBlock
void *rq;
char serial_str[BLOCK_SERIAL_STRLEN + 1];
QEMUBH *bh;
+ size_t config_size;
} VirtIOBlock;
static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
@@ -129,6 +130,13 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
}
+static void virtio_blk_flush_complete(void *opaque, int ret)
+{
+ VirtIOBlockReq *req = opaque;
+
+ virtio_blk_req_complete(req, ret ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK);
+}
+
static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
{
VirtIOBlockReq *req = qemu_mallocz(sizeof(*req));
@@ -252,17 +260,52 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
}
#endif /* __linux__ */
-static void virtio_blk_handle_write(VirtIOBlockReq *req)
+static void do_multiwrite(BlockDriverState *bs, BlockRequest *blkreq,
+ int num_writes)
+{
+ int i, ret;
+ ret = bdrv_aio_multiwrite(bs, blkreq, num_writes);
+
+ if (ret != 0) {
+ for (i = 0; i < num_writes; i++) {
+ if (blkreq[i].error) {
+ virtio_blk_req_complete(blkreq[i].opaque, VIRTIO_BLK_S_IOERR);
+ }
+ }
+ }
+}
+
+static void virtio_blk_handle_flush(VirtIOBlockReq *req)
{
BlockDriverAIOCB *acb;
- acb = bdrv_aio_writev(req->dev->bs, req->out->sector, &req->qiov,
- req->qiov.size / 512, virtio_blk_rw_complete, req);
+ acb = bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req);
if (!acb) {
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
}
}
+static void virtio_blk_handle_write(BlockRequest *blkreq, int *num_writes,
+ VirtIOBlockReq *req, BlockDriverState **old_bs)
+{
+ if (req->dev->bs != *old_bs || *num_writes == 32) {
+ if (*old_bs != NULL) {
+ do_multiwrite(*old_bs, blkreq, *num_writes);
+ }
+ *num_writes = 0;
+ *old_bs = req->dev->bs;
+ }
+
+ blkreq[*num_writes].sector = req->out->sector;
+ blkreq[*num_writes].nb_sectors = req->qiov.size / 512;
+ blkreq[*num_writes].qiov = &req->qiov;
+ blkreq[*num_writes].cb = virtio_blk_rw_complete;
+ blkreq[*num_writes].opaque = req;
+ blkreq[*num_writes].error = 0;
+
+ (*num_writes)++;
+}
+
static void virtio_blk_handle_read(VirtIOBlockReq *req)
{
BlockDriverAIOCB *acb;
@@ -278,6 +321,9 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOBlock *s = to_virtio_blk(vdev);
VirtIOBlockReq *req;
+ BlockRequest blkreq[32];
+ int num_writes = 0;
+ BlockDriverState *old_bs = NULL;
while ((req = virtio_blk_get_request(s))) {
if (req->elem.out_num < 1 || req->elem.in_num < 1) {
@@ -294,18 +340,25 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
req->out = (void *)req->elem.out_sg[0].iov_base;
req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
- if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
+ if (req->out->type & VIRTIO_BLK_T_FLUSH) {
+ virtio_blk_handle_flush(req);
+ } else if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
virtio_blk_handle_scsi(req);
} else if (req->out->type & VIRTIO_BLK_T_OUT) {
qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
req->elem.out_num - 1);
- virtio_blk_handle_write(req);
+ virtio_blk_handle_write(blkreq, &num_writes, req, &old_bs);
} else {
qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
req->elem.in_num - 1);
virtio_blk_handle_read(req);
}
}
+
+ if (num_writes > 0) {
+ do_multiwrite(old_bs, blkreq, num_writes);
+ }
+
/*
* FIXME: Want to check for completions before returning to guest mode,
* so cached reads and writes are reported as quickly as possible. But
@@ -324,7 +377,8 @@ static void virtio_blk_dma_restart_bh(void *opaque)
s->rq = NULL;
while (req) {
- virtio_blk_handle_write(req);
+ bdrv_aio_writev(req->dev->bs, req->out->sector, &req->qiov,
+ req->qiov.size / 512, virtio_blk_rw_complete, req);
req = req->next;
}
}
@@ -372,7 +426,7 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
virtio_identify_template(&blkcfg);
memcpy(&blkcfg.identify[VIRTIO_BLK_ID_SN], s->serial_str,
VIRTIO_BLK_ID_SN_BYTES);
- memcpy(config, &blkcfg, sizeof(blkcfg));
+ memcpy(config, &blkcfg, s->config_size);
}
static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
@@ -382,6 +436,9 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
features |= (1 << VIRTIO_BLK_F_SEG_MAX);
features |= (1 << VIRTIO_BLK_F_GEOMETRY);
+
+ if (bdrv_enable_write_cache(s->bs))
+ features |= (1 << VIRTIO_BLK_F_WCACHE);
#ifdef __linux__
features |= (1 << VIRTIO_BLK_F_SCSI);
#endif
@@ -429,18 +486,21 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, DriveInfo *dinfo)
VirtIOBlock *s;
int cylinders, heads, secs;
static int virtio_blk_id;
- char *ps;
+ char *ps = (char *)drive_get_serial(dinfo->bdrv);
+ size_t size = strlen(ps) ? sizeof(struct virtio_blk_config) :
+ offsetof(struct virtio_blk_config, _blk_size);
s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK,
- sizeof(struct virtio_blk_config),
+ size,
sizeof(VirtIOBlock));
+ s->config_size = size;
s->vdev.get_config = virtio_blk_update_config;
s->vdev.get_features = virtio_blk_get_features;
s->vdev.reset = virtio_blk_reset;
s->bs = dinfo->bdrv;
s->rq = NULL;
- if (strlen(ps = (char *)drive_get_serial(s->bs)))
+ if (strlen(ps))
strncpy(s->serial_str, ps, sizeof(s->serial_str));
else
snprintf(s->serial_str, sizeof(s->serial_str), "0");
diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h
index 1be434270..23ad74cae 100644
--- a/hw/virtio-blk.h
+++ b/hw/virtio-blk.h
@@ -31,6 +31,7 @@
#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/
#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
#define VIRTIO_BLK_F_IDENTIFY 8 /* ATA IDENTIFY supported */
+#define VIRTIO_BLK_F_WCACHE 9 /* write cache enabled */
#define VIRTIO_BLK_ID_LEN 256 /* length of identify u16 array */
#define VIRTIO_BLK_ID_SN 10 /* start of char * serial# */
@@ -55,6 +56,9 @@ struct virtio_blk_config
/* This bit says it's a scsi command, not an actual read or write. */
#define VIRTIO_BLK_T_SCSI_CMD 2
+/* Flush the volatile write cache */
+#define VIRTIO_BLK_T_FLUSH 4
+
/* Barrier before this op. */
#define VIRTIO_BLK_T_BARRIER 0x80000000
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index f812ab7a6..f7a51ff76 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -364,8 +364,17 @@ static void virtio_map(PCIDevice *pci_dev, int region_num,
static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
uint32_t val, int len)
{
+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+ if (PCI_COMMAND == address) {
+ if (!(val & PCI_COMMAND_MASTER)) {
+ proxy->vdev->status &= !VIRTIO_CONFIG_S_DRIVER_OK;
+ }
+ }
+
pci_default_write_config(pci_dev, address, val, len);
- msix_write_config(pci_dev, address, val, len);
+ if(proxy->vdev->nvectors)
+ msix_write_config(pci_dev, address, val, len);
}
static const VirtIOBindings virtio_pci_bindings = {
@@ -407,11 +416,12 @@ static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
msix_bar_size(&proxy->pci_dev),
PCI_ADDRESS_SPACE_MEM,
msix_mmio_map);
- proxy->pci_dev.config_write = virtio_write_config;
proxy->pci_dev.unregister = msix_uninit;
} else
vdev->nvectors = 0;
+ proxy->pci_dev.config_write = virtio_write_config;
+
size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + vdev->config_len;
if (size & (size-1))
size = 1 << qemu_fls(size);
diff --git a/hw/virtio.c b/hw/virtio.c
index 41e7ca2c1..337ff27ba 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -694,6 +694,7 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
size_t config_size, size_t struct_size)
{
VirtIODevice *vdev;
+ int i;
vdev = qemu_mallocz(struct_size);
@@ -703,6 +704,8 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
vdev->queue_sel = 0;
vdev->config_vector = VIRTIO_NO_VECTOR;
vdev->vq = qemu_mallocz(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
+ for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++)
+ vdev->vq[i].vector = VIRTIO_NO_VECTOR;
vdev->name = name;
vdev->config_len = config_size;
diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
index 6927d43c9..fc038c8e3 100644
--- a/hw/wdt_i6300esb.c
+++ b/hw/wdt_i6300esb.c
@@ -198,7 +198,7 @@ static void i6300esb_timer_expired(void *vp)
static void i6300esb_config_write(PCIDevice *dev, uint32_t addr,
uint32_t data, int len)
{
- I6300State *d = container_of(dev, I6300State, dev);
+ I6300State *d = DO_UPCAST(I6300State, dev, dev);
int old;
i6300esb_debug("addr = %x, data = %x, len = %d\n", addr, data, len);
@@ -226,7 +226,7 @@ static void i6300esb_config_write(PCIDevice *dev, uint32_t addr,
static uint32_t i6300esb_config_read(PCIDevice *dev, uint32_t addr, int len)
{
- I6300State *d = container_of(dev, I6300State, dev);
+ I6300State *d = DO_UPCAST(I6300State, dev, dev);
uint32_t data;
i6300esb_debug ("addr = %x, len = %d\n", addr, len);
@@ -360,7 +360,7 @@ static void i6300esb_map(PCIDevice *dev, int region_num,
i6300esb_mem_writew,
i6300esb_mem_writel,
};
- I6300State *d = container_of(dev, I6300State, dev);
+ I6300State *d = DO_UPCAST(I6300State, dev, dev);
int io_mem;
i6300esb_debug("addr = %x, size = %x, type = %d\n", addr, size, type);
@@ -415,7 +415,7 @@ static int i6300esb_load(QEMUFile *f, void *vp, int version)
static int i6300esb_init(PCIDevice *dev)
{
- I6300State *d = container_of(dev, I6300State, dev);
+ I6300State *d = DO_UPCAST(I6300State, dev, dev);
uint8_t *pci_conf;
d->reboot_enabled = 1;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 25b95ea05..b42567c3d 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -3685,8 +3685,10 @@ static int target_to_host_fcntl_cmd(int cmd)
return F_SETLEASE;
case TARGET_F_GETLEASE:
return F_GETLEASE;
+#ifdef F_DUPFD_CLOEXEC
case TARGET_F_DUPFD_CLOEXEC:
return F_DUPFD_CLOEXEC;
+#endif
case TARGET_F_NOTIFY:
return F_NOTIFY;
default:
diff --git a/monitor.c b/monitor.c
index 067f78402..6e69fd4c4 100644
--- a/monitor.c
+++ b/monitor.c
@@ -88,6 +88,8 @@ struct mon_fd_t {
struct Monitor {
CharDriverState *chr;
+ int mux_out;
+ int reset_seen;
int flags;
int suspend_cnt;
uint8_t outbuf[1024];
@@ -132,7 +134,7 @@ static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
void monitor_flush(Monitor *mon)
{
- if (mon && mon->outbuf_index != 0 && mon->chr->focus == 0) {
+ if (mon && mon->outbuf_index != 0 && !mon->mux_out) {
qemu_chr_write(mon->chr, mon->outbuf, mon->outbuf_index);
mon->outbuf_index = 0;
}
@@ -3135,23 +3137,36 @@ static void monitor_event(void *opaque, int event)
switch (event) {
case CHR_EVENT_MUX_IN:
- readline_restart(mon->rs);
- monitor_resume(mon);
- monitor_flush(mon);
+ mon->mux_out = 0;
+ if (mon->reset_seen) {
+ readline_restart(mon->rs);
+ monitor_resume(mon);
+ monitor_flush(mon);
+ } else {
+ mon->suspend_cnt = 0;
+ }
break;
case CHR_EVENT_MUX_OUT:
- if (mon->suspend_cnt == 0)
- monitor_printf(mon, "\n");
- monitor_flush(mon);
- monitor_suspend(mon);
+ if (mon->reset_seen) {
+ if (mon->suspend_cnt == 0) {
+ monitor_printf(mon, "\n");
+ }
+ monitor_flush(mon);
+ monitor_suspend(mon);
+ } else {
+ mon->suspend_cnt++;
+ }
+ mon->mux_out = 1;
break;
case CHR_EVENT_RESET:
monitor_printf(mon, "QEMU %s monitor - type 'help' for more "
"information\n", QEMU_VERSION);
- if (mon->chr->focus == 0)
+ if (!mon->mux_out) {
readline_show_prompt(mon->rs);
+ }
+ mon->reset_seen = 1;
break;
}
}
@@ -3179,8 +3194,6 @@ void monitor_init(CharDriverState *chr, int flags)
mon->chr = chr;
mon->flags = flags;
- if (mon->chr->focus != 0)
- mon->suspend_cnt = 1; /* mux'ed monitors start suspended */
if (flags & MONITOR_USE_READLINE) {
mon->rs = readline_init(mon, monitor_find_completion);
monitor_read_command(mon, 0);
diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc
index 76f3588d6..3941c0bf5 100644..100755
--- a/pc-bios/openbios-ppc
+++ b/pc-bios/openbios-ppc
Binary files differ
diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index fd9e71645..9320b3d79 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -135,6 +135,16 @@ static size_t handle_aiocb_ioctl(struct qemu_paiocb *aiocb)
return aiocb->aio_nbytes;
}
+static size_t handle_aiocb_flush(struct qemu_paiocb *aiocb)
+{
+ int ret;
+
+ ret = fdatasync(aiocb->aio_fildes);
+ if (ret == -1)
+ return -errno;
+ return 0;
+}
+
#ifdef CONFIG_PREADV
static ssize_t
@@ -331,6 +341,9 @@ static void *aio_thread(void *unused)
case QEMU_AIO_WRITE:
ret = handle_aiocb_rw(aiocb);
break;
+ case QEMU_AIO_FLUSH:
+ ret = handle_aiocb_flush(aiocb);
+ break;
case QEMU_AIO_IOCTL:
ret = handle_aiocb_ioctl(aiocb);
break;
@@ -531,8 +544,10 @@ BlockDriverAIOCB *paio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
acb->aio_type = type;
acb->aio_fildes = fd;
acb->ev_signo = SIGUSR2;
- acb->aio_iov = qiov->iov;
- acb->aio_niov = qiov->niov;
+ if (qiov) {
+ acb->aio_iov = qiov->iov;
+ acb->aio_niov = qiov->niov;
+ }
acb->aio_nbytes = nb_sectors * 512;
acb->aio_offset = sector_num * 512;
diff --git a/qemu-char.c b/qemu-char.c
index c25ed1c61..4f2961802 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -214,7 +214,7 @@ static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
return len;
}
-static CharDriverState *qemu_chr_open_null(void)
+static CharDriverState *qemu_chr_open_null(QemuOpts *opts)
{
CharDriverState *chr;
@@ -233,6 +233,7 @@ typedef struct {
IOEventHandler *chr_event[MAX_MUX];
void *ext_opaque[MAX_MUX];
CharDriverState *drv;
+ int focus;
int mux_cnt;
int term_got_escape;
int max_size;
@@ -361,11 +362,11 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
break;
case 'c':
/* Switch to the next registered device */
- mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_OUT);
- chr->focus++;
- if (chr->focus >= d->mux_cnt)
- chr->focus = 0;
- mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_IN);
+ mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
+ d->focus++;
+ if (d->focus >= d->mux_cnt)
+ d->focus = 0;
+ mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
break;
case 't':
d->timestamps = !d->timestamps;
@@ -384,8 +385,8 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
static void mux_chr_accept_input(CharDriverState *chr)
{
- int m = chr->focus;
MuxDriver *d = chr->opaque;
+ int m = d->focus;
while (d->prod[m] != d->cons[m] &&
d->chr_can_read[m] &&
@@ -399,7 +400,7 @@ static int mux_chr_can_read(void *opaque)
{
CharDriverState *chr = opaque;
MuxDriver *d = chr->opaque;
- int m = chr->focus;
+ int m = d->focus;
if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE)
return 1;
@@ -412,7 +413,7 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
{
CharDriverState *chr = opaque;
MuxDriver *d = chr->opaque;
- int m = chr->focus;
+ int m = d->focus;
int i;
mux_chr_accept_input (opaque);
@@ -456,8 +457,12 @@ static void mux_chr_update_read_handler(CharDriverState *chr)
qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,
mux_chr_event, chr);
}
- chr->focus = d->mux_cnt;
+ if (d->focus != -1) {
+ mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
+ }
+ d->focus = d->mux_cnt;
d->mux_cnt++;
+ mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
}
static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
@@ -470,7 +475,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
chr->opaque = d;
d->drv = drv;
- chr->focus = -1;
+ d->focus = -1;
chr->chr_write = mux_chr_write;
chr->chr_update_read_handler = mux_chr_update_read_handler;
chr->chr_accept_input = mux_chr_accept_input;
@@ -626,20 +631,27 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
return chr;
}
-static CharDriverState *qemu_chr_open_file_out(const char *file_out)
+static CharDriverState *qemu_chr_open_file_out(QemuOpts *opts)
{
int fd_out;
- TFR(fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
+ TFR(fd_out = open(qemu_opt_get(opts, "path"),
+ O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
if (fd_out < 0)
return NULL;
return qemu_chr_open_fd(-1, fd_out);
}
-static CharDriverState *qemu_chr_open_pipe(const char *filename)
+static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts)
{
int fd_in, fd_out;
char filename_in[256], filename_out[256];
+ const char *filename = qemu_opt_get(opts, "path");
+
+ if (filename == NULL) {
+ fprintf(stderr, "chardev: pipe: no filename given\n");
+ return NULL;
+ }
snprintf(filename_in, 256, "%s.in", filename);
snprintf(filename_out, 256, "%s.out", filename);
@@ -751,7 +763,7 @@ static void qemu_chr_close_stdio(struct CharDriverState *chr)
fd_chr_close(chr);
}
-static CharDriverState *qemu_chr_open_stdio(void)
+static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts)
{
CharDriverState *chr;
@@ -949,7 +961,7 @@ static void pty_chr_close(struct CharDriverState *chr)
qemu_chr_event(chr, CHR_EVENT_CLOSED);
}
-static CharDriverState *qemu_chr_open_pty(void)
+static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
{
CharDriverState *chr;
PtyCharDriver *s;
@@ -979,6 +991,7 @@ static CharDriverState *qemu_chr_open_pty(void)
len = strlen(q_ptsname(s->fd)) + 5;
chr->filename = qemu_malloc(len);
snprintf(chr->filename, len, "pty:%s", q_ptsname(s->fd));
+ qemu_opt_set(opts, "path", q_ptsname(s->fd));
fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd));
chr->opaque = s;
@@ -1138,8 +1151,9 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
return 0;
}
-static CharDriverState *qemu_chr_open_tty(const char *filename)
+static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
{
+ const char *filename = qemu_opt_get(opts, "path");
CharDriverState *chr;
int fd;
@@ -1271,8 +1285,9 @@ static void pp_close(CharDriverState *chr)
qemu_chr_event(chr, CHR_EVENT_CLOSED);
}
-static CharDriverState *qemu_chr_open_pp(const char *filename)
+static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
{
+ const char *filename = qemu_opt_get(opts, "path");
CharDriverState *chr;
ParallelCharDriver *drv;
int fd;
@@ -1340,8 +1355,9 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
return 0;
}
-static CharDriverState *qemu_chr_open_pp(const char *filename)
+static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
{
+ const char *filename = qemu_opt_get(opts, "path");
CharDriverState *chr;
int fd;
@@ -1559,8 +1575,9 @@ static int win_chr_poll(void *opaque)
return 0;
}
-static CharDriverState *qemu_chr_open_win(const char *filename)
+static CharDriverState *qemu_chr_open_win(QemuOpts *opts)
{
+ const char *filename = qemu_opt_get(opts, "path");
CharDriverState *chr;
WinCharState *s;
@@ -1658,8 +1675,9 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
}
-static CharDriverState *qemu_chr_open_win_pipe(const char *filename)
+static CharDriverState *qemu_chr_open_win_pipe(QemuOpts *opts)
{
+ const char *filename = qemu_opt_get(opts, "path");
CharDriverState *chr;
WinCharState *s;
@@ -1692,13 +1710,14 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
return chr;
}
-static CharDriverState *qemu_chr_open_win_con(const char *filename)
+static CharDriverState *qemu_chr_open_win_con(QemuOpts *opts)
{
return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE));
}
-static CharDriverState *qemu_chr_open_win_file_out(const char *file_out)
+static CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts)
{
+ const char *file_out = qemu_opt_get(opts, "path");
HANDLE fd_out;
fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
@@ -1715,7 +1734,6 @@ static CharDriverState *qemu_chr_open_win_file_out(const char *file_out)
typedef struct {
int fd;
- struct sockaddr_in daddr;
uint8_t buf[1024];
int bufcnt;
int bufptr;
@@ -1726,8 +1744,7 @@ static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
NetCharDriver *s = chr->opaque;
- return sendto(s->fd, (const void *)buf, len, 0,
- (struct sockaddr *)&s->daddr, sizeof(struct sockaddr_in));
+ return send(s->fd, (const void *)buf, len, 0);
}
static int udp_chr_read_poll(void *opaque)
@@ -1789,30 +1806,18 @@ static void udp_chr_close(CharDriverState *chr)
qemu_chr_event(chr, CHR_EVENT_CLOSED);
}
-static CharDriverState *qemu_chr_open_udp(const char *def)
+static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
{
CharDriverState *chr = NULL;
NetCharDriver *s = NULL;
int fd = -1;
- struct sockaddr_in saddr;
chr = qemu_mallocz(sizeof(CharDriverState));
s = qemu_mallocz(sizeof(NetCharDriver));
- fd = socket(PF_INET, SOCK_DGRAM, 0);
+ fd = inet_dgram_opts(opts);
if (fd < 0) {
- perror("socket(PF_INET, SOCK_DGRAM)");
- goto return_err;
- }
-
- if (parse_host_src_port(&s->daddr, &saddr, def) < 0) {
- printf("Could not parse: %s\n", def);
- goto return_err;
- }
-
- if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
- {
- perror("bind");
+ fprintf(stderr, "inet_dgram_opts failed\n");
goto return_err;
}
@@ -2107,67 +2112,39 @@ static void tcp_chr_close(CharDriverState *chr)
qemu_chr_event(chr, CHR_EVENT_CLOSED);
}
-static CharDriverState *qemu_chr_open_tcp(const char *host_str,
- int is_telnet,
- int is_unix)
+static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
{
CharDriverState *chr = NULL;
TCPCharDriver *s = NULL;
- int fd = -1, offset = 0;
- int is_listen = 0;
- int is_waitconnect = 1;
- int do_nodelay = 0;
- const char *ptr;
-
- ptr = host_str;
- while((ptr = strchr(ptr,','))) {
- ptr++;
- if (!strncmp(ptr,"server",6)) {
- is_listen = 1;
- } else if (!strncmp(ptr,"nowait",6)) {
- is_waitconnect = 0;
- } else if (!strncmp(ptr,"nodelay",6)) {
- do_nodelay = 1;
- } else if (!strncmp(ptr,"to=",3)) {
- /* nothing, inet_listen() parses this one */;
- } else if (!strncmp(ptr,"ipv4",4)) {
- /* nothing, inet_connect() and inet_listen() parse this one */;
- } else if (!strncmp(ptr,"ipv6",4)) {
- /* nothing, inet_connect() and inet_listen() parse this one */;
- } else {
- printf("Unknown option: %s\n", ptr);
- goto fail;
- }
- }
+ int fd = -1;
+ int is_listen;
+ int is_waitconnect;
+ int do_nodelay;
+ int is_unix;
+ int is_telnet;
+
+ is_listen = qemu_opt_get_bool(opts, "server", 0);
+ is_waitconnect = qemu_opt_get_bool(opts, "wait", 1);
+ is_telnet = qemu_opt_get_bool(opts, "telnet", 0);
+ do_nodelay = !qemu_opt_get_bool(opts, "delay", 1);
+ is_unix = qemu_opt_get(opts, "path") != NULL;
if (!is_listen)
is_waitconnect = 0;
chr = qemu_mallocz(sizeof(CharDriverState));
s = qemu_mallocz(sizeof(TCPCharDriver));
- if (is_listen) {
- chr->filename = qemu_malloc(256);
- if (is_unix) {
- pstrcpy(chr->filename, 256, "unix:");
- } else if (is_telnet) {
- pstrcpy(chr->filename, 256, "telnet:");
- } else {
- pstrcpy(chr->filename, 256, "tcp:");
- }
- offset = strlen(chr->filename);
- }
if (is_unix) {
if (is_listen) {
- fd = unix_listen(host_str, chr->filename + offset, 256 - offset);
+ fd = unix_listen_opts(opts);
} else {
- fd = unix_connect(host_str);
+ fd = unix_connect_opts(opts);
}
} else {
if (is_listen) {
- fd = inet_listen(host_str, chr->filename + offset, 256 - offset,
- SOCK_STREAM, 0);
+ fd = inet_listen_opts(opts, 0);
} else {
- fd = inet_connect(host_str, SOCK_STREAM);
+ fd = inet_connect_opts(opts);
}
}
if (fd < 0)
@@ -2193,6 +2170,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
if (is_telnet)
s->do_telnetopt = 1;
+
} else {
s->connected = 1;
s->fd = fd;
@@ -2200,14 +2178,30 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
tcp_chr_connect(chr);
}
+ /* for "info chardev" monitor command */
+ chr->filename = qemu_malloc(256);
+ if (is_unix) {
+ snprintf(chr->filename, 256, "unix:%s%s",
+ qemu_opt_get(opts, "path"),
+ qemu_opt_get_bool(opts, "server", 0) ? ",server" : "");
+ } else if (is_telnet) {
+ snprintf(chr->filename, 256, "telnet:%s:%s%s",
+ qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"),
+ qemu_opt_get_bool(opts, "server", 0) ? ",server" : "");
+ } else {
+ snprintf(chr->filename, 256, "tcp:%s:%s%s",
+ qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"),
+ qemu_opt_get_bool(opts, "server", 0) ? ",server" : "");
+ }
+
if (is_listen && is_waitconnect) {
printf("QEMU waiting for connection on: %s\n",
- chr->filename ? chr->filename : host_str);
+ chr->filename);
tcp_chr_accept(chr);
socket_set_nonblock(s->listen_fd);
}
-
return chr;
+
fail:
if (fd >= 0)
closesocket(fd);
@@ -2216,97 +2210,229 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
return NULL;
}
-CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s))
+static QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
{
+ char host[65], port[33], width[8], height[8];
+ int pos;
const char *p;
- CharDriverState *chr;
+ QemuOpts *opts;
+
+ opts = qemu_opts_create(&qemu_chardev_opts, label, 1);
+ if (NULL == opts)
+ return NULL;
- if (!strcmp(filename, "vc")) {
- chr = text_console_init(NULL);
- } else
- if (strstart(filename, "vc:", &p)) {
- chr = text_console_init(p);
- } else
- if (!strcmp(filename, "null")) {
- chr = qemu_chr_open_null();
- } else
- if (strstart(filename, "tcp:", &p)) {
- chr = qemu_chr_open_tcp(p, 0, 0);
- } else
- if (strstart(filename, "telnet:", &p)) {
- chr = qemu_chr_open_tcp(p, 1, 0);
- } else
- if (strstart(filename, "udp:", &p)) {
- chr = qemu_chr_open_udp(p);
- } else
if (strstart(filename, "mon:", &p)) {
- chr = qemu_chr_open(label, p, NULL);
- if (chr) {
- chr = qemu_chr_open_mux(chr);
- monitor_init(chr, MONITOR_USE_READLINE);
- } else {
- printf("Unable to open driver: %s\n", p);
+ filename = p;
+ qemu_opt_set(opts, "mux", "on");
+ }
+
+ if (strcmp(filename, "null") == 0 ||
+ strcmp(filename, "pty") == 0 ||
+ strcmp(filename, "msmouse") == 0 ||
+ strcmp(filename, "braille") == 0 ||
+ strcmp(filename, "stdio") == 0) {
+ qemu_opt_set(opts, "backend", filename);
+ return opts;
+ }
+ if (strstart(filename, "vc", &p)) {
+ qemu_opt_set(opts, "backend", "vc");
+ if (*p == ':') {
+ if (sscanf(p+1, "%8[0-9]x%8[0-9]", width, height) == 2) {
+ /* pixels */
+ qemu_opt_set(opts, "width", width);
+ qemu_opt_set(opts, "height", height);
+ } else if (sscanf(p+1, "%8[0-9]Cx%8[0-9]C", width, height) == 2) {
+ /* chars */
+ qemu_opt_set(opts, "cols", width);
+ qemu_opt_set(opts, "rows", height);
+ } else {
+ goto fail;
+ }
}
- } else if (!strcmp(filename, "msmouse")) {
- chr = qemu_chr_open_msmouse();
- } else
-#ifndef _WIN32
+ return opts;
+ }
+ if (strcmp(filename, "con:") == 0) {
+ qemu_opt_set(opts, "backend", "console");
+ return opts;
+ }
+ if (strstart(filename, "COM", NULL)) {
+ qemu_opt_set(opts, "backend", "serial");
+ qemu_opt_set(opts, "path", filename);
+ return opts;
+ }
+ if (strstart(filename, "file:", &p)) {
+ qemu_opt_set(opts, "backend", "file");
+ qemu_opt_set(opts, "path", p);
+ return opts;
+ }
+ if (strstart(filename, "pipe:", &p)) {
+ qemu_opt_set(opts, "backend", "pipe");
+ qemu_opt_set(opts, "path", p);
+ return opts;
+ }
+ if (strstart(filename, "tcp:", &p) ||
+ strstart(filename, "telnet:", &p)) {
+ if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
+ host[0] = 0;
+ if (sscanf(p, ":%32[^,]%n", port, &pos) < 1)
+ goto fail;
+ }
+ qemu_opt_set(opts, "backend", "socket");
+ qemu_opt_set(opts, "host", host);
+ qemu_opt_set(opts, "port", port);
+ if (p[pos] == ',') {
+ if (qemu_opts_do_parse(opts, p+pos+1, NULL) != 0)
+ goto fail;
+ }
+ if (strstart(filename, "telnet:", &p))
+ qemu_opt_set(opts, "telnet", "on");
+ return opts;
+ }
+ if (strstart(filename, "udp:", &p)) {
+ qemu_opt_set(opts, "backend", "udp");
+ if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) {
+ host[0] = 0;
+ if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) {
+ fprintf(stderr, "udp #1\n");
+ goto fail;
+ }
+ }
+ qemu_opt_set(opts, "host", host);
+ qemu_opt_set(opts, "port", port);
+ if (p[pos] == '@') {
+ p += pos + 1;
+ if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
+ host[0] = 0;
+ if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) {
+ fprintf(stderr, "udp #2\n");
+ goto fail;
+ }
+ }
+ qemu_opt_set(opts, "localaddr", host);
+ qemu_opt_set(opts, "localport", port);
+ }
+ return opts;
+ }
if (strstart(filename, "unix:", &p)) {
- chr = qemu_chr_open_tcp(p, 0, 1);
- } else if (strstart(filename, "file:", &p)) {
- chr = qemu_chr_open_file_out(p);
- } else if (strstart(filename, "pipe:", &p)) {
- chr = qemu_chr_open_pipe(p);
- } else if (!strcmp(filename, "pty")) {
- chr = qemu_chr_open_pty();
- } else if (!strcmp(filename, "stdio")) {
- chr = qemu_chr_open_stdio();
- } else
-#if defined(__linux__)
- if (strstart(filename, "/dev/parport", NULL)) {
- chr = qemu_chr_open_pp(filename);
- } else
-#elif defined(__FreeBSD__) || defined(__DragonFly__)
- if (strstart(filename, "/dev/ppi", NULL)) {
- chr = qemu_chr_open_pp(filename);
- } else
+ qemu_opt_set(opts, "backend", "socket");
+ if (qemu_opts_do_parse(opts, p, "path") != 0)
+ goto fail;
+ return opts;
+ }
+ if (strstart(filename, "/dev/parport", NULL) ||
+ strstart(filename, "/dev/ppi", NULL)) {
+ qemu_opt_set(opts, "backend", "parport");
+ qemu_opt_set(opts, "path", filename);
+ return opts;
+ }
+ if (strstart(filename, "/dev/", NULL)) {
+ qemu_opt_set(opts, "backend", "tty");
+ qemu_opt_set(opts, "path", filename);
+ return opts;
+ }
+
+fail:
+ fprintf(stderr, "%s: fail on \"%s\"\n", __FUNCTION__, filename);
+ qemu_opts_del(opts);
+ return NULL;
+}
+
+static const struct {
+ const char *name;
+ CharDriverState *(*open)(QemuOpts *opts);
+} backend_table[] = {
+ { .name = "null", .open = qemu_chr_open_null },
+ { .name = "socket", .open = qemu_chr_open_socket },
+ { .name = "udp", .open = qemu_chr_open_udp },
+ { .name = "msmouse", .open = qemu_chr_open_msmouse },
+ { .name = "vc", .open = text_console_init },
+#ifdef _WIN32
+ { .name = "file", .open = qemu_chr_open_win_file_out },
+ { .name = "pipe", .open = qemu_chr_open_win_pipe },
+ { .name = "console", .open = qemu_chr_open_win_con },
+ { .name = "serial", .open = qemu_chr_open_win },
+#else
+ { .name = "file", .open = qemu_chr_open_file_out },
+ { .name = "pipe", .open = qemu_chr_open_pipe },
+ { .name = "pty", .open = qemu_chr_open_pty },
+ { .name = "stdio", .open = qemu_chr_open_stdio },
+#endif
+#ifdef CONFIG_BRLAPI
+ { .name = "braille", .open = chr_baum_init },
#endif
#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
|| defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
- if (strstart(filename, "/dev/", NULL)) {
- chr = qemu_chr_open_tty(filename);
- } else
+ { .name = "tty", .open = qemu_chr_open_tty },
#endif
-#else /* !_WIN32 */
- if (strstart(filename, "COM", NULL)) {
- chr = qemu_chr_open_win(filename);
- } else
- if (strstart(filename, "pipe:", &p)) {
- chr = qemu_chr_open_win_pipe(p);
- } else
- if (strstart(filename, "con:", NULL)) {
- chr = qemu_chr_open_win_con(filename);
- } else
- if (strstart(filename, "file:", &p)) {
- chr = qemu_chr_open_win_file_out(p);
- } else
-#endif
-#ifdef CONFIG_BRLAPI
- if (!strcmp(filename, "braille")) {
- chr = chr_baum_init();
- } else
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
+ { .name = "parport", .open = qemu_chr_open_pp },
#endif
- {
- chr = NULL;
+};
+
+CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
+ void (*init)(struct CharDriverState *s))
+{
+ CharDriverState *chr;
+ int i;
+
+ if (qemu_opts_id(opts) == NULL) {
+ fprintf(stderr, "chardev: no id specified\n");
+ return NULL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(backend_table); i++) {
+ if (strcmp(backend_table[i].name, qemu_opt_get(opts, "backend")) == 0)
+ break;
+ }
+ if (i == ARRAY_SIZE(backend_table)) {
+ fprintf(stderr, "chardev: backend \"%s\" not found\n",
+ qemu_opt_get(opts, "backend"));
+ return NULL;
+ }
+
+ chr = backend_table[i].open(opts);
+ if (!chr) {
+ fprintf(stderr, "chardev: opening backend \"%s\" failed\n",
+ qemu_opt_get(opts, "backend"));
+ return NULL;
}
- if (chr) {
- if (!chr->filename)
- chr->filename = qemu_strdup(filename);
- chr->init = init;
- chr->label = qemu_strdup(label);
+ if (!chr->filename)
+ chr->filename = qemu_strdup(qemu_opt_get(opts, "backend"));
+ chr->init = init;
+ TAILQ_INSERT_TAIL(&chardevs, chr, next);
+
+ if (qemu_opt_get_bool(opts, "mux", 0)) {
+ CharDriverState *base = chr;
+ int len = strlen(qemu_opts_id(opts)) + 6;
+ base->label = qemu_malloc(len);
+ snprintf(base->label, len, "%s-base", qemu_opts_id(opts));
+ chr = qemu_chr_open_mux(base);
+ chr->filename = base->filename;
TAILQ_INSERT_TAIL(&chardevs, chr, next);
}
+ chr->label = qemu_strdup(qemu_opts_id(opts));
+ return chr;
+}
+
+CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s))
+{
+ const char *p;
+ CharDriverState *chr;
+ QemuOpts *opts;
+
+ if (strstart(filename, "chardev:", &p)) {
+ return qemu_chr_find(p);
+ }
+
+ opts = qemu_chr_parse_compat(label, filename);
+ if (!opts)
+ return NULL;
+
+ chr = qemu_chr_open_opts(opts, init);
+ if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
+ monitor_init(chr, MONITOR_USE_READLINE);
+ }
return chr;
}
@@ -2328,3 +2454,15 @@ void qemu_chr_info(Monitor *mon)
monitor_printf(mon, "%s: filename=%s\n", chr->label, chr->filename);
}
}
+
+CharDriverState *qemu_chr_find(const char *name)
+{
+ CharDriverState *chr;
+
+ TAILQ_FOREACH(chr, &chardevs, next) {
+ if (strcmp(chr->label, name) != 0)
+ continue;
+ return chr;
+ }
+ return NULL;
+}
diff --git a/qemu-char.h b/qemu-char.h
index df620bc7d..d12ab11a8 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -3,6 +3,8 @@
#include "qemu-common.h"
#include "sys-queue.h"
+#include "qemu-option.h"
+#include "qemu-config.h"
/* character device */
@@ -61,13 +63,14 @@ struct CharDriverState {
void (*chr_close)(struct CharDriverState *chr);
void (*chr_accept_input)(struct CharDriverState *chr);
void *opaque;
- int focus;
QEMUBH *bh;
char *label;
char *filename;
TAILQ_ENTRY(CharDriverState) next;
};
+CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
+ void (*init)(struct CharDriverState *s));
CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s));
void qemu_chr_close(CharDriverState *chr);
void qemu_chr_printf(CharDriverState *s, const char *fmt, ...);
@@ -86,6 +89,7 @@ void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len);
int qemu_chr_get_msgfd(CharDriverState *s);
void qemu_chr_accept_input(CharDriverState *s);
void qemu_chr_info(Monitor *mon);
+CharDriverState *qemu_chr_find(const char *name);
extern int term_escape_char;
diff --git a/qemu-common.h b/qemu-common.h
index c8fb315d2..875010bd9 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -114,6 +114,7 @@ int stristart(const char *str, const char *val, const char **ptr);
int qemu_strnlen(const char *s, int max_len);
time_t mktimegm(struct tm *tm);
int qemu_fls(int i);
+int qemu_fdatasync(int fd);
/* path.c */
void init_paths(const char *prefix);
@@ -231,6 +232,7 @@ typedef struct QEMUIOVector {
void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint);
void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov);
void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len);
+void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t size);
void qemu_iovec_destroy(QEMUIOVector *qiov);
void qemu_iovec_reset(QEMUIOVector *qiov);
void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf);
diff --git a/qemu-config.c b/qemu-config.c
index efea7f447..c7d6da936 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -79,6 +79,69 @@ QemuOptsList qemu_drive_opts = {
},
};
+QemuOptsList qemu_chardev_opts = {
+ .name = "chardev",
+ .head = TAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
+ .desc = {
+ {
+ .name = "backend",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "path",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "host",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "port",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "localaddr",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "localport",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "to",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "ipv4",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "ipv6",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "wait",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "server",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "delay",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "telnet",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "width",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "height",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "cols",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "rows",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "mux",
+ .type = QEMU_OPT_BOOL,
+ },
+ { /* end if list */ }
+ },
+};
+
QemuOptsList qemu_device_opts = {
.name = "device",
.head = TAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
@@ -94,6 +157,7 @@ QemuOptsList qemu_device_opts = {
static QemuOptsList *lists[] = {
&qemu_drive_opts,
+ &qemu_chardev_opts,
&qemu_device_opts,
NULL,
};
diff --git a/qemu-config.h b/qemu-config.h
index 08629deb9..13b0f1930 100644
--- a/qemu-config.h
+++ b/qemu-config.h
@@ -1,4 +1,10 @@
+#ifndef QEMU_CONFIG_H
+#define QEMU_CONFIG_H
+
extern QemuOptsList qemu_drive_opts;
+extern QemuOptsList qemu_chardev_opts;
extern QemuOptsList qemu_device_opts;
int qemu_set_option(const char *str);
+
+#endif /* QEMU_CONFIG_H */
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 2f566b6ce..99d7f0db5 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -199,6 +199,20 @@ QEMU uses YM3812 emulation by Tatsuyuki Satoh.
QEMU uses GUS emulation(GUSEMU32 @url{http://www.deinmeister.de/gusemu/})
by Tibor "TS" Sch├╝tz.
+Not that, by default, GUS shares IRQ(7) with parallel ports and so
+qemu must be told to not have parallel ports to have working GUS
+
+@example
+qemu dos.img -soundhw gus -parallel none
+@end example
+
+Alternatively:
+@example
+qemu dos.img -device gus,irq=5
+@end example
+
+Or some other unclaimed IRQ.
+
CS4231A is the chip used in Windows Sound System and GUSMAX products
@c man end
diff --git a/qemu-option.c b/qemu-option.c
index 0473605c1..0c2101e3e 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -709,23 +709,11 @@ int qemu_opts_print(QemuOpts *opts, void *dummy)
return 0;
}
-QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *firstname)
+int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname)
{
- char option[128], value[128], *id = NULL;
- QemuOpts *opts;
+ char option[128], value[128];
const char *p,*pe,*pc;
- if (strncmp(params, "id=", 3) == 0) {
- get_opt_value(value, sizeof(value), params+3);
- id = qemu_strdup(value);
- } else if ((p = strstr(params, ",id=")) != NULL) {
- get_opt_value(value, sizeof(value), p+4);
- id = qemu_strdup(value);
- }
- opts = qemu_opts_create(list, id, 1);
- if (opts == NULL)
- return NULL;
-
p = params;
for(;;) {
pe = strchr(p, '=');
@@ -739,7 +727,7 @@ QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *fi
} else {
/* option without value, probably a flag */
p = get_opt_name(option, sizeof(option), p, ',');
- if (strncmp(p, "no", 2) == 0) {
+ if (strncmp(option, "no", 2) == 0) {
memmove(option, option+2, strlen(option+2)+1);
pstrcpy(value, sizeof(value), "off");
} else {
@@ -758,8 +746,7 @@ QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *fi
if (strcmp(option, "id") != 0) {
/* store and parse */
if (-1 == qemu_opt_set(opts, option, value)) {
- qemu_opts_del(opts);
- return NULL;
+ return -1;
}
}
if (*p != ',') {
@@ -767,6 +754,31 @@ QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *fi
}
p++;
}
+ return 0;
+}
+
+QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *firstname)
+{
+ char value[128], *id = NULL;
+ const char *p;
+ QemuOpts *opts;
+
+ if (strncmp(params, "id=", 3) == 0) {
+ get_opt_value(value, sizeof(value), params+3);
+ id = qemu_strdup(value);
+ } else if ((p = strstr(params, ",id=")) != NULL) {
+ get_opt_value(value, sizeof(value), p+4);
+ id = qemu_strdup(value);
+ }
+ opts = qemu_opts_create(list, id, 1);
+ if (opts == NULL)
+ return NULL;
+
+ if (qemu_opts_do_parse(opts, params, firstname) != 0) {
+ qemu_opts_del(opts);
+ return NULL;
+ }
+
return opts;
}
diff --git a/qemu-option.h b/qemu-option.h
index 56c7eac07..9e52625cc 100644
--- a/qemu-option.h
+++ b/qemu-option.h
@@ -114,6 +114,7 @@ int qemu_opts_set(QemuOptsList *list, const char *id,
const char *name, const char *value);
const char *qemu_opts_id(QemuOpts *opts);
void qemu_opts_del(QemuOpts *opts);
+int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname);
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *firstname);
typedef int (*qemu_opts_loopfunc)(QemuOpts *opts, void *opaque);
diff --git a/qemu-options.hx b/qemu-options.hx
index f2e602ab4..2f4291dd7 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1196,6 +1196,8 @@ STEXI
@table @option
ETEXI
+DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, \
+ "-chardev spec create unconnected chardev\n")
DEF("serial", HAS_ARG, QEMU_OPTION_serial, \
"-serial dev redirect the serial port to char device 'dev'\n")
STEXI
diff --git a/qemu-sockets.c b/qemu-sockets.c
index bd49d29a4..b80279c86 100644
--- a/qemu-sockets.c
+++ b/qemu-sockets.c
@@ -29,6 +29,34 @@
static int sockets_debug = 0;
static const int on=1, off=0;
+/* used temporarely until all users are converted to QemuOpts */
+QemuOptsList dummy_opts = {
+ .name = "dummy",
+ .head = TAILQ_HEAD_INITIALIZER(dummy_opts.head),
+ .desc = {
+ {
+ .name = "path",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "host",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "port",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "to",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "ipv4",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "ipv6",
+ .type = QEMU_OPT_BOOL,
+ },
+ { /* end if list */ }
+ },
+};
+
static int inet_getport(struct addrinfo *e)
{
struct sockaddr_in *i4;
@@ -88,63 +116,31 @@ static void inet_print_addrinfo(const char *tag, struct addrinfo *res)
}
}
-int inet_listen(const char *str, char *ostr, int olen,
- int socktype, int port_offset)
+int inet_listen_opts(QemuOpts *opts, int port_offset)
{
struct addrinfo ai,*res,*e;
- char addr[64];
+ const char *addr;
char port[33];
char uaddr[INET6_ADDRSTRLEN+1];
char uport[33];
- const char *opts, *h;
- int slisten,rc,pos,to,try_next;
+ int slisten,rc,to,try_next;
memset(&ai,0, sizeof(ai));
ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
ai.ai_family = PF_UNSPEC;
- ai.ai_socktype = socktype;
+ ai.ai_socktype = SOCK_STREAM;
- /* parse address */
- if (str[0] == ':') {
- /* no host given */
- addr[0] = '\0';
- if (1 != sscanf(str,":%32[^,]%n",port,&pos)) {
- fprintf(stderr, "%s: portonly parse error (%s)\n",
- __FUNCTION__, str);
- return -1;
- }
- } else if (str[0] == '[') {
- /* IPv6 addr */
- if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) {
- fprintf(stderr, "%s: ipv6 parse error (%s)\n",
- __FUNCTION__, str);
- return -1;
- }
- ai.ai_family = PF_INET6;
- } else if (qemu_isdigit(str[0])) {
- /* IPv4 addr */
- if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {
- fprintf(stderr, "%s: ipv4 parse error (%s)\n",
- __FUNCTION__, str);
- return -1;
- }
- ai.ai_family = PF_INET;
- } else {
- /* hostname */
- if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {
- fprintf(stderr, "%s: hostname parse error (%s)\n",
- __FUNCTION__, str);
- return -1;
- }
+ if (qemu_opt_get(opts, "port") == NULL) {
+ fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__);
+ return -1;
}
+ pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port"));
+ addr = qemu_opt_get(opts, "host");
- /* parse options */
- opts = str + pos;
- h = strstr(opts, ",to=");
- to = h ? atoi(h+4) : 0;
- if (strstr(opts, ",ipv4"))
+ to = qemu_opt_get_number(opts, "to", 0);
+ if (qemu_opt_get_bool(opts, "ipv4", 0))
ai.ai_family = PF_INET;
- if (strstr(opts, ",ipv6"))
+ if (qemu_opt_get_bool(opts, "ipv6", 0))
ai.ai_family = PF_INET6;
/* lookup */
@@ -152,8 +148,8 @@ int inet_listen(const char *str, char *ostr, int olen,
snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
if (rc != 0) {
- fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__,
- addr, port, gai_strerror(rc));
+ fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
+ gai_strerror(rc));
return -1;
}
if (sockets_debug)
@@ -211,24 +207,20 @@ listen:
freeaddrinfo(res);
return -1;
}
- if (ostr) {
- if (e->ai_family == PF_INET6) {
- snprintf(ostr, olen, "[%s]:%d%s", uaddr,
- inet_getport(e) - port_offset, opts);
- } else {
- snprintf(ostr, olen, "%s:%d%s", uaddr,
- inet_getport(e) - port_offset, opts);
- }
- }
+ snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset);
+ qemu_opt_set(opts, "host", uaddr);
+ qemu_opt_set(opts, "port", uport);
+ qemu_opt_set(opts, "ipv6", (e->ai_family == PF_INET6) ? "on" : "off");
+ qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off");
freeaddrinfo(res);
return slisten;
}
-int inet_connect(const char *str, int socktype)
+int inet_connect_opts(QemuOpts *opts)
{
struct addrinfo ai,*res,*e;
- char addr[64];
- char port[33];
+ const char *addr;
+ const char *port;
char uaddr[INET6_ADDRSTRLEN+1];
char uport[33];
int sock,rc;
@@ -236,44 +228,24 @@ int inet_connect(const char *str, int socktype)
memset(&ai,0, sizeof(ai));
ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
ai.ai_family = PF_UNSPEC;
- ai.ai_socktype = socktype;
+ ai.ai_socktype = SOCK_STREAM;
- /* parse address */
- if (str[0] == '[') {
- /* IPv6 addr */
- if (2 != sscanf(str,"[%64[^]]]:%32[^,]",addr,port)) {
- fprintf(stderr, "%s: ipv6 parse error (%s)\n",
- __FUNCTION__, str);
- return -1;
- }
- ai.ai_family = PF_INET6;
- } else if (qemu_isdigit(str[0])) {
- /* IPv4 addr */
- if (2 != sscanf(str,"%64[0-9.]:%32[^,]",addr,port)) {
- fprintf(stderr, "%s: ipv4 parse error (%s)\n",
- __FUNCTION__, str);
- return -1;
- }
- ai.ai_family = PF_INET;
- } else {
- /* hostname */
- if (2 != sscanf(str,"%64[^:]:%32[^,]",addr,port)) {
- fprintf(stderr, "%s: hostname parse error (%s)\n",
- __FUNCTION__, str);
- return -1;
- }
+ addr = qemu_opt_get(opts, "host");
+ port = qemu_opt_get(opts, "port");
+ if (addr == NULL || port == NULL) {
+ fprintf(stderr, "inet_connect: host and/or port not specified\n");
+ return -1;
}
- /* parse options */
- if (strstr(str, ",ipv4"))
+ if (qemu_opt_get_bool(opts, "ipv4", 0))
ai.ai_family = PF_INET;
- if (strstr(str, ",ipv6"))
+ if (qemu_opt_get_bool(opts, "ipv6", 0))
ai.ai_family = PF_INET6;
/* lookup */
if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) {
- fprintf(stderr,"getaddrinfo(%s,%s): %s\n", gai_strerror(rc),
- addr, port);
+ fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
+ gai_strerror(rc));
return -1;
}
if (sockets_debug)
@@ -314,13 +286,224 @@ int inet_connect(const char *str, int socktype)
return -1;
}
+int inet_dgram_opts(QemuOpts *opts)
+{
+ struct addrinfo ai, *peer = NULL, *local = NULL;
+ const char *addr;
+ const char *port;
+ char uaddr[INET6_ADDRSTRLEN+1];
+ char uport[33];
+ int sock = -1, rc;
+
+ /* lookup peer addr */
+ memset(&ai,0, sizeof(ai));
+ ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
+ ai.ai_family = PF_UNSPEC;
+ ai.ai_socktype = SOCK_DGRAM;
+
+ addr = qemu_opt_get(opts, "host");
+ port = qemu_opt_get(opts, "port");
+ if (addr == NULL || strlen(addr) == 0) {
+ addr = "localhost";
+ }
+ if (port == NULL || strlen(port) == 0) {
+ fprintf(stderr, "inet_dgram: port not specified\n");
+ return -1;
+ }
+
+ if (qemu_opt_get_bool(opts, "ipv4", 0))
+ ai.ai_family = PF_INET;
+ if (qemu_opt_get_bool(opts, "ipv6", 0))
+ ai.ai_family = PF_INET6;
+
+ if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) {
+ fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
+ gai_strerror(rc));
+ return -1;
+ }
+ if (sockets_debug) {
+ fprintf(stderr, "%s: peer (%s:%s)\n", __FUNCTION__, addr, port);
+ inet_print_addrinfo(__FUNCTION__, peer);
+ }
+
+ /* lookup local addr */
+ memset(&ai,0, sizeof(ai));
+ ai.ai_flags = AI_PASSIVE;
+ ai.ai_family = peer->ai_family;
+ ai.ai_socktype = SOCK_DGRAM;
+
+ addr = qemu_opt_get(opts, "localaddr");
+ port = qemu_opt_get(opts, "localport");
+ if (addr == NULL || strlen(addr) == 0) {
+ addr = NULL;
+ }
+ if (!port || strlen(port) == 0)
+ port = "0";
+
+ if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) {
+ fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
+ gai_strerror(rc));
+ return -1;
+ }
+ if (sockets_debug) {
+ fprintf(stderr, "%s: local (%s:%s)\n", __FUNCTION__, addr, port);
+ inet_print_addrinfo(__FUNCTION__, local);
+ }
+
+ /* create socket */
+ sock = socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol);
+ if (sock < 0) {
+ fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
+ inet_strfamily(peer->ai_family), strerror(errno));
+ goto err;
+ }
+ setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
+
+ /* bind socket */
+ if (getnameinfo((struct sockaddr*)local->ai_addr,local->ai_addrlen,
+ uaddr,INET6_ADDRSTRLEN,uport,32,
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
+ fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__);
+ goto err;
+ }
+ if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) {
+ fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
+ inet_strfamily(local->ai_family), uaddr, inet_getport(local));
+ goto err;
+ }
+
+ /* connect to peer */
+ if (getnameinfo((struct sockaddr*)peer->ai_addr, peer->ai_addrlen,
+ uaddr, INET6_ADDRSTRLEN, uport, 32,
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
+ fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__);
+ goto err;
+ }
+ if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) {
+ fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
+ inet_strfamily(peer->ai_family),
+ peer->ai_canonname, uaddr, uport, strerror(errno));
+ goto err;
+ }
+
+ freeaddrinfo(local);
+ freeaddrinfo(peer);
+ return sock;
+
+err:
+ if (-1 != sock)
+ closesocket(sock);
+ if (local)
+ freeaddrinfo(local);
+ if (peer)
+ freeaddrinfo(peer);
+ return -1;
+}
+
+/* compatibility wrapper */
+static int inet_parse(QemuOpts *opts, const char *str)
+{
+ const char *optstr, *h;
+ char addr[64];
+ char port[33];
+ int pos;
+
+ /* parse address */
+ if (str[0] == ':') {
+ /* no host given */
+ addr[0] = '\0';
+ if (1 != sscanf(str,":%32[^,]%n",port,&pos)) {
+ fprintf(stderr, "%s: portonly parse error (%s)\n",
+ __FUNCTION__, str);
+ return -1;
+ }
+ } else if (str[0] == '[') {
+ /* IPv6 addr */
+ if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) {
+ fprintf(stderr, "%s: ipv6 parse error (%s)\n",
+ __FUNCTION__, str);
+ return -1;
+ }
+ qemu_opt_set(opts, "ipv6", "yes");
+ } else if (qemu_isdigit(str[0])) {
+ /* IPv4 addr */
+ if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {
+ fprintf(stderr, "%s: ipv4 parse error (%s)\n",
+ __FUNCTION__, str);
+ return -1;
+ }
+ qemu_opt_set(opts, "ipv4", "yes");
+ } else {
+ /* hostname */
+ if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {
+ fprintf(stderr, "%s: hostname parse error (%s)\n",
+ __FUNCTION__, str);
+ return -1;
+ }
+ }
+ qemu_opt_set(opts, "host", addr);
+ qemu_opt_set(opts, "port", port);
+
+ /* parse options */
+ optstr = str + pos;
+ h = strstr(optstr, ",to=");
+ if (h)
+ qemu_opt_set(opts, "to", h+4);
+ if (strstr(optstr, ",ipv4"))
+ qemu_opt_set(opts, "ipv4", "yes");
+ if (strstr(optstr, ",ipv6"))
+ qemu_opt_set(opts, "ipv6", "yes");
+ return 0;
+}
+
+int inet_listen(const char *str, char *ostr, int olen,
+ int socktype, int port_offset)
+{
+ QemuOpts *opts;
+ char *optstr;
+ int sock = -1;
+
+ opts = qemu_opts_create(&dummy_opts, NULL, 0);
+ if (inet_parse(opts, str) == 0) {
+ sock = inet_listen_opts(opts, port_offset);
+ if (sock != -1 && ostr) {
+ optstr = strchr(str, ',');
+ if (qemu_opt_get_bool(opts, "ipv6", 0)) {
+ snprintf(ostr, olen, "[%s]:%s%s",
+ qemu_opt_get(opts, "host"),
+ qemu_opt_get(opts, "port"),
+ optstr ? optstr : "");
+ } else {
+ snprintf(ostr, olen, "%s:%s%s",
+ qemu_opt_get(opts, "host"),
+ qemu_opt_get(opts, "port"),
+ optstr ? optstr : "");
+ }
+ }
+ }
+ qemu_opts_del(opts);
+ return sock;
+}
+
+int inet_connect(const char *str, int socktype)
+{
+ QemuOpts *opts;
+ int sock = -1;
+
+ opts = qemu_opts_create(&dummy_opts, NULL, 0);
+ if (inet_parse(opts, str) == 0)
+ sock = inet_connect_opts(opts);
+ qemu_opts_del(opts);
+ return sock;
+}
+
#ifndef _WIN32
-int unix_listen(const char *str, char *ostr, int olen)
+int unix_listen_opts(QemuOpts *opts)
{
struct sockaddr_un un;
- char *path, *opts;
- int sock, fd, len;
+ const char *path = qemu_opt_get(opts, "path");
+ int sock, fd;
sock = socket(PF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
@@ -328,14 +511,6 @@ int unix_listen(const char *str, char *ostr, int olen)
return -1;
}
- opts = strchr(str, ',');
- if (opts) {
- len = opts - str;
- path = qemu_malloc(len+1);
- snprintf(path, len+1, "%.*s", len, str);
- } else
- path = qemu_strdup(str);
-
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
if (path && strlen(path)) {
@@ -352,8 +527,8 @@ int unix_listen(const char *str, char *ostr, int olen)
* worst case possible is bind() failing, i.e. a DoS attack.
*/
fd = mkstemp(un.sun_path); close(fd);
+ qemu_opt_set(opts, "path", un.sun_path);
}
- snprintf(ostr, olen, "%s%s", un.sun_path, opts ? opts : "");
unlink(un.sun_path);
if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
@@ -367,20 +542,24 @@ int unix_listen(const char *str, char *ostr, int olen)
if (sockets_debug)
fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path);
- qemu_free(path);
return sock;
err:
- qemu_free(path);
closesocket(sock);
return -1;
}
-int unix_connect(const char *path)
+int unix_connect_opts(QemuOpts *opts)
{
struct sockaddr_un un;
+ const char *path = qemu_opt_get(opts, "path");
int sock;
+ if (NULL == path) {
+ fprintf(stderr, "unix connect: no path specified\n");
+ return -1;
+ }
+
sock = socket(PF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket(unix)");
@@ -400,8 +579,62 @@ int unix_connect(const char *path)
return sock;
}
+/* compatibility wrapper */
+int unix_listen(const char *str, char *ostr, int olen)
+{
+ QemuOpts *opts;
+ char *path, *optstr;
+ int sock, len;
+
+ opts = qemu_opts_create(&dummy_opts, NULL, 0);
+
+ optstr = strchr(str, ',');
+ if (optstr) {
+ len = optstr - str;
+ if (len) {
+ path = qemu_malloc(len+1);
+ snprintf(path, len+1, "%.*s", len, str);
+ qemu_opt_set(opts, "path", path);
+ qemu_free(path);
+ }
+ } else {
+ qemu_opt_set(opts, "path", str);
+ }
+
+ sock = unix_listen_opts(opts);
+
+ if (sock != -1 && ostr)
+ snprintf(ostr, olen, "%s%s", qemu_opt_get(opts, "path"), optstr ? optstr : "");
+ qemu_opts_del(opts);
+ return sock;
+}
+
+int unix_connect(const char *path)
+{
+ QemuOpts *opts;
+ int sock;
+
+ opts = qemu_opts_create(&dummy_opts, NULL, 0);
+ qemu_opt_set(opts, "path", path);
+ sock = unix_connect_opts(opts);
+ qemu_opts_del(opts);
+ return sock;
+}
+
#else
+int unix_listen_opts(QemuOpts *opts)
+{
+ fprintf(stderr, "unix sockets are not available on windows\n");
+ return -1;
+}
+
+int unix_connect_opts(QemuOpts *opts)
+{
+ fprintf(stderr, "unix sockets are not available on windows\n");
+ return -1;
+}
+
int unix_listen(const char *path, char *ostr, int olen)
{
fprintf(stderr, "unix sockets are not available on windows\n");
diff --git a/qemu_socket.h b/qemu_socket.h
index fc5b5889b..c253b3241 100644
--- a/qemu_socket.h
+++ b/qemu_socket.h
@@ -29,16 +29,23 @@ int inet_aton(const char *cp, struct in_addr *ia);
#endif /* !_WIN32 */
+#include "qemu-option.h"
+
/* misc helpers */
void socket_set_nonblock(int fd);
int send_all(int fd, const void *buf, int len1);
/* New, ipv6-ready socket helper functions, see qemu-sockets.c */
+int inet_listen_opts(QemuOpts *opts, int port_offset);
int inet_listen(const char *str, char *ostr, int olen,
int socktype, int port_offset);
+int inet_connect_opts(QemuOpts *opts);
int inet_connect(const char *str, int socktype);
+int inet_dgram_opts(QemuOpts *opts);
+int unix_listen_opts(QemuOpts *opts);
int unix_listen(const char *path, char *ostr, int olen);
+int unix_connect_opts(QemuOpts *opts);
int unix_connect(const char *path);
/* Old, ipv4 only bits. Don't use for new code. */
diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c
index 89dbc0c0e..ee4f62313 100644
--- a/target-microblaze/op_helper.c
+++ b/target-microblaze/op_helper.c
@@ -209,17 +209,18 @@ uint32_t helper_pcmpbf(uint32_t a, uint32_t b)
void helper_memalign(uint32_t addr, uint32_t dr, uint32_t wr, uint32_t mask)
{
if (addr & mask) {
- qemu_log("unaligned access addr=%x mask=%x, wr=%d\n",
- addr, mask, wr);
- if (!(env->sregs[SR_MSR] & MSR_EE)) {
- return;
- }
-
+ qemu_log_mask(CPU_LOG_INT,
+ "unaligned access addr=%x mask=%x, wr=%d dr=r%d\n",
+ addr, mask, wr, dr);
+ env->sregs[SR_EAR] = addr;
env->sregs[SR_ESR] = ESR_EC_UNALIGNED_DATA | (wr << 10) \
| (dr & 31) << 5;
if (mask == 3) {
env->sregs[SR_ESR] |= 1 << 11;
}
+ if (!(env->sregs[SR_MSR] & MSR_EE)) {
+ return;
+ }
helper_raise_exception(EXCP_HW_EXCP);
}
}
@@ -245,19 +246,20 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
generated code */
saved_env = env;
env = cpu_single_env;
- qemu_log("Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n",
+ qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n",
addr, is_write, is_exec);
if (!(env->sregs[SR_MSR] & MSR_EE)) {
return;
}
+ env->sregs[SR_EAR] = addr;
if (is_exec) {
- if (!(env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) {
+ if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) {
env->sregs[SR_ESR] = ESR_EC_INSN_BUS;
helper_raise_exception(EXCP_HW_EXCP);
}
} else {
- if (!(env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) {
+ if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) {
env->sregs[SR_ESR] = ESR_EC_DATA_BUS;
helper_raise_exception(EXCP_HW_EXCP);
}
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index bb37f04ed..fe53b2e14 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -232,7 +232,7 @@ static void dec_pattern(DisasContext *dc)
int l1;
if ((dc->tb_flags & MSR_EE_FLAG)
- && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+ && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
&& !((dc->env->pvr.regs[2] & PVR2_USE_PCMP_INSTR))) {
tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
t_gen_raise_exception(dc, EXCP_HW_EXCP);
@@ -553,7 +553,7 @@ static void dec_mul(DisasContext *dc)
unsigned int subcode;
if ((dc->tb_flags & MSR_EE_FLAG)
- && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+ && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
&& !(dc->env->pvr.regs[0] & PVR0_USE_HW_MUL_MASK)) {
tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
t_gen_raise_exception(dc, EXCP_HW_EXCP);
@@ -610,7 +610,7 @@ static void dec_div(DisasContext *dc)
u = dc->imm & 2;
LOG_DIS("div\n");
- if (!(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+ if ((dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
&& !((dc->env->pvr.regs[0] & PVR0_USE_DIV_MASK))) {
tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
t_gen_raise_exception(dc, EXCP_HW_EXCP);
@@ -630,7 +630,7 @@ static void dec_barrel(DisasContext *dc)
unsigned int s, t;
if ((dc->tb_flags & MSR_EE_FLAG)
- && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+ && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
&& !(dc->env->pvr.regs[0] & PVR0_USE_BARREL_MASK)) {
tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
t_gen_raise_exception(dc, EXCP_HW_EXCP);
@@ -804,7 +804,7 @@ static void dec_load(DisasContext *dc)
size = 1 << (dc->opcode & 3);
if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
- && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
+ && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
t_gen_raise_exception(dc, EXCP_HW_EXCP);
return;
@@ -819,14 +819,28 @@ static void dec_load(DisasContext *dc)
/* Verify alignment if needed. */
if ((dc->env->pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
+ TCGv v = tcg_temp_new();
+
+ /*
+ * Microblaze gives MMU faults priority over faults due to
+ * unaligned addresses. That's why we speculatively do the load
+ * into v. If the load succeeds, we verify alignment of the
+ * address and if that succeeds we write into the destination reg.
+ */
+ gen_load(dc, v, *addr, size);
+
+ tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
gen_helper_memalign(*addr, tcg_const_tl(dc->rd),
tcg_const_tl(0), tcg_const_tl(size - 1));
- }
-
- if (dc->rd) {
- gen_load(dc, cpu_R[dc->rd], *addr, size);
+ if (dc->rd)
+ tcg_gen_mov_tl(cpu_R[dc->rd], v);
+ tcg_temp_free(v);
} else {
- gen_load(dc, env_imm, *addr, size);
+ if (dc->rd) {
+ gen_load(dc, cpu_R[dc->rd], *addr, size);
+ } else {
+ gen_load(dc, env_imm, *addr, size);
+ }
}
if (addr == &t)
@@ -856,7 +870,7 @@ static void dec_store(DisasContext *dc)
size = 1 << (dc->opcode & 3);
if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
- && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
+ && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
t_gen_raise_exception(dc, EXCP_HW_EXCP);
return;
@@ -868,13 +882,18 @@ static void dec_store(DisasContext *dc)
sync_jmpstate(dc);
addr = compute_ldst_addr(dc, &t);
+ gen_store(dc, *addr, cpu_R[dc->rd], size);
+
/* Verify alignment if needed. */
if ((dc->env->pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
+ tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
+ /* FIXME: if the alignment is wrong, we should restore the value
+ * in memory.
+ */
gen_helper_memalign(*addr, tcg_const_tl(dc->rd),
tcg_const_tl(1), tcg_const_tl(size - 1));
}
- gen_store(dc, *addr, cpu_R[dc->rd], size);
if (addr == &t)
tcg_temp_free(t);
}
@@ -1112,9 +1131,9 @@ static void dec_rts(DisasContext *dc)
static void dec_fpu(DisasContext *dc)
{
if ((dc->tb_flags & MSR_EE_FLAG)
- && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+ && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
&& !((dc->env->pvr.regs[2] & PVR2_USE_FPU_MASK))) {
- tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
+ tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_FPU);
t_gen_raise_exception(dc, EXCP_HW_EXCP);
return;
}
@@ -1125,6 +1144,12 @@ static void dec_fpu(DisasContext *dc)
static void dec_null(DisasContext *dc)
{
+ if ((dc->tb_flags & MSR_EE_FLAG)
+ && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
+ tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
+ t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ return;
+ }
qemu_log ("unknown insn pc=%x opc=%x\n", dc->pc, dc->opcode);
dc->abort_at_next_insn = 1;
}
@@ -1171,8 +1196,8 @@ static inline void decode(DisasContext *dc)
dc->nr_nops = 0;
else {
if ((dc->tb_flags & MSR_EE_FLAG)
- && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
- && !(dc->env->pvr.regs[2] & PVR2_OPCODE_0x0_ILL_MASK)) {
+ && (dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
+ && (dc->env->pvr.regs[2] & PVR2_OPCODE_0x0_ILL_MASK)) {
tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
t_gen_raise_exception(dc, EXCP_HW_EXCP);
return;
diff --git a/tcg/x86_64/tcg-target.c b/tcg/x86_64/tcg-target.c
index 9facb01e4..9709430c6 100644
--- a/tcg/x86_64/tcg-target.c
+++ b/tcg/x86_64/tcg-target.c
@@ -363,6 +363,20 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type,
}
}
+static void tcg_out_goto(TCGContext *s, int call, uint8_t *target)
+{
+ int32_t disp;
+
+ disp = target - s->code_ptr - 5;
+ if (disp == (target - s->code_ptr - 5)) {
+ tcg_out8(s, call ? 0xe8 : 0xe9);
+ tcg_out32(s, disp);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R10, (tcg_target_long) target);
+ tcg_out_modrm(s, 0xff, call ? 2 : 4, TCG_REG_R10);
+ }
+}
+
static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
int arg1, tcg_target_long arg2)
{
@@ -559,9 +573,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
/* XXX: move that code at the end of the TB */
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RSI, mem_index);
- tcg_out8(s, 0xe8);
- tcg_out32(s, (tcg_target_long)qemu_ld_helpers[s_bits] -
- (tcg_target_long)s->code_ptr - 4);
+ tcg_out_goto(s, 1, qemu_ld_helpers[s_bits]);
switch(opc) {
case 0 | 4:
@@ -774,9 +786,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
break;
}
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index);
- tcg_out8(s, 0xe8);
- tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] -
- (tcg_target_long)s->code_ptr - 4);
+ tcg_out_goto(s, 1, qemu_st_helpers[s_bits]);
/* jmp label2 */
tcg_out8(s, 0xeb);
@@ -865,8 +875,7 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
switch(opc) {
case INDEX_op_exit_tb:
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RAX, args[0]);
- tcg_out8(s, 0xe9); /* jmp tb_ret_addr */
- tcg_out32(s, tb_ret_addr - s->code_ptr - 4);
+ tcg_out_goto(s, 0, tb_ret_addr);
break;
case INDEX_op_goto_tb:
if (s->tb_jmp_offset) {
@@ -885,16 +894,14 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
break;
case INDEX_op_call:
if (const_args[0]) {
- tcg_out8(s, 0xe8);
- tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4);
+ tcg_out_goto(s, 1, (void *) args[0]);
} else {
tcg_out_modrm(s, 0xff, 2, args[0]);
}
break;
case INDEX_op_jmp:
if (const_args[0]) {
- tcg_out8(s, 0xe9);
- tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4);
+ tcg_out_goto(s, 0, (void *) args[0]);
} else {
tcg_out_modrm(s, 0xff, 4, args[0]);
}
diff --git a/usb-linux.c b/usb-linux.c
index 01d145d17..c80499af9 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -115,7 +115,7 @@ struct ctrl_struct {
uint16_t offset;
uint8_t state;
struct usb_ctrlrequest req;
- uint8_t buffer[1024];
+ uint8_t buffer[2048];
};
typedef struct USBHostDevice {
@@ -552,6 +552,7 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
struct usbdevfs_urb *urb;
AsyncURB *aurb;
int ret, value, index;
+ int buffer_len;
/*
* Process certain standard device requests.
@@ -580,6 +581,13 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
/* The rest are asynchronous */
+ buffer_len = 8 + s->ctrl.len;
+ if (buffer_len > sizeof(s->ctrl.buffer)) {
+ fprintf(stderr, "husb: ctrl buffer too small (%u > %lu)\n",
+ buffer_len, sizeof(s->ctrl.buffer));
+ return USB_RET_STALL;
+ }
+
aurb = async_alloc();
aurb->hdev = s;
aurb->packet = p;
@@ -596,7 +604,7 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
urb->endpoint = p->devep;
urb->buffer = &s->ctrl.req;
- urb->buffer_length = 8 + s->ctrl.len;
+ urb->buffer_length = buffer_len;
urb->usercontext = s;
diff --git a/vl.c b/vl.c
index 4d186e5e2..45824f6ef 100644
--- a/vl.c
+++ b/vl.c
@@ -2817,47 +2817,6 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
/***********************************************************/
/* ram save/restore */
-static int ram_get_page(QEMUFile *f, uint8_t *buf, int len)
-{
- int v;
-
- v = qemu_get_byte(f);
- switch(v) {
- case 0:
- if (qemu_get_buffer(f, buf, len) != len)
- return -EIO;
- break;
- case 1:
- v = qemu_get_byte(f);
- memset(buf, v, len);
- break;
- default:
- return -EINVAL;
- }
-
- if (qemu_file_has_error(f))
- return -EIO;
-
- return 0;
-}
-
-static int ram_load_v1(QEMUFile *f, void *opaque)
-{
- int ret;
- ram_addr_t i;
-
- if (qemu_get_be32(f) != last_ram_offset)
- return -EINVAL;
- for(i = 0; i < last_ram_offset; i+= TARGET_PAGE_SIZE) {
- if (kvm_enabled() && (i>=0xa0000) && (i<0xc0000)) /* do not access video-addresses */
- continue;
- ret = ram_get_page(f, qemu_get_ram_ptr(i), TARGET_PAGE_SIZE);
- if (ret)
- return ret;
- }
- return 0;
-}
-
#define BDRV_HASH_BLOCK_SIZE 1024
#define IOBUF_SIZE 4096
#define RAM_CBLOCK_MAGIC 0xfabe
@@ -3103,9 +3062,6 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
ram_addr_t addr;
int flags;
- if (version_id == 1)
- return ram_load_v1(f, opaque);
-
if (version_id == 2) {
if (qemu_get_be32(f) != last_ram_offset)
return -EINVAL;
@@ -5345,6 +5301,16 @@ int main(int argc, char **argv, char **envp)
monitor_devices[monitor_device_index] = optarg;
monitor_device_index++;
break;
+ case QEMU_OPTION_chardev:
+ opts = qemu_opts_parse(&qemu_chardev_opts, optarg, "backend");
+ if (!opts) {
+ fprintf(stderr, "parse error: %s\n", optarg);
+ exit(1);
+ }
+ if (NULL == qemu_chr_open_opts(opts, NULL)) {
+ exit(1);
+ }
+ break;
case QEMU_OPTION_serial:
if (serial_device_index >= MAX_SERIAL_PORTS) {
fprintf(stderr, "qemu: too many serial ports\n");