From 3d6d306c104abe37610184f12e9342fcbc078395 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 15 Oct 2010 09:47:53 +0200 Subject: [PATCH 001/105] spice-core: fix watching for write events Signed-off-by: Gerd Hoffmann --- ui/spice-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/spice-core.c b/ui/spice-core.c index 6a1cf17e49..45807ed6e1 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -95,7 +95,7 @@ static void watch_update_mask(SpiceWatch *watch, int event_mask) on_read = watch_read; } if (watch->event_mask & SPICE_WATCH_EVENT_WRITE) { - on_read = watch_write; + on_write = watch_write; } qemu_set_fd_handler(watch->fd, on_read, on_write, watch); } From f61d69607d58a81944a4bfcfc1f260d09a686460 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 2 Nov 2010 12:21:50 +0100 Subject: [PATCH 002/105] spice-core: fix warning when building with spice < 0.6.0 Signed-off-by: Gerd Hoffmann --- ui/spice-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/spice-core.c b/ui/spice-core.c index 45807ed6e1..e97a72d3d6 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -240,7 +240,7 @@ void qemu_spice_init(void) char *x509_key_file = NULL, *x509_cert_file = NULL, *x509_cacert_file = NULL; - int port, tls_port, len, addr_flags, streaming_video; + int port, tls_port, len, addr_flags; spice_image_compression_t compression; spice_wan_compression_t wan_compr; @@ -344,7 +344,7 @@ void qemu_spice_init(void) str = qemu_opt_get(opts, "streaming-video"); if (str) { - streaming_video = parse_stream_video(str); + int streaming_video = parse_stream_video(str); spice_server_set_streaming_video(spice_server, streaming_video); } From 7466bc49107fbd84336ba680f860d5eadd6def13 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 14 Oct 2010 16:55:01 +0200 Subject: [PATCH 003/105] spice-display: replace private lock with qemu mutex. qemu_spice_create_update() must aquire the global qemu mutex to make sure DisplayState doesn't change while we are accessing it. Once this is in place the private lock is pretty pointless as everything it protects is covered by the global qemu mutex now. Drop it. Signed-off-by: Gerd Hoffmann --- ui/spice-display.c | 27 ++++++++++++++------------- ui/spice-display.h | 1 - 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ui/spice-display.c b/ui/spice-display.c index 7b4f5c1bc9..020b423bd6 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -64,10 +64,10 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r) /* * Called from spice server thread context (via interface_get_command). - * We do *not* hold the global qemu mutex here, so extra care is needed - * when calling qemu functions. Qemu interfaces used: - * - pflib (is re-entrant). - * - qemu_malloc (underlying glibc malloc is re-entrant). + * + * We must aquire the global qemu mutex here to make sure the + * DisplayState (+DisplaySurface) we are accessing doesn't change + * underneath us. */ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) { @@ -78,11 +78,12 @@ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) uint8_t *src, *dst; int by, bw, bh; + qemu_mutex_lock_iothread(); if (qemu_spice_rect_is_empty(&ssd->dirty)) { + qemu_mutex_unlock_iothread(); return NULL; }; - pthread_mutex_lock(&ssd->lock); dprint(2, "%s: lr %d -> %d, tb -> %d -> %d\n", __FUNCTION__, ssd->dirty.left, ssd->dirty.right, ssd->dirty.top, ssd->dirty.bottom); @@ -140,7 +141,7 @@ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) cmd->data = (intptr_t)drawable; memset(&ssd->dirty, 0, sizeof(ssd->dirty)); - pthread_mutex_unlock(&ssd->lock); + qemu_mutex_unlock_iothread(); return update; } @@ -184,14 +185,19 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) surface.type = 0; surface.mem = (intptr_t)ssd->buf; surface.group_id = MEMSLOT_GROUP_HOST; + + qemu_mutex_unlock_iothread(); ssd->worker->create_primary_surface(ssd->worker, 0, &surface); + qemu_mutex_lock_iothread(); } void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) { dprint(1, "%s:\n", __FUNCTION__); + qemu_mutex_unlock_iothread(); ssd->worker->destroy_primary_surface(ssd->worker, 0); + qemu_mutex_lock_iothread(); } void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason) @@ -201,7 +207,9 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason) if (running) { ssd->worker->start(ssd->worker); } else { + qemu_mutex_unlock_iothread(); ssd->worker->stop(ssd->worker); + qemu_mutex_lock_iothread(); } ssd->running = running; } @@ -219,31 +227,25 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, update_area.top = y; update_area.bottom = y + h; - pthread_mutex_lock(&ssd->lock); if (qemu_spice_rect_is_empty(&ssd->dirty)) { ssd->notify++; } qemu_spice_rect_union(&ssd->dirty, &update_area); - pthread_mutex_unlock(&ssd->lock); } void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) { dprint(1, "%s:\n", __FUNCTION__); - pthread_mutex_lock(&ssd->lock); memset(&ssd->dirty, 0, sizeof(ssd->dirty)); qemu_pf_conv_put(ssd->conv); ssd->conv = NULL; - pthread_mutex_unlock(&ssd->lock); qemu_spice_destroy_host_primary(ssd); qemu_spice_create_host_primary(ssd); - pthread_mutex_lock(&ssd->lock); memset(&ssd->dirty, 0, sizeof(ssd->dirty)); ssd->notify++; - pthread_mutex_unlock(&ssd->lock); } void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) @@ -398,7 +400,6 @@ void qemu_spice_display_init(DisplayState *ds) sdpy.ds = ds; sdpy.bufsize = (16 * 1024 * 1024); sdpy.buf = qemu_malloc(sdpy.bufsize); - pthread_mutex_init(&sdpy.lock, NULL); register_displaychangelistener(ds, &display_listener); sdpy.qxl.base.sif = &dpy_interface.base; diff --git a/ui/spice-display.h b/ui/spice-display.h index e17671c12a..aef0464f86 100644 --- a/ui/spice-display.h +++ b/ui/spice-display.h @@ -40,7 +40,6 @@ typedef struct SimpleSpiceDisplay { uint32_t unique; QemuPfConv *conv; - pthread_mutex_t lock; QXLRect dirty; int notify; int running; From 5dba48a882c126ccc86db6506cfa6dcca97badab Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 25 Oct 2010 14:52:21 +0200 Subject: [PATCH 004/105] scsi-disk: Implement rerror option This implements the rerror option for SCSI disks. It also includes minor changes to the write path where the same code is used that was criticized in the review for the changes to the read path required for rerror support. Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- blockdev.c | 6 +-- hw/scsi-disk.c | 100 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 69 insertions(+), 37 deletions(-) diff --git a/blockdev.c b/blockdev.c index ff7602be2c..6cb179a409 100644 --- a/blockdev.c +++ b/blockdev.c @@ -314,7 +314,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error) on_write_error = BLOCK_ERR_STOP_ENOSPC; if ((buf = qemu_opt_get(opts, "werror")) != NULL) { if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) { - fprintf(stderr, "werror is no supported by this format\n"); + fprintf(stderr, "werror is not supported by this format\n"); return NULL; } @@ -326,8 +326,8 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error) on_read_error = BLOCK_ERR_REPORT; if ((buf = qemu_opt_get(opts, "rerror")) != NULL) { - if (type != IF_IDE && type != IF_VIRTIO && type != IF_NONE) { - fprintf(stderr, "rerror is no supported by this format\n"); + if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type != IF_NONE) { + fprintf(stderr, "rerror is not supported by this format\n"); return NULL; } diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 9628b39a21..43a5b59e26 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -41,7 +41,10 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #define SCSI_DMA_BUF_SIZE 131072 #define SCSI_MAX_INQUIRY_LEN 256 -#define SCSI_REQ_STATUS_RETRY 0x01 +#define SCSI_REQ_STATUS_RETRY 0x01 +#define SCSI_REQ_STATUS_RETRY_TYPE_MASK 0x06 +#define SCSI_REQ_STATUS_RETRY_READ 0x00 +#define SCSI_REQ_STATUS_RETRY_WRITE 0x02 typedef struct SCSIDiskState SCSIDiskState; @@ -70,6 +73,8 @@ struct SCSIDiskState char *serial; }; +static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type); + static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag, uint32_t lun) { @@ -127,34 +132,30 @@ static void scsi_cancel_io(SCSIDevice *d, uint32_t tag) static void scsi_read_complete(void * opaque, int ret) { SCSIDiskReq *r = (SCSIDiskReq *)opaque; + int n; r->req.aiocb = NULL; if (ret) { - DPRINTF("IO error\n"); - r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0); - scsi_command_complete(r, CHECK_CONDITION, NO_SENSE); - return; + if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) { + return; + } } + DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len); + n = r->iov.iov_len / 512; + r->sector += n; + r->sector_count -= n; r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len); } -/* Read more data from scsi device into buffer. */ -static void scsi_read_data(SCSIDevice *d, uint32_t tag) + +static void scsi_read_request(SCSIDiskReq *r) { - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); - SCSIDiskReq *r; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); uint32_t n; - r = scsi_find_request(s, tag); - if (!r) { - BADF("Bad read tag 0x%x\n", tag); - /* ??? This is the wrong error. */ - scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); - return; - } if (r->sector_count == (uint32_t)-1) { DPRINTF("Read buf_len=%zd\n", r->iov.iov_len); r->sector_count = 0; @@ -177,29 +178,54 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) scsi_read_complete, r); if (r->req.aiocb == NULL) scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); - r->sector += n; - r->sector_count -= n; } -static int scsi_handle_write_error(SCSIDiskReq *r, int error) +/* Read more data from scsi device into buffer. */ +static void scsi_read_data(SCSIDevice *d, uint32_t tag) { + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); + SCSIDiskReq *r; + + r = scsi_find_request(s, tag); + if (!r) { + BADF("Bad read tag 0x%x\n", tag); + /* ??? This is the wrong error. */ + scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); + return; + } + + /* No data transfer may already be in progress */ + assert(r->req.aiocb == NULL); + + scsi_read_request(r); +} + +static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type) +{ + int is_read = (type == SCSI_REQ_STATUS_RETRY_READ); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - BlockErrorAction action = bdrv_get_on_error(s->bs, 0); + BlockErrorAction action = bdrv_get_on_error(s->bs, is_read); if (action == BLOCK_ERR_IGNORE) { - bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, 0); + bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read); return 0; } if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) || action == BLOCK_ERR_STOP_ANY) { - r->status |= SCSI_REQ_STATUS_RETRY; - bdrv_mon_event(s->bs, BDRV_ACTION_STOP, 0); + + type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK; + r->status |= SCSI_REQ_STATUS_RETRY | type; + + bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read); vm_stop(0); } else { + if (type == SCSI_REQ_STATUS_RETRY_READ) { + r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0); + } scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); - bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, 0); + bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read); } return 1; @@ -214,8 +240,9 @@ static void scsi_write_complete(void * opaque, int ret) r->req.aiocb = NULL; if (ret) { - if (scsi_handle_write_error(r, -ret)) + if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) { return; + } } n = r->iov.iov_len / 512; @@ -268,8 +295,8 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) return 1; } - if (r->req.aiocb) - BADF("Data transfer already in progress\n"); + /* No data transfer may already be in progress */ + assert(r->req.aiocb == NULL); scsi_write_request(r); @@ -288,8 +315,18 @@ static void scsi_dma_restart_bh(void *opaque) QTAILQ_FOREACH(req, &s->qdev.requests, next) { r = DO_UPCAST(SCSIDiskReq, req, req); if (r->status & SCSI_REQ_STATUS_RETRY) { - r->status &= ~SCSI_REQ_STATUS_RETRY; - scsi_write_request(r); + int status = r->status; + r->status &= + ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK); + + switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) { + case SCSI_REQ_STATUS_RETRY_READ: + scsi_read_request(r); + break; + case SCSI_REQ_STATUS_RETRY_WRITE: + scsi_write_request(r); + break; + } } } } @@ -1152,11 +1189,6 @@ static int scsi_disk_initfn(SCSIDevice *dev) return -1; } - if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) { - error_report("Device doesn't support drive option rerror"); - return -1; - } - if (!s->serial) { /* try to fall back to value set with legacy -drive serial=... */ dinfo = drive_get_by_blockdev(s->bs); From 205ef7961f781496366e0a93a4ec621ad3724bd7 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 21 Oct 2010 16:43:43 +0200 Subject: [PATCH 005/105] block: Allow bdrv_flush to return errors This changes bdrv_flush to return 0 on success and -errno in case of failure. It's a requirement for implementing proper error handle in users of bdrv_flush. Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- block.c | 21 +++++++++++++++++---- block.h | 2 +- block/blkdebug.c | 4 ++-- block/blkverify.c | 4 ++-- block/cow.c | 4 ++-- block/qcow.c | 4 ++-- block/qcow2.c | 4 ++-- block/raw-posix.c | 4 ++-- block/raw-win32.c | 9 ++++++++- block/raw.c | 4 ++-- block/vdi.c | 4 ++-- block/vmdk.c | 4 ++-- block_int.h | 2 +- 13 files changed, 45 insertions(+), 25 deletions(-) diff --git a/block.c b/block.c index 985d0b7e39..6b505fba1b 100644 --- a/block.c +++ b/block.c @@ -1453,14 +1453,27 @@ const char *bdrv_get_device_name(BlockDriverState *bs) return bs->device_name; } -void bdrv_flush(BlockDriverState *bs) +int bdrv_flush(BlockDriverState *bs) { if (bs->open_flags & BDRV_O_NO_FLUSH) { - return; + return 0; } - if (bs->drv && bs->drv->bdrv_flush) - bs->drv->bdrv_flush(bs); + if (bs->drv && bs->drv->bdrv_flush) { + return bs->drv->bdrv_flush(bs); + } + + /* + * Some block drivers always operate in either writethrough or unsafe mode + * and don't support bdrv_flush therefore. Usually qemu doesn't know how + * the server works (because the behaviour is hardcoded or depends on + * server-side configuration), so we can't ensure that everything is safe + * on disk. Returning an error doesn't work because that would break guests + * even if the server operates in writethrough mode. + * + * Let's hope the user knows what he's doing. + */ + return 0; } void bdrv_flush_all(void) diff --git a/block.h b/block.h index a4facf2fa6..78ecfac343 100644 --- a/block.h +++ b/block.h @@ -142,7 +142,7 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque); /* Ensure contents are flushed to disk. */ -void bdrv_flush(BlockDriverState *bs); +int bdrv_flush(BlockDriverState *bs); void bdrv_flush_all(void); void bdrv_close_all(void); diff --git a/block/blkdebug.c b/block/blkdebug.c index 4d6ff0a368..cd9eb8006a 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -397,9 +397,9 @@ static void blkdebug_close(BlockDriverState *bs) } } -static void blkdebug_flush(BlockDriverState *bs) +static int blkdebug_flush(BlockDriverState *bs) { - bdrv_flush(bs->file); + return bdrv_flush(bs->file); } static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs, diff --git a/block/blkverify.c b/block/blkverify.c index b2a12fe7f5..0a8d691210 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -116,12 +116,12 @@ static void blkverify_close(BlockDriverState *bs) s->test_file = NULL; } -static void blkverify_flush(BlockDriverState *bs) +static int blkverify_flush(BlockDriverState *bs) { BDRVBlkverifyState *s = bs->opaque; /* Only flush test file, the raw file is not important */ - bdrv_flush(s->test_file); + return bdrv_flush(s->test_file); } static int64_t blkverify_getlength(BlockDriverState *bs) diff --git a/block/cow.c b/block/cow.c index eedcc48772..4cf543c832 100644 --- a/block/cow.c +++ b/block/cow.c @@ -282,9 +282,9 @@ exit: return ret; } -static void cow_flush(BlockDriverState *bs) +static int cow_flush(BlockDriverState *bs) { - bdrv_flush(bs->file); + return bdrv_flush(bs->file); } static QEMUOptionParameter cow_create_options[] = { diff --git a/block/qcow.c b/block/qcow.c index 816103d395..9cd547dc02 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -910,9 +910,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, return 0; } -static void qcow_flush(BlockDriverState *bs) +static int qcow_flush(BlockDriverState *bs) { - bdrv_flush(bs->file); + return bdrv_flush(bs->file); } static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs, diff --git a/block/qcow2.c b/block/qcow2.c index b816d8733f..537c479a7b 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1148,9 +1148,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, return 0; } -static void qcow_flush(BlockDriverState *bs) +static int qcow_flush(BlockDriverState *bs) { - bdrv_flush(bs->file); + return bdrv_flush(bs->file); } static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs, diff --git a/block/raw-posix.c b/block/raw-posix.c index d0393e0c44..d0960b85c4 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -734,10 +734,10 @@ static int raw_create(const char *filename, QEMUOptionParameter *options) return result; } -static void raw_flush(BlockDriverState *bs) +static int raw_flush(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; - qemu_fdatasync(s->fd); + return qemu_fdatasync(s->fd); } diff --git a/block/raw-win32.c b/block/raw-win32.c index 503ed3959a..7f32778612 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -150,7 +150,14 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num, static void raw_flush(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; - FlushFileBuffers(s->hfile); + int ret; + + ret = FlushFileBuffers(s->hfile); + if (ret != 0) { + return -EIO; + } + + return 0; } static void raw_close(BlockDriverState *bs) diff --git a/block/raw.c b/block/raw.c index 91087792fc..1980debc00 100644 --- a/block/raw.c +++ b/block/raw.c @@ -39,9 +39,9 @@ static void raw_close(BlockDriverState *bs) { } -static void raw_flush(BlockDriverState *bs) +static int raw_flush(BlockDriverState *bs) { - bdrv_flush(bs->file); + return bdrv_flush(bs->file); } static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs, diff --git a/block/vdi.c b/block/vdi.c index f72633cf19..3b51e532c4 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -900,10 +900,10 @@ static void vdi_close(BlockDriverState *bs) { } -static void vdi_flush(BlockDriverState *bs) +static int vdi_flush(BlockDriverState *bs) { logout("\n"); - bdrv_flush(bs->file); + return bdrv_flush(bs->file); } diff --git a/block/vmdk.c b/block/vmdk.c index 2d4ba421db..872aebac9b 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -823,9 +823,9 @@ static void vmdk_close(BlockDriverState *bs) qemu_free(s->l2_cache); } -static void vmdk_flush(BlockDriverState *bs) +static int vmdk_flush(BlockDriverState *bs) { - bdrv_flush(bs->file); + return bdrv_flush(bs->file); } diff --git a/block_int.h b/block_int.h index 87e60b8597..3c3adb5c85 100644 --- a/block_int.h +++ b/block_int.h @@ -59,7 +59,7 @@ struct BlockDriver { const uint8_t *buf, int nb_sectors); void (*bdrv_close)(BlockDriverState *bs); int (*bdrv_create)(const char *filename, QEMUOptionParameter *options); - void (*bdrv_flush)(BlockDriverState *bs); + int (*bdrv_flush)(BlockDriverState *bs); int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum); int (*bdrv_set_key)(BlockDriverState *bs, const char *key); From 8af7a3ab51d9780f52b7d2581f144ab127097362 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 25 Oct 2010 12:43:22 +0200 Subject: [PATCH 006/105] scsi-disk: Complete failed requests in scsi_disk_emulate_command This pulls the request completion for error cases from the caller to scsi_disk_emulate_command. This should not change semantics, but allows to reuse scsi_handle_write_error() for flushes in the next patch. Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- hw/scsi-disk.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 43a5b59e26..96acfe31b9 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -784,8 +784,9 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf) return toclen; } -static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) +static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) { + SCSIRequest *req = &r->req; SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); uint64_t nb_sectors; int buflen = 0; @@ -943,12 +944,12 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) return buflen; not_ready: - scsi_req_set_status(req, CHECK_CONDITION, NOT_READY); - return 0; + scsi_command_complete(r, CHECK_CONDITION, NOT_READY); + return -1; illegal_request: - scsi_req_set_status(req, CHECK_CONDITION, ILLEGAL_REQUEST); - return 0; + scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST); + return -1; } /* Execute a scsi command. Returns the length of the data expected by the @@ -1056,14 +1057,12 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case REPORT_LUNS: case VERIFY: case REZERO_UNIT: - rc = scsi_disk_emulate_command(&r->req, outbuf); - if (rc > 0) { - r->iov.iov_len = rc; - } else { - scsi_req_complete(&r->req); - scsi_remove_request(r); + rc = scsi_disk_emulate_command(r, outbuf); + if (rc < 0) { return 0; } + + r->iov.iov_len = rc; break; case READ_6: case READ_10: From 78ced65e6ec6d76059f0d943a82103122d4e6494 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 25 Oct 2010 16:40:17 +0200 Subject: [PATCH 007/105] scsi-disk: Implement werror for flushes Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- hw/scsi-disk.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 96acfe31b9..6815239fd4 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -45,6 +45,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #define SCSI_REQ_STATUS_RETRY_TYPE_MASK 0x06 #define SCSI_REQ_STATUS_RETRY_READ 0x00 #define SCSI_REQ_STATUS_RETRY_WRITE 0x02 +#define SCSI_REQ_STATUS_RETRY_FLUSH 0x04 typedef struct SCSIDiskState SCSIDiskState; @@ -74,6 +75,7 @@ struct SCSIDiskState }; static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type); +static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf); static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag, uint32_t lun) @@ -316,6 +318,8 @@ static void scsi_dma_restart_bh(void *opaque) r = DO_UPCAST(SCSIDiskReq, req, req); if (r->status & SCSI_REQ_STATUS_RETRY) { int status = r->status; + int ret; + r->status &= ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK); @@ -326,6 +330,11 @@ static void scsi_dma_restart_bh(void *opaque) case SCSI_REQ_STATUS_RETRY_WRITE: scsi_write_request(r); break; + case SCSI_REQ_STATUS_RETRY_FLUSH: + ret = scsi_disk_emulate_command(r, r->iov.iov_base); + if (ret == 0) { + scsi_command_complete(r, GOOD, NO_SENSE); + } } } } @@ -790,6 +799,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); uint64_t nb_sectors; int buflen = 0; + int ret; switch (req->cmd.buf[0]) { case TEST_UNIT_READY: @@ -880,7 +890,12 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) buflen = 8; break; case SYNCHRONIZE_CACHE: - bdrv_flush(s->bs); + ret = bdrv_flush(s->bs); + if (ret < 0) { + if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) { + return -1; + } + } break; case GET_CONFIGURATION: memset(outbuf, 0, 8); From 4a4111851fa75bc91028a26eb75dcdd136d9032d Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 22 Oct 2010 16:17:57 +0200 Subject: [PATCH 008/105] vpc: Implement bdrv_flush Signed-off-by: Kevin Wolf --- block/vpc.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/block/vpc.c b/block/vpc.c index e50509eeaa..416f48900c 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -439,6 +439,10 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num, return 0; } +static int vpc_flush(BlockDriverState *bs) +{ + return bdrv_flush(bs->file); +} /* * Calculates the number of cylinders, heads and sectors per cylinder @@ -618,14 +622,15 @@ static QEMUOptionParameter vpc_create_options[] = { }; static BlockDriver bdrv_vpc = { - .format_name = "vpc", - .instance_size = sizeof(BDRVVPCState), - .bdrv_probe = vpc_probe, - .bdrv_open = vpc_open, - .bdrv_read = vpc_read, - .bdrv_write = vpc_write, - .bdrv_close = vpc_close, - .bdrv_create = vpc_create, + .format_name = "vpc", + .instance_size = sizeof(BDRVVPCState), + .bdrv_probe = vpc_probe, + .bdrv_open = vpc_open, + .bdrv_read = vpc_read, + .bdrv_write = vpc_write, + .bdrv_flush = vpc_flush, + .bdrv_close = vpc_close, + .bdrv_create = vpc_create, .create_options = vpc_create_options, }; From 1c02e2a17104fe7fc11893125864dc0daf1e6d5b Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 28 Oct 2010 16:16:00 +0200 Subject: [PATCH 009/105] qcow2: Invalidate cache after failed read The cache content may be destroyed after a failed read, better not use it any more. Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- block/qcow2-cluster.c | 1 + block/qcow2-refcount.c | 1 + 2 files changed, 2 insertions(+) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 4f7dc59b76..b0402087cf 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -188,6 +188,7 @@ static int l2_load(BlockDriverState *bs, uint64_t l2_offset, ret = bdrv_pread(bs->file, l2_offset, *l2_table, s->l2_size * sizeof(uint64_t)); if (ret < 0) { + qcow2_l2_cache_reset(bs); return ret; } diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 0efb6760cb..a10453c875 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -103,6 +103,7 @@ static int load_refcount_block(BlockDriverState *bs, ret = bdrv_pread(bs->file, refcount_block_offset, s->refcount_block_cache, s->cluster_size); if (ret < 0) { + s->refcount_block_cache_offset = 0; return ret; } From a31335863648d1e707f59296cffb74205aedba96 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sat, 30 Oct 2010 16:46:27 +0000 Subject: [PATCH 010/105] block: avoid a warning on 64 bit hosts with long as int64_t When building on a 64 bit host which uses 'long' for int64_t, GCC emits a warning: CC block/blkverify.o /src/qemu/block/blkverify.c: In function `blkverify_verify_readv': /src/qemu/block/blkverify.c:304: warning: long long int format, long unsigned int arg (arg 3) Rework a77cffe7e916f4dd28f2048982ea2e0d98143b11 to avoid the warning. Signed-off-by: Blue Swirl Signed-off-by: Kevin Wolf --- block/blkverify.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/blkverify.c b/block/blkverify.c index 0a8d691210..c7522b4093 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -300,8 +300,8 @@ static void blkverify_verify_readv(BlkverifyAIOCB *acb) { ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov); if (offset != -1) { - blkverify_err(acb, "contents mismatch in sector %lld", - acb->sector_num + (offset / BDRV_SECTOR_SIZE)); + blkverify_err(acb, "contents mismatch in sector %" PRId64, + acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE)); } } From b2df7531f3adc4f0f65067b917cef8c66ba812c5 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 27 Oct 2010 13:04:15 +0200 Subject: [PATCH 011/105] ide: Handle immediate bdrv_aio_flush failure If bdrv_aio_flush returns NULL, this should be treated as an error. Signed-off-by: Kevin Wolf --- hw/ide/core.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index bc3e91658a..484e0ca96f 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -811,10 +811,16 @@ static void ide_flush_cb(void *opaque, int ret) static void ide_flush_cache(IDEState *s) { - if (s->bs) { - bdrv_aio_flush(s->bs, ide_flush_cb, s); - } else { + BlockDriverAIOCB *acb; + + if (s->bs == NULL) { ide_flush_cb(s, 0); + return; + } + + acb = bdrv_aio_flush(s->bs, ide_flush_cb, s); + if (acb == NULL) { + ide_flush_cb(s, -EIO); } } From 18a8d4214b861aff0caa5acfa921862d0be05bbb Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 27 Oct 2010 13:10:15 +0200 Subject: [PATCH 012/105] virtio-blk: Handle immediate flush failure properly Fix virtio-blk to use the usual completion path that involves werror handling instead of directly completing the request in cases where bdrv_aio_flush returns NULL. Signed-off-by: Kevin Wolf --- hw/virtio-blk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index dbe207070e..49528a9977 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -273,7 +273,7 @@ static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb) acb = bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req); if (!acb) { - virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR); + virtio_blk_flush_complete(req, -EIO); } } From d33ea50a958b2e050d2b28e5f17e3b55e91c6d74 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 27 Oct 2010 13:15:27 +0200 Subject: [PATCH 013/105] scsi-disk: Fix immediate failure of bdrv_aio_* Fix scsi-disk to use the usual completion paths that involve rerror/werror handling instead of directly completing the requests in cases where bdrv_aio_readv/writev returns NULL. Signed-off-by: Kevin Wolf --- hw/scsi-disk.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 6815239fd4..dc719578b0 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -178,8 +178,9 @@ static void scsi_read_request(SCSIDiskReq *r) qemu_iovec_init_external(&r->qiov, &r->iov, 1); r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n, scsi_read_complete, r); - if (r->req.aiocb == NULL) - scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); + if (r->req.aiocb == NULL) { + scsi_read_complete(r, -EIO); + } } /* Read more data from scsi device into buffer. */ @@ -273,9 +274,9 @@ static void scsi_write_request(SCSIDiskReq *r) qemu_iovec_init_external(&r->qiov, &r->iov, 1); r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n, scsi_write_complete, r); - if (r->req.aiocb == NULL) - scsi_command_complete(r, CHECK_CONDITION, - HARDWARE_ERROR); + if (r->req.aiocb == NULL) { + scsi_write_complete(r, -EIO); + } } else { /* Invoke completion routine to fetch data from host. */ scsi_write_complete(r, 0); From cfd07e7abb1ef39373cd4ce312b015d61b9eea8d Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 7 Nov 2010 15:10:40 +0000 Subject: [PATCH 014/105] Fix win32 build Fix a return value change missed by 205ef7961f781496366e0a93a4ec621ad3724bd7. Signed-off-by: Blue Swirl --- block/raw-win32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/raw-win32.c b/block/raw-win32.c index 7f32778612..06c97101bb 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -147,7 +147,7 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num, return ret_count; } -static void raw_flush(BlockDriverState *bs) +static int raw_flush(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; int ret; From dc4b9240dc531f1fc8538e9dc968f2e34e169346 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 9 Nov 2010 11:47:44 +0100 Subject: [PATCH 015/105] intel-hda: exit cleanup Add pci exit callback for the intel-hda device and cleanup properly. Also add an exit callback to the HDA bus implementation and make sure it is called on qdev_free(). Signed-off-by: Gerd Hoffmann Signed-off-by: malc --- hw/intel-hda.c | 20 ++++++++++++++++++++ hw/intel-hda.h | 1 + 2 files changed, 21 insertions(+) diff --git a/hw/intel-hda.c b/hw/intel-hda.c index ccb059dc92..78c32da473 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -61,9 +61,20 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base) return info->init(dev); } +static int hda_codec_dev_exit(DeviceState *qdev) +{ + HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev); + + if (dev->info->exit) { + dev->info->exit(dev); + } + return 0; +} + void hda_codec_register(HDACodecDeviceInfo *info) { info->qdev.init = hda_codec_dev_init; + info->qdev.exit = hda_codec_dev_exit; info->qdev.bus_info = &hda_codec_bus_info; qdev_register(&info->qdev); } @@ -1137,6 +1148,14 @@ static int intel_hda_init(PCIDevice *pci) return 0; } +static int intel_hda_exit(PCIDevice *pci) +{ + IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci); + + cpu_unregister_io_memory(d->mmio_addr); + return 0; +} + static int intel_hda_post_load(void *opaque, int version) { IntelHDAState* d = opaque; @@ -1219,6 +1238,7 @@ static PCIDeviceInfo intel_hda_info = { .qdev.vmsd = &vmstate_intel_hda, .qdev.reset = intel_hda_reset, .init = intel_hda_init, + .exit = intel_hda_exit, .qdev.props = (Property[]) { DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/intel-hda.h b/hw/intel-hda.h index ba290ec850..4e44e3894f 100644 --- a/hw/intel-hda.h +++ b/hw/intel-hda.h @@ -32,6 +32,7 @@ struct HDACodecDevice { struct HDACodecDeviceInfo { DeviceInfo qdev; int (*init)(HDACodecDevice *dev); + int (*exit)(HDACodecDevice *dev); void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data); void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running); }; From 129dcd2c66c3f693425f8a50c553146b8f6f4fd6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 9 Nov 2010 11:47:45 +0100 Subject: [PATCH 016/105] hda-audio: exit cleanup Add exit callback to the driver. Unregister the sound card properly on exit. [ v2: codestyle: add braces ] Signed-off-by: Gerd Hoffmann Signed-off-by: malc --- hw/hda-audio.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/hw/hda-audio.c b/hw/hda-audio.c index 103577470a..c699d6fd8b 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -808,6 +808,28 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc) return 0; } +static int hda_audio_exit(HDACodecDevice *hda) +{ + HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda); + HDAAudioStream *st; + int i; + + dprint(a, 1, "%s\n", __FUNCTION__); + for (i = 0; i < ARRAY_SIZE(a->st); i++) { + st = a->st + i; + if (st->node == NULL) { + continue; + } + if (st->output) { + AUD_close_out(&a->card, st->voice.out); + } else { + AUD_close_in(&a->card, st->voice.in); + } + } + AUD_remove_card(&a->card); + return 0; +} + static int hda_audio_post_load(void *opaque, int version) { HDAAudioState *a = opaque; @@ -879,6 +901,7 @@ static HDACodecDeviceInfo hda_audio_info_output = { .qdev.vmsd = &vmstate_hda_audio, .qdev.props = hda_audio_properties, .init = hda_audio_init_output, + .exit = hda_audio_exit, .command = hda_audio_command, .stream = hda_audio_stream, }; @@ -890,6 +913,7 @@ static HDACodecDeviceInfo hda_audio_info_duplex = { .qdev.vmsd = &vmstate_hda_audio, .qdev.props = hda_audio_properties, .init = hda_audio_init_duplex, + .exit = hda_audio_exit, .command = hda_audio_command, .stream = hda_audio_stream, }; From af93485cde810f3c2f488533e0b60c99eae5d01d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= Date: Tue, 9 Nov 2010 11:47:46 +0100 Subject: [PATCH 017/105] intel-hda: Honor WAKEEN bits. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HDA: Honor WAKEEN bits when deciding to raise an interrupt on codec status change. This prevents an interrupt storm with the Haiku HDA driver which does not handle codec status changes in the irq handler. Signed-off-by: François Revol Signed-off-by: Gerd Hoffmann Signed-off-by: malc --- hw/intel-hda.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/intel-hda.c b/hw/intel-hda.c index 78c32da473..2c1ef12491 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -246,7 +246,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d) if (d->rirb_sts & ICH6_RBSTS_OVERRUN) { sts |= (1 << 30); } - if (d->state_sts) { + if (d->state_sts & d->wake_en) { sts |= (1 << 30); } @@ -628,6 +628,7 @@ static const struct IntelHDAReg regtab[] = { [ ICH6_REG_WAKEEN ] = { .name = "WAKEEN", .size = 2, + .wmask = 0x3fff, .offset = offsetof(IntelHDAState, wake_en), }, [ ICH6_REG_STATESTS ] = { From 6a0d02f5be44ee17cf0ce843f0658d08e97a68c2 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 9 Nov 2010 11:47:47 +0100 Subject: [PATCH 018/105] intel-hda: update irq status on WAKEEN changes. When the guest updates the WAKEEN register we must re-calculate the IRQ status. Signed-off-by: Gerd Hoffmann Signed-off-by: malc --- hw/intel-hda.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/intel-hda.c b/hw/intel-hda.c index 2c1ef12491..e478e677c5 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -508,6 +508,11 @@ static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32 } } +static void intel_hda_set_wake_en(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) +{ + intel_hda_update_irq(d); +} + static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) { intel_hda_update_irq(d); @@ -630,6 +635,7 @@ static const struct IntelHDAReg regtab[] = { .size = 2, .wmask = 0x3fff, .offset = offsetof(IntelHDAState, wake_en), + .whandler = intel_hda_set_wake_en, }, [ ICH6_REG_STATESTS ] = { .name = "STATESTS", From 17786d52acd3e18e77cd7e823f7d6bad9ece818e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 9 Nov 2010 11:47:48 +0100 Subject: [PATCH 019/105] intel-hda: add msi support This patch adds MSI support to the intel hda audio driver. It is enabled by default, use '-device intel-hda,msi=0' to disable it. [ v2: codestyle: add braces ] Signed-off-by: Gerd Hoffmann Signed-off-by: malc --- hw/intel-hda.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/hw/intel-hda.c b/hw/intel-hda.c index e478e677c5..5e13dc35ed 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -19,6 +19,7 @@ #include "hw.h" #include "pci.h" +#include "msi.h" #include "qemu-timer.h" #include "audiodev.h" #include "intel-hda.h" @@ -188,6 +189,7 @@ struct IntelHDAState { /* properties */ uint32_t debug; + uint32_t msi; }; struct IntelHDAReg { @@ -268,6 +270,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d) static void intel_hda_update_irq(IntelHDAState *d) { + int msi = d->msi && msi_enabled(&d->pci); int level; intel_hda_update_int_sts(d); @@ -276,8 +279,15 @@ static void intel_hda_update_irq(IntelHDAState *d) } else { level = 0; } - dprint(d, 2, "%s: level %d\n", __FUNCTION__, level); - qemu_set_irq(d->pci.irq[0], level); + dprint(d, 2, "%s: level %d [%s]\n", __FUNCTION__, + level, msi ? "msi" : "intx"); + if (msi) { + if (level) { + msi_notify(&d->pci, 0); + } + } else { + qemu_set_irq(d->pci.irq[0], level); + } } static int intel_hda_send_command(IntelHDAState *d, uint32_t verb) @@ -1148,6 +1158,9 @@ static int intel_hda_init(PCIDevice *pci) intel_hda_mmio_write, d); pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY, intel_hda_map); + if (d->msi) { + msi_init(&d->pci, 0x50, 1, true, false); + } hda_codec_bus_init(&d->pci.qdev, &d->codecs, intel_hda_response, intel_hda_xfer); @@ -1159,10 +1172,24 @@ static int intel_hda_exit(PCIDevice *pci) { IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci); + if (d->msi) { + msi_uninit(&d->pci); + } cpu_unregister_io_memory(d->mmio_addr); return 0; } +static void intel_hda_write_config(PCIDevice *pci, uint32_t addr, + uint32_t val, int len) +{ + IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci); + + pci_default_write_config(pci, addr, val, len); + if (d->msi) { + msi_write_config(pci, addr, val, len); + } +} + static int intel_hda_post_load(void *opaque, int version) { IntelHDAState* d = opaque; @@ -1246,8 +1273,10 @@ static PCIDeviceInfo intel_hda_info = { .qdev.reset = intel_hda_reset, .init = intel_hda_init, .exit = intel_hda_exit, + .config_write = intel_hda_write_config, .qdev.props = (Property[]) { DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0), + DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1), DEFINE_PROP_END_OF_LIST(), } }; From acc086837e49b44f15eff6007bb1726844df7aec Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 9 Nov 2010 11:47:49 +0100 Subject: [PATCH 020/105] intel-hda: fix codec addressing. The HDA bus supports up to 15 codecs, with addresses 0 ... 14. We get that wrong in two places: * When handing out addresses we accept address 15 as valid. * The bitmasks for two registers (WAKEEN and STATESTS) don't have bit 14 set. This patch fixes it. Signed-off-by: Gerd Hoffmann Signed-off-by: malc --- hw/intel-hda.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/intel-hda.c b/hw/intel-hda.c index 5e13dc35ed..b34b1408f2 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -56,7 +56,7 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base) if (dev->cad == -1) { dev->cad = bus->next_cad; } - if (dev->cad > 15) + if (dev->cad >= 15) return -1; bus->next_cad = dev->cad + 1; return info->init(dev); @@ -643,15 +643,15 @@ static const struct IntelHDAReg regtab[] = { [ ICH6_REG_WAKEEN ] = { .name = "WAKEEN", .size = 2, - .wmask = 0x3fff, + .wmask = 0x7fff, .offset = offsetof(IntelHDAState, wake_en), .whandler = intel_hda_set_wake_en, }, [ ICH6_REG_STATESTS ] = { .name = "STATESTS", .size = 2, - .wmask = 0x3fff, - .wclear = 0x3fff, + .wmask = 0x7fff, + .wclear = 0x7fff, .offset = offsetof(IntelHDAState, state_sts), .whandler = intel_hda_set_state_sts, }, From e2553eb44e4ddd0b22124216d3dd20b6a0fecefb Mon Sep 17 00:00:00 2001 From: malc Date: Tue, 9 Nov 2010 19:14:15 +0300 Subject: [PATCH 021/105] Revert "intel-hda: fix codec addressing." Misses braces This reverts commit acc086837e49b44f15eff6007bb1726844df7aec. --- hw/intel-hda.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/intel-hda.c b/hw/intel-hda.c index b34b1408f2..5e13dc35ed 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -56,7 +56,7 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base) if (dev->cad == -1) { dev->cad = bus->next_cad; } - if (dev->cad >= 15) + if (dev->cad > 15) return -1; bus->next_cad = dev->cad + 1; return info->init(dev); @@ -643,15 +643,15 @@ static const struct IntelHDAReg regtab[] = { [ ICH6_REG_WAKEEN ] = { .name = "WAKEEN", .size = 2, - .wmask = 0x7fff, + .wmask = 0x3fff, .offset = offsetof(IntelHDAState, wake_en), .whandler = intel_hda_set_wake_en, }, [ ICH6_REG_STATESTS ] = { .name = "STATESTS", .size = 2, - .wmask = 0x7fff, - .wclear = 0x7fff, + .wmask = 0x3fff, + .wclear = 0x3fff, .offset = offsetof(IntelHDAState, state_sts), .whandler = intel_hda_set_state_sts, }, From df0db2212d86e98c41774600c44cc960ddc2b68c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 9 Nov 2010 17:28:38 +0100 Subject: [PATCH 022/105] intel-hda: fix codec addressing. The HDA bus supports up to 15 codecs, with addresses 0 ... 14. We get that wrong in two places: * When handing out addresses we accept address 15 as valid. * The bitmasks for two registers (WAKEEN and STATESTS) don't have bit 14 set. This patch fixes it. [ v2: codestyle: add braces ] Signed-off-by: Gerd Hoffmann Signed-off-by: malc --- hw/intel-hda.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/intel-hda.c b/hw/intel-hda.c index 5e13dc35ed..fe316245ad 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -56,8 +56,9 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base) if (dev->cad == -1) { dev->cad = bus->next_cad; } - if (dev->cad > 15) + if (dev->cad >= 15) { return -1; + } bus->next_cad = dev->cad + 1; return info->init(dev); } @@ -643,15 +644,15 @@ static const struct IntelHDAReg regtab[] = { [ ICH6_REG_WAKEEN ] = { .name = "WAKEEN", .size = 2, - .wmask = 0x3fff, + .wmask = 0x7fff, .offset = offsetof(IntelHDAState, wake_en), .whandler = intel_hda_set_wake_en, }, [ ICH6_REG_STATESTS ] = { .name = "STATESTS", .size = 2, - .wmask = 0x3fff, - .wclear = 0x3fff, + .wmask = 0x7fff, + .wclear = 0x7fff, .offset = offsetof(IntelHDAState, state_sts), .whandler = intel_hda_set_state_sts, }, From 3e31375378f40558f1ee7c258f3cc63c85596bfc Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 9 Nov 2010 17:29:46 +0100 Subject: [PATCH 023/105] spice: add audio Add support for the spice audio interface. With this patch applied audio can be forwarded over the network from/to the spice client. Both recording and playback is supported. The driver is first in the driver list, but the can_be_default flag is set only in case spice is active. So if you have the spice protocol enabled the spice audio driver is the default one, otherwise whatever comes first after spice in the list. Overriding the default using QEMU_AUDIO_DRV works in any case. [ v2: audio codestyle: add spaces before open parenthesis ] [ v2: add const to silence array ] Signed-off-by: Gerd Hoffmann Cc: malc Signed-off-by: malc --- Makefile.objs | 1 + audio/audio.c | 3 + audio/audio_int.h | 1 + audio/spiceaudio.c | 327 +++++++++++++++++++++++++++++++++++++++++++++ ui/qemu-spice.h | 1 + ui/spice-core.c | 1 + 6 files changed, 334 insertions(+) create mode 100644 audio/spiceaudio.c diff --git a/Makefile.objs b/Makefile.objs index faf485ed1b..15569afa14 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -102,6 +102,7 @@ common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display. audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o audio-obj-$(CONFIG_SDL) += sdlaudio.o audio-obj-$(CONFIG_OSS) += ossaudio.o +audio-obj-$(CONFIG_SPICE) += spiceaudio.o audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o audio-obj-$(CONFIG_ALSA) += alsaaudio.o audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o diff --git a/audio/audio.c b/audio/audio.c index ad51077f32..ade342e856 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -44,6 +44,9 @@ that we generate the list. */ static struct audio_driver *drvtab[] = { +#ifdef CONFIG_SPICE + &spice_audio_driver, +#endif CONFIG_AUDIO_DRIVERS &no_audio_driver, &wav_audio_driver diff --git a/audio/audio_int.h b/audio/audio_int.h index d8560b662b..d66f2c3bf6 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -209,6 +209,7 @@ extern struct audio_driver coreaudio_audio_driver; extern struct audio_driver dsound_audio_driver; extern struct audio_driver esd_audio_driver; extern struct audio_driver pa_audio_driver; +extern struct audio_driver spice_audio_driver; extern struct audio_driver winwave_audio_driver; extern struct mixeng_volume nominal_volume; diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c new file mode 100644 index 0000000000..51ba53a39d --- /dev/null +++ b/audio/spiceaudio.c @@ -0,0 +1,327 @@ +#include "hw/hw.h" +#include "qemu-timer.h" +#include "ui/qemu-spice.h" + +#define AUDIO_CAP "spice" +#include "audio.h" +#include "audio_int.h" + +#define LINE_IN_SAMPLES 1024 +#define LINE_OUT_SAMPLES 1024 + +typedef struct SpiceRateCtl { + int64_t start_ticks; + int64_t bytes_sent; +} SpiceRateCtl; + +typedef struct SpiceVoiceOut { + HWVoiceOut hw; + SpicePlaybackInstance sin; + SpiceRateCtl rate; + int active; + uint32_t *frame; + uint32_t *fpos; + uint32_t fsize; +} SpiceVoiceOut; + +typedef struct SpiceVoiceIn { + HWVoiceIn hw; + SpiceRecordInstance sin; + SpiceRateCtl rate; + int active; + uint32_t samples[LINE_IN_SAMPLES]; +} SpiceVoiceIn; + +static const SpicePlaybackInterface playback_sif = { + .base.type = SPICE_INTERFACE_PLAYBACK, + .base.description = "playback", + .base.major_version = SPICE_INTERFACE_PLAYBACK_MAJOR, + .base.minor_version = SPICE_INTERFACE_PLAYBACK_MINOR, +}; + +static const SpiceRecordInterface record_sif = { + .base.type = SPICE_INTERFACE_RECORD, + .base.description = "record", + .base.major_version = SPICE_INTERFACE_RECORD_MAJOR, + .base.minor_version = SPICE_INTERFACE_RECORD_MINOR, +}; + +static void *spice_audio_init (void) +{ + if (!using_spice) { + return NULL; + } + return &spice_audio_init; +} + +static void spice_audio_fini (void *opaque) +{ + /* nothing */ +} + +static void rate_start (SpiceRateCtl *rate) +{ + memset (rate, 0, sizeof (*rate)); + rate->start_ticks = qemu_get_clock (vm_clock); +} + +static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate) +{ + int64_t now; + int64_t ticks; + int64_t bytes; + int64_t samples; + + now = qemu_get_clock (vm_clock); + ticks = now - rate->start_ticks; + bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ()); + samples = (bytes - rate->bytes_sent) >> info->shift; + if (samples < 0 || samples > 65536) { + fprintf (stderr, "Resetting rate control (%" PRId64 " samples)\n", samples); + rate_start (rate); + samples = 0; + } + rate->bytes_sent += samples << info->shift; + return samples; +} + +/* playback */ + +static int line_out_init (HWVoiceOut *hw, struct audsettings *as) +{ + SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); + struct audsettings settings; + + settings.freq = SPICE_INTERFACE_PLAYBACK_FREQ; + settings.nchannels = SPICE_INTERFACE_PLAYBACK_CHAN; + settings.fmt = AUD_FMT_S16; + settings.endianness = AUDIO_HOST_ENDIANNESS; + + audio_pcm_init_info (&hw->info, &settings); + hw->samples = LINE_OUT_SAMPLES; + out->active = 0; + + out->sin.base.sif = &playback_sif.base; + qemu_spice_add_interface (&out->sin.base); + return 0; +} + +static void line_out_fini (HWVoiceOut *hw) +{ + SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); + + spice_server_remove_interface (&out->sin.base); +} + +static int line_out_run (HWVoiceOut *hw, int live) +{ + SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); + int rpos, decr; + int samples; + + if (!live) { + return 0; + } + + decr = rate_get_samples (&hw->info, &out->rate); + decr = audio_MIN (live, decr); + + samples = decr; + rpos = hw->rpos; + while (samples) { + int left_till_end_samples = hw->samples - rpos; + int len = audio_MIN (samples, left_till_end_samples); + + if (!out->frame) { + spice_server_playback_get_buffer (&out->sin, &out->frame, &out->fsize); + out->fpos = out->frame; + } + if (out->frame) { + len = audio_MIN (len, out->fsize); + hw->clip (out->fpos, hw->mix_buf + rpos, len); + out->fsize -= len; + out->fpos += len; + if (out->fsize == 0) { + spice_server_playback_put_samples (&out->sin, out->frame); + out->frame = out->fpos = NULL; + } + } + rpos = (rpos + len) % hw->samples; + samples -= len; + } + hw->rpos = rpos; + return decr; +} + +static int line_out_write (SWVoiceOut *sw, void *buf, int len) +{ + return audio_pcm_sw_write (sw, buf, len); +} + +static int line_out_ctl (HWVoiceOut *hw, int cmd, ...) +{ + SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); + + switch (cmd) { + case VOICE_ENABLE: + if (out->active) { + break; + } + out->active = 1; + rate_start (&out->rate); + spice_server_playback_start (&out->sin); + break; + case VOICE_DISABLE: + if (!out->active) { + break; + } + out->active = 0; + if (out->frame) { + memset (out->fpos, 0, out->fsize << 2); + spice_server_playback_put_samples (&out->sin, out->frame); + out->frame = out->fpos = NULL; + } + spice_server_playback_stop (&out->sin); + break; + } + return 0; +} + +/* record */ + +static int line_in_init (HWVoiceIn *hw, struct audsettings *as) +{ + SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); + struct audsettings settings; + + settings.freq = SPICE_INTERFACE_RECORD_FREQ; + settings.nchannels = SPICE_INTERFACE_RECORD_CHAN; + settings.fmt = AUD_FMT_S16; + settings.endianness = AUDIO_HOST_ENDIANNESS; + + audio_pcm_init_info (&hw->info, &settings); + hw->samples = LINE_IN_SAMPLES; + in->active = 0; + + in->sin.base.sif = &record_sif.base; + qemu_spice_add_interface (&in->sin.base); + return 0; +} + +static void line_in_fini (HWVoiceIn *hw) +{ + SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); + + spice_server_remove_interface (&in->sin.base); +} + +static int line_in_run (HWVoiceIn *hw) +{ + SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); + int num_samples; + int ready; + int len[2]; + uint64_t delta_samp; + const uint32_t *samples; + + if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in (hw))) { + return 0; + } + + delta_samp = rate_get_samples (&hw->info, &in->rate); + num_samples = audio_MIN (num_samples, delta_samp); + + ready = spice_server_record_get_samples (&in->sin, in->samples, num_samples); + samples = in->samples; + if (ready == 0) { + static const uint32_t silence[LINE_IN_SAMPLES]; + samples = silence; + ready = LINE_IN_SAMPLES; + } + + num_samples = audio_MIN (ready, num_samples); + + if (hw->wpos + num_samples > hw->samples) { + len[0] = hw->samples - hw->wpos; + len[1] = num_samples - len[0]; + } else { + len[0] = num_samples; + len[1] = 0; + } + + hw->conv (hw->conv_buf + hw->wpos, samples, len[0], &nominal_volume); + + if (len[1]) { + hw->conv (hw->conv_buf, samples + len[0], len[1], + &nominal_volume); + } + + hw->wpos = (hw->wpos + num_samples) % hw->samples; + + return num_samples; +} + +static int line_in_read (SWVoiceIn *sw, void *buf, int size) +{ + return audio_pcm_sw_read (sw, buf, size); +} + +static int line_in_ctl (HWVoiceIn *hw, int cmd, ...) +{ + SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); + + switch (cmd) { + case VOICE_ENABLE: + if (in->active) { + break; + } + in->active = 1; + rate_start (&in->rate); + spice_server_record_start (&in->sin); + break; + case VOICE_DISABLE: + if (!in->active) { + break; + } + in->active = 0; + spice_server_record_stop (&in->sin); + break; + } + return 0; +} + +static struct audio_option audio_options[] = { + { /* end of list */ }, +}; + +static struct audio_pcm_ops audio_callbacks = { + .init_out = line_out_init, + .fini_out = line_out_fini, + .run_out = line_out_run, + .write = line_out_write, + .ctl_out = line_out_ctl, + + .init_in = line_in_init, + .fini_in = line_in_fini, + .run_in = line_in_run, + .read = line_in_read, + .ctl_in = line_in_ctl, +}; + +struct audio_driver spice_audio_driver = { + .name = "spice", + .descr = "spice audio driver", + .options = audio_options, + .init = spice_audio_init, + .fini = spice_audio_fini, + .pcm_ops = &audio_callbacks, + .max_voices_out = 1, + .max_voices_in = 1, + .voice_size_out = sizeof (SpiceVoiceOut), + .voice_size_in = sizeof (SpiceVoiceIn), +}; + +void qemu_spice_audio_init (void) +{ + spice_audio_driver.can_be_default = 1; +} diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h index 063c7dc8c8..0e3ad9b8c0 100644 --- a/ui/qemu-spice.h +++ b/ui/qemu-spice.h @@ -29,6 +29,7 @@ extern int using_spice; void qemu_spice_init(void); void qemu_spice_input_init(void); +void qemu_spice_audio_init(void); void qemu_spice_display_init(DisplayState *ds); int qemu_spice_add_interface(SpiceBaseInstance *sin); diff --git a/ui/spice-core.c b/ui/spice-core.c index 6a1cf17e49..6c404b39fb 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -361,6 +361,7 @@ void qemu_spice_init(void) using_spice = 1; qemu_spice_input_init(); + qemu_spice_audio_init(); qemu_free(x509_key_file); qemu_free(x509_cert_file); From cf2c1839a955482f2e208d7400594bf076c222f2 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 11 Nov 2010 13:07:52 +0100 Subject: [PATCH 024/105] add copyright to spiceaudio Signed-off-by: Gerd Hoffmann Signed-off-by: malc --- audio/spiceaudio.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c index 51ba53a39d..373e4c43ed 100644 --- a/audio/spiceaudio.c +++ b/audio/spiceaudio.c @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * maintained by Gerd Hoffmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + #include "hw/hw.h" #include "qemu-timer.h" #include "ui/qemu-spice.h" From 3b3d448e01ccfc6fdcb6e3d4ebf47418075e3bb4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 23 Aug 2010 12:10:46 +0200 Subject: [PATCH 025/105] Add new vgabios binaries to blobs list. aliguori: update VGA BIOS Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- Makefile | 5 +++-- pc-bios/vgabios-cirrus.bin | Bin 35840 -> 35840 bytes pc-bios/vgabios-stdvga.bin | Bin 0 -> 40448 bytes pc-bios/vgabios-vmware.bin | Bin 0 -> 40448 bytes pc-bios/vgabios.bin | Bin 38400 -> 40448 bytes roms/vgabios | 2 +- 6 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 pc-bios/vgabios-stdvga.bin create mode 100644 pc-bios/vgabios-vmware.bin diff --git a/Makefile b/Makefile index 02698e976c..68963198f0 100644 --- a/Makefile +++ b/Makefile @@ -178,8 +178,9 @@ ar de en-us fi fr-be hr it lv nl pl ru th \ common de-ch es fo fr-ca hu ja mk nl-be pt sl tr ifdef INSTALL_BLOBS -BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ -openbios-sparc32 openbios-sparc64 openbios-ppc \ +BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \ +vgabios-stdvga.bin vgabios-vmware.bin \ +ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \ gpxe-eepro100-80861209.rom \ gpxe-eepro100-80861229.rom \ pxe-e1000.bin \ diff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin index 4fa8f99f7e0b4ffb492531f44703f49dc47c4837..424dd0c70c4a52e1a98d8a64ebf4aa382b85d5cf 100644 GIT binary patch delta 6146 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 ScgV-bT5N3_YhQ~{#lHdj>OxWg delta 6138 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 diff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin new file mode 100644 index 0000000000000000000000000000000000000000..5123c5fd070c14c1d11b432e5c522ec2d1026253 GIT binary patch literal 40448 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 M|4RRdCGfrf1$j7lD*ylh literal 0 HcmV?d00001 diff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin new file mode 100644 index 0000000000000000000000000000000000000000..5e8c06b2286de62f27aa72c79defab686cdb07b5 GIT binary patch literal 40448 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 M|5y4yEPp3Bn958SK z*L7eX7ekMv34Yuu75ylU&h0q)n%Nmrsh~fW*pG5%XC#tbx&1>V1ChK@WPgXt@(V>$ zc-sCdqG6TU<{=gGvNC%UXCBfaIibvMMl!k5pZ>ngQDq)VL25^tqkOG-C>6=JGRKqV zp|r}S^u01ian=M?#eB0xFuBQ`ibb0Rqp|C|{)W9`(sUZwp>KS9Qs zYVF`*yP0Q-KAD!ryN8tolk?gz%zd%06!pA|zsfJZW) z3Y(nb$aPl*qa#lq4lrkqC*Q&=nfc=yQ|fwE_6p*zlA{7EU?<$ojGl5S4byVy5D;M% z?MFc2h`A4Z0JCOKp8s8OLsv*W%PGvUNpjM%F07EIuR?XZ1uKyJszh|#8tj#0ix&(M z!57!U8?(pD_O1tE_TiXgMGajQ%H%E+tzBU>+IacYnnqrZzge%-a-ekG z8$u&z5)7P)zAXX22v!dO5T#ED{+hw)O8DH*L_dQfebdvK3~J)@OCU;r+JC0fI zsyjj#LT%8JHHAD2A7)L=De&4d!CWuXi%c40aC4c2&yb51Il?hVIm{7L3C)I}?CInu z$jF{7>&b%FtVaW8vVu;d@C~TW)`xG+5)<{tcUS#PmuA72*;8bXXTh!Pgh!ov7DkI< zSOzylj^+I&%*rv4L-2e~e1c^To84-*2gJBfi&`wLJiXD_$PWu4o-~)};Y^M;V>UCe z@xv?^rZ#~YNP`p>qAD9)H|i+dRkwvj9^i9`HN@1sE5SbtzxTj@lz`uadJnKk0&WTo z9-xu|Hr^dn!s6}npm_`x?jh%0D(NEPT_*%NTw%<_3#sSStwb9o+Soi^WX$HsU(*YP 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 delta 4820 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 diff --git a/roms/vgabios b/roms/vgabios index 6e62666cfc..19ea12c230 160000 --- a/roms/vgabios +++ b/roms/vgabios @@ -1 +1 @@ -Subproject commit 6e62666cfc19e7fd45dd0d7c3ad62fd8d0b5f67a +Subproject commit 19ea12c230ded95928ecaef0db47a82231c2e485 From 543f8e3468e6df32bfde8f84ac36d05a7604e082 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 6 May 2010 11:13:11 +0200 Subject: [PATCH 026/105] switch stdvga to pci vgabios Make stdvga provide the new vgabios binary (with pcibios support) using the PCI option rom bar. Seabios will happily load it from there. The new vga bios will also lookup the framebuffer address in pci config space, so the magic bochs lfb @ 0xe0000000 is not needed any more -> zap it. Without the patch: # dmesg | grep framebuffer vesafb: framebuffer at 0xe0000000, mapped to 0xf7e80000, using 1875k, total 8192k # lspci -vs2 00:02.0 VGA compatible controller: Technical Corp. Device 1111 (prog-if 00 [VGA controller]) Subsystem: Qumranet, Inc. Device 1100 Physical Slot: 2 Flags: fast devsel Memory at f0000000 (32-bit, prefetchable) [size=8M] Expansion ROM at [disabled] With patch applied: # dmesg | grep framebuffer vesafb: framebuffer at 0xf0000000, mapped to 0xf7e80000, using 1875k, total 8192k # lspci -vs2 00:02.0 VGA compatible controller: Technical Corp. Device 1111 (prog-if 00 [VGA controller]) Subsystem: Qumranet, Inc. Device 1100 Physical Slot: 2 Flags: fast devsel Memory at f0000000 (32-bit, prefetchable) [size=8M] Expansion ROM at f0800000 [disabled] [size=64K] cheers, Gerd Signed-off-by: Gerd Hoffmann --- hw/vga-pci.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/vga-pci.c b/hw/vga-pci.c index 2315f70bca..eef0e3c737 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -103,11 +103,10 @@ static int pci_vga_initfn(PCIDevice *dev) bios_total_size <<= 1; pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size, PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map); + } else { + if (dev->romfile == NULL) + dev->romfile = qemu_strdup("vgabios-stdvga.bin"); } - - vga_init_vbe(s); - /* ROM BIOS */ - rom_add_vga(VGABIOS_FILENAME); return 0; } From 4eccfec4943db1106c79a01069e18dd4f463219b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 6 May 2010 11:14:11 +0200 Subject: [PATCH 027/105] switch vmware_vga to pci vgabios Signed-off-by: Gerd Hoffmann --- hw/vmware_vga.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 3d25c14da9..9337fdbfef 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -114,14 +114,12 @@ struct pci_vmsvga_state_s { # define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT # define SVGA_IO_MUL 1 # define SVGA_FIFO_SIZE 0x10000 -# define SVGA_MEM_BASE 0xe0000000 # define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA2 #else # define SVGA_ID SVGA_ID_1 # define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT # define SVGA_IO_MUL 4 # define SVGA_FIFO_SIZE 0x10000 -# define SVGA_MEM_BASE 0xe0000000 # define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA #endif @@ -1219,10 +1217,6 @@ static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size) vga_init(&s->vga); vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga); - vga_init_vbe(&s->vga); - - rom_add_vga(VGABIOS_FILENAME); - vmsvga_reset(s); } @@ -1320,6 +1314,7 @@ static PCIDeviceInfo vmsvga_info = { .qdev.size = sizeof(struct pci_vmsvga_state_s), .qdev.vmsd = &vmstate_vmware_vga, .init = pci_vmsvga_initfn, + .romfile = "vgabios-vmware.bin", }; static void vmsvga_register(void) From 788954270d339b4b271e1a537a481e7068ba3591 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 15 Oct 2010 11:45:13 +0200 Subject: [PATCH 028/105] more stdvga cleanups. video.x is gone now. It was the only user of the vga bios_offset + bios_size logic. Zap it. Signed-off-by: Gerd Hoffmann --- hw/mips_malta.c | 2 +- hw/pc.c | 2 +- hw/pc.h | 3 +-- hw/ppc_newworld.c | 2 +- hw/ppc_oldworld.c | 2 +- hw/ppc_prep.c | 2 +- hw/sun4u.c | 2 +- hw/vga-pci.c | 42 ++++++++---------------------------------- hw/vga.c | 2 -- hw/vga_int.h | 2 -- 10 files changed, 15 insertions(+), 46 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 80260714ec..6be8aa70f9 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -977,7 +977,7 @@ void mips_malta_init (ram_addr_t ram_size, } else if (vmsvga_enabled) { pci_vmsvga_init(pci_bus); } else if (std_vga_enabled) { - pci_vga_init(pci_bus, 0, 0); + pci_vga_init(pci_bus); } } diff --git a/hw/pc.c b/hw/pc.c index 69b13bf62c..0e44df8103 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -993,7 +993,7 @@ void pc_vga_init(PCIBus *pci_bus) fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); } else if (std_vga_enabled) { if (pci_bus) { - pci_vga_init(pci_bus, 0, 0); + pci_vga_init(pci_bus); } else { isa_vga_init(); } diff --git a/hw/pc.h b/hw/pc.h index 63b0249f2f..68527902a5 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -154,8 +154,7 @@ enum vga_retrace_method { extern enum vga_retrace_method vga_retrace_method; int isa_vga_init(void); -int pci_vga_init(PCIBus *bus, - unsigned long vga_bios_offset, int vga_bios_size); +int pci_vga_init(PCIBus *bus); int isa_vga_mm_init(target_phys_addr_t vram_base, target_phys_addr_t ctrl_base, int it_shift); diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index 4369337b21..305b2d45e6 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -316,7 +316,7 @@ static void ppc_core99_init (ram_addr_t ram_size, machine_arch = ARCH_MAC99; } /* init basic PC hardware */ - pci_vga_init(pci_bus, 0, 0); + pci_vga_init(pci_bus); escc_mem_index = escc_init(0x80013000, pic[0x25], pic[0x24], serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index a2f9ddf738..5efc93dc10 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -227,7 +227,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, } pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs); pci_bus = pci_grackle_init(0xfec00000, pic); - pci_vga_init(pci_bus, 0, 0); + pci_vga_init(pci_bus); escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index a6915f7e68..b1f9cc74f8 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -694,7 +694,7 @@ static void ppc_prep_init (ram_addr_t ram_size, cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory); /* init basic PC hardware */ - pci_vga_init(pci_bus, 0, 0); + pci_vga_init(pci_bus); // openpic = openpic_init(0x00000000, 0xF0000000, 1); // pit = pit_init(0x40, i8259[0]); rtc_init(2000, NULL); diff --git a/hw/sun4u.c b/hw/sun4u.c index 45a46d673c..5292ac670f 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -767,7 +767,7 @@ static void sun4uv_init(ram_addr_t RAM_size, pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2, &pci_bus3); isa_mem_base = APB_PCI_IO_BASE; - pci_vga_init(pci_bus, 0, 0); + pci_vga_init(pci_bus); // XXX Should be pci_bus3 pci_ebus_init(pci_bus, -1); diff --git a/hw/vga-pci.c b/hw/vga-pci.c index eef0e3c737..b09789cd11 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -52,14 +52,11 @@ static void vga_map(PCIDevice *pci_dev, int region_num, { PCIVGAState *d = (PCIVGAState *)pci_dev; VGACommonState *s = &d->vga; - if (region_num == PCI_ROM_SLOT) { - cpu_register_physical_memory(addr, s->bios_size, s->bios_offset); - } else { - cpu_register_physical_memory(addr, s->vram_size, s->vram_offset); - s->map_addr = addr; - s->map_end = addr + s->vram_size; - vga_dirty_log_start(s); - } + + cpu_register_physical_memory(addr, s->vram_size, s->vram_offset); + s->map_addr = addr; + s->map_end = addr + s->vram_size; + vga_dirty_log_start(s); } static void pci_vga_write_config(PCIDevice *d, @@ -95,31 +92,12 @@ static int pci_vga_initfn(PCIDevice *dev) pci_register_bar(&d->dev, 0, VGA_RAM_SIZE, PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map); - if (s->bios_size) { - unsigned int bios_total_size; - /* must be a power of two */ - bios_total_size = 1; - while (bios_total_size < s->bios_size) - bios_total_size <<= 1; - pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size, - PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map); - } else { - if (dev->romfile == NULL) - dev->romfile = qemu_strdup("vgabios-stdvga.bin"); - } return 0; } -int pci_vga_init(PCIBus *bus, - unsigned long vga_bios_offset, int vga_bios_size) +int pci_vga_init(PCIBus *bus) { - PCIDevice *dev; - - dev = pci_create(bus, -1, "VGA"); - qdev_prop_set_uint32(&dev->qdev, "bios-offset", vga_bios_offset); - qdev_prop_set_uint32(&dev->qdev, "bios-size", vga_bios_size); - qdev_init_nofail(&dev->qdev); - + pci_create_simple(bus, -1, "VGA"); return 0; } @@ -129,11 +107,7 @@ static PCIDeviceInfo vga_info = { .qdev.vmsd = &vmstate_vga_pci, .init = pci_vga_initfn, .config_write = pci_vga_write_config, - .qdev.props = (Property[]) { - DEFINE_PROP_HEX32("bios-offset", PCIVGAState, vga.bios_offset, 0), - DEFINE_PROP_HEX32("bios-size", PCIVGAState, vga.bios_size, 0), - DEFINE_PROP_END_OF_LIST(), - } + .romfile = "vgabios-stdvga.bin", }; static void vga_register(void) diff --git a/hw/vga.c b/hw/vga.c index 966185e03b..c057f4f653 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1934,8 +1934,6 @@ void vga_common_reset(VGACommonState *s) s->map_addr = 0; s->map_end = 0; s->lfb_vram_mapped = 0; - s->bios_offset = 0; - s->bios_size = 0; s->sr_index = 0; memset(s->sr, '\0', sizeof(s->sr)); s->gr_index = 0; diff --git a/hw/vga_int.h b/hw/vga_int.h index 6a46a434fe..bc1327fbf6 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -112,8 +112,6 @@ typedef struct VGACommonState { uint32_t map_addr; uint32_t map_end; uint32_t lfb_vram_mapped; /* whether 0xa0000 is mapped as ram */ - uint32_t bios_offset; - uint32_t bios_size; uint32_t latch; uint8_t sr_index; uint8_t sr[256]; From 43849424cff82803011fad21074531a1101e514e Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 27 Oct 2010 20:03:43 +0200 Subject: [PATCH 029/105] tap: clear vhost_net backend on cleanup Frontends calling tap_get_vhost_net get an invalid pointer after the peer backend has been deleted. Jason Wang reports this leading to a crash in ack_features when we remove the vhost-net bakend of a virtio nic. The fix is simply to clear the backend pointer. Signed-off-by: Michael S. Tsirkin --- net/tap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/tap.c b/net/tap.c index 4afb314fde..937d9429eb 100644 --- a/net/tap.c +++ b/net/tap.c @@ -279,6 +279,7 @@ static void tap_cleanup(VLANClientState *nc) if (s->vhost_net) { vhost_net_cleanup(s->vhost_net); + s->vhost_net = NULL; } qemu_purge_queued_packets(nc); From f6584ee20338a74ef3b05b38b8f9dc5e7a7276a6 Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Sun, 24 Oct 2010 14:27:55 +0200 Subject: [PATCH 030/105] Add support for async page fault to qemu Add save/restore of MSR for migration and cpuid bit. Signed-off-by: Gleb Natapov Signed-off-by: Marcelo Tosatti --- target-i386/cpu.h | 1 + target-i386/cpuid.c | 2 +- target-i386/kvm.c | 14 ++++++++++++++ target-i386/machine.c | 26 ++++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 2440d6536c..06e40f3e49 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -681,6 +681,7 @@ typedef struct CPUX86State { #endif uint64_t system_time_msr; uint64_t wall_clock_msr; + uint64_t async_pf_en_msr; uint64_t tsc; diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c index 650a7192de..165045ec42 100644 --- a/target-i386/cpuid.c +++ b/target-i386/cpuid.c @@ -73,7 +73,7 @@ static const char *ext3_feature_name[] = { }; static const char *kvm_feature_name[] = { - "kvmclock", "kvm_nopiodelay", "kvm_mmu", NULL, NULL, NULL, NULL, NULL, + "kvmclock", "kvm_nopiodelay", "kvm_mmu", NULL, "kvm_asyncpf", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, diff --git a/target-i386/kvm.c b/target-i386/kvm.c index ae0a034ab0..7dfc357e42 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -161,6 +161,9 @@ struct kvm_para_features { #endif #ifdef KVM_CAP_PV_MMU { KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP }, +#endif +#ifdef KVM_CAP_ASYNC_PF + { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF }, #endif { -1, -1 } }; @@ -838,6 +841,9 @@ static int kvm_put_msrs(CPUState *env, int level) kvm_msr_entry_set(&msrs[n++], MSR_KVM_SYSTEM_TIME, env->system_time_msr); kvm_msr_entry_set(&msrs[n++], MSR_KVM_WALL_CLOCK, env->wall_clock_msr); +#ifdef KVM_CAP_ASYNC_PF + kvm_msr_entry_set(&msrs[n++], MSR_KVM_ASYNC_PF_EN, env->async_pf_en_msr); +#endif } #ifdef KVM_CAP_MCE if (env->mcg_cap) { @@ -1064,6 +1070,9 @@ static int kvm_get_msrs(CPUState *env) #endif msrs[n++].index = MSR_KVM_SYSTEM_TIME; msrs[n++].index = MSR_KVM_WALL_CLOCK; +#ifdef KVM_CAP_ASYNC_PF + msrs[n++].index = MSR_KVM_ASYNC_PF_EN; +#endif #ifdef KVM_CAP_MCE if (env->mcg_cap) { @@ -1135,6 +1144,11 @@ static int kvm_get_msrs(CPUState *env) } #endif break; +#ifdef KVM_CAP_ASYNC_PF + case MSR_KVM_ASYNC_PF_EN: + env->async_pf_en_msr = msrs[i].data; + break; +#endif } } diff --git a/target-i386/machine.c b/target-i386/machine.c index 5f8376c37b..d78eceb779 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -373,6 +373,24 @@ static int cpu_post_load(void *opaque, int version_id) return 0; } +static bool async_pf_msr_needed(void *opaque) +{ + CPUState *cpu = opaque; + + return cpu->async_pf_en_msr != 0; +} + +static const VMStateDescription vmstate_async_pf_msr = { + .name = "cpu/async_pf_msr", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT64(async_pf_en_msr, CPUState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_cpu = { .name = "cpu", .version_id = CPU_SAVE_VERSION, @@ -475,6 +493,14 @@ static const VMStateDescription vmstate_cpu = { VMSTATE_YMMH_REGS_VARS(ymmh_regs, CPUState, CPU_NB_REGS, 12), VMSTATE_END_OF_LIST() /* The above list is not sorted /wrt version numbers, watch out! */ + }, + .subsections = (VMStateSubsection []) { + { + .vmsd = &vmstate_async_pf_msr, + .needed = async_pf_msr_needed, + } , { + /* empty */ + } } }; From 27a6375de3edece2e5d115847d54c01e52331f7e Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 31 Oct 2010 19:06:47 +0200 Subject: [PATCH 031/105] tap: make set_offload a nop after netdev cleanup virtio-net expects set_offload to succeed after peer cleanup. Since we don't have an open fd anymore, make it so. Fixes warning about the failure of offload setting. Reported-by: Jason Wang Signed-off-by: Michael S. Tsirkin --- net/tap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/tap.c b/net/tap.c index 937d9429eb..eada34ac2b 100644 --- a/net/tap.c +++ b/net/tap.c @@ -269,8 +269,11 @@ void tap_set_offload(VLANClientState *nc, int csum, int tso4, int tso6, int ecn, int ufo) { TAPState *s = DO_UPCAST(TAPState, nc, nc); + if (s->fd < 0) { + return; + } - return tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo); + tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo); } static void tap_cleanup(VLANClientState *nc) @@ -290,6 +293,7 @@ static void tap_cleanup(VLANClientState *nc) tap_read_poll(s, 0); tap_write_poll(s, 0); close(s->fd); + s->fd = -1; } static void tap_poll(VLANClientState *nc, bool enable) From 1f892feb37dabedbb2492c6b499b0c1b22631a1f Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 5 Nov 2010 14:52:08 -0600 Subject: [PATCH 032/105] e1000: Fix TCP checksum overflow with TSO When adding the length to the pseudo header, we're not properly accounting for overflow. From: Mark Wu Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/e1000.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/e1000.c b/hw/e1000.c index 532efdc27d..677165f830 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -384,9 +384,12 @@ xmit_seg(E1000State *s) } else // UDP cpu_to_be16wu((uint16_t *)(tp->data+css+4), len); if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { + unsigned int phsum; // add pseudo-header length before checksum calculation sp = (uint16_t *)(tp->data + tp->tucso); - cpu_to_be16wu(sp, be16_to_cpup(sp) + len); + phsum = be16_to_cpup(sp) + len; + phsum = (phsum >> 16) + (phsum & 0xffff); + cpu_to_be16wu(sp, phsum); } tp->tso_frames++; } From a6a9239cd87d1bcdade909cf71413686fb70f8d0 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 4 Oct 2010 15:53:11 -0600 Subject: [PATCH 033/105] PCI: Bus number from the bridge, not the device pcibus_dev_print() was erroneously retrieving the device bus number from the secondary bus number offset of the device instead of the bridge above the device. This ends of landing in the 2nd byte of the 3rd BAR for devices, which thankfully is usually zero. Note: pcibus_get_dev_path() copied this code, inheriting the same bug. pcibus_get_dev_path() is used for ramblock naming, so changing it can effect migration. However, I've only seen this byte be non-zero for an assigned device, which can't migrate anyway, so hopefully we won't run into any issues. This patch does not touch pcibus_get_dev_path, as bus number is guest assigned for nested buses, so using it for migration is broken anyway. Fix it properly later. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 962886e767..8f6fcf8a53 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1806,8 +1806,7 @@ static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, " "pci id %04x:%04x (sub %04x:%04x)\n", - indent, "", ctxt, - d->config[PCI_SECONDARY_BUS], + indent, "", ctxt, pci_bus_num(d->bus), PCI_SLOT(d->devfn), PCI_FUNC(d->devfn), pci_get_word(d->config + PCI_VENDOR_ID), pci_get_word(d->config + PCI_DEVICE_ID), From 4cff0a5994d0300e6e77e90d3354aa517a120539 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 12 Nov 2010 16:21:35 +0900 Subject: [PATCH 034/105] pci: allow hotplug removal of cold-plugged devices This patch fixes hot unplug of cold plugged devices (those present at system start), which got broken by 5beb8ad503c88a76f2b8106c3b74b4ce485a60e1 . Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin Acked-by: Cam Macdonell Tested-by: Cam Macdonell Reported-by: Cam Macdonell . --- hw/acpi_piix4.c | 14 ++++++++++---- hw/pci.c | 10 +++++++--- hw/pci.h | 10 +++++++++- hw/pcie.c | 10 ++++++---- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 66c7885d62..f549089a55 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -585,7 +585,8 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val) PIIX4_DPRINTF("pciej write %x <== %d\n", addr, val); } -static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state); +static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, + PCIHotplugState state); static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) { @@ -615,18 +616,23 @@ static void disable_device(PIIX4PMState *s, int slot) s->pci0_status.down |= (1 << slot); } -static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state) +static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, + PCIHotplugState state) { int slot = PCI_SLOT(dev->devfn); PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, DO_UPCAST(PCIDevice, qdev, qdev)); - if (!dev->qdev.hotplugged) + /* Don't send event when device is enabled during qemu machine creation: + * it is present on boot, no hotplug event is necessary. We do send an + * event when the device is disabled later. */ + if (state == PCI_COLDPLUG_ENABLED) { return 0; + } s->pci0_status.up = 0; s->pci0_status.down = 0; - if (state) { + if (state == PCI_HOTPLUG_ENABLED) { enable_device(s, slot); } else { disable_device(s, slot); diff --git a/hw/pci.c b/hw/pci.c index 8f6fcf8a53..438c0d1691 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1558,8 +1558,11 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base) pci_add_option_rom(pci_dev); if (bus->hotplug) { - /* lower layer must check qdev->hotplugged */ - rc = bus->hotplug(bus->hotplug_qdev, pci_dev, 1); + /* Let buses differentiate between hotplug and when device is + * enabled during qemu machine creation. */ + rc = bus->hotplug(bus->hotplug_qdev, pci_dev, + qdev->hotplugged ? PCI_HOTPLUG_ENABLED: + PCI_COLDPLUG_ENABLED); if (rc != 0) { int r = pci_unregister_device(&pci_dev->qdev); assert(!r); @@ -1573,7 +1576,8 @@ static int pci_unplug_device(DeviceState *qdev) { PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev); - return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, 0); + return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, + PCI_HOTPLUG_DISABLED); } void pci_qdev_register(PCIDeviceInfo *info) diff --git a/hw/pci.h b/hw/pci.h index 7100804e7c..09b3e4c033 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -214,7 +214,15 @@ int pci_device_load(PCIDevice *s, QEMUFile *f); typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level); typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); -typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, int state); + +typedef enum { + PCI_HOTPLUG_DISABLED, + PCI_HOTPLUG_ENABLED, + PCI_COLDPLUG_ENABLED, +} PCIHotplugState; + +typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, + PCIHotplugState state); void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, const char *name, int devfn_min); PCIBus *pci_bus_new(DeviceState *parent, const char *name, int devfn_min); diff --git a/hw/pcie.c b/hw/pcie.c index 35918f7c2c..f461c1cfbe 100644 --- a/hw/pcie.c +++ b/hw/pcie.c @@ -192,14 +192,16 @@ static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event) } static int pcie_cap_slot_hotplug(DeviceState *qdev, - PCIDevice *pci_dev, int state) + PCIDevice *pci_dev, PCIHotplugState state) { PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev); uint8_t *exp_cap = d->config + d->exp.exp_cap; uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); - if (!pci_dev->qdev.hotplugged) { - assert(state); /* this case only happens at machine creation. */ + /* Don't send event when device is enabled during qemu machine creation: + * it is present on boot, no hotplug event is necessary. We do send an + * event when the device is disabled later. */ + if (state == PCI_COLDPLUG_ENABLED) { pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDS); return 0; @@ -219,7 +221,7 @@ static int pcie_cap_slot_hotplug(DeviceState *qdev, */ assert(PCI_FUNC(pci_dev->devfn) == 0); - if (state) { + if (state == PCI_HOTPLUG_ENABLED) { pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDS); pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); From b538e53ee7e8b9e2920d3286b480276cef209fd4 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 5 Nov 2010 16:01:29 -0600 Subject: [PATCH 035/105] apic: Don't iterate past last used apic local_apics are allocated sequentially and never removed, so we can stop any iterations that go to MAX_APICS as soon as we hit the first NULL. Looking at a small guest running a virtio-net workload with oprofile, this drops apic_get_delivery_bitmask() from #3 in the profile to down in the noise. Signed-off-by: Alex Williamson Signed-off-by: Anthony Liguori --- hw/apic.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/apic.c b/hw/apic.c index 63d62c7553..5f4a87c807 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -437,6 +437,8 @@ static int apic_find_dest(uint8_t dest) apic = local_apics[i]; if (apic && apic->id == dest) return i; + if (!apic) + break; } return -1; @@ -472,6 +474,8 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, set_bit(deliver_bitmask, i); } } + } else { + break; } } } From 9696846600cac4bd0dfd6835e45e69d25ec2b11e Mon Sep 17 00:00:00 2001 From: Adam Lackorzynski Date: Thu, 4 Nov 2010 23:22:15 +0100 Subject: [PATCH 036/105] multiboot: Prevent loading of x86_64 images A via -kernel supplied x86_64 ELF image is being started in 32bit mode. Detect and exit if a 64bit image has been supplied. Signed-off-by: Adam Lackorzynski Acked-by: Alexander Graf Signed-off-by: Anthony Liguori --- hw/multiboot.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/multiboot.c b/hw/multiboot.c index f9097a2f60..e710bbb948 100644 --- a/hw/multiboot.c +++ b/hw/multiboot.c @@ -171,6 +171,12 @@ int load_multiboot(void *fw_cfg, uint64_t elf_low, elf_high; int kernel_size; fclose(f); + + if (((struct elf64_hdr*)header)->e_machine == EM_X86_64) { + fprintf(stderr, "Cannot load x86-64 image, give a 32bit one.\n"); + exit(1); + } + kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry, &elf_low, &elf_high, 0, ELF_MACHINE, 0); if (kernel_size < 0) { From 4addb1127f6327c7ebcbd150a6b589e7677adc92 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 8 Nov 2010 19:33:07 +0000 Subject: [PATCH 037/105] Add a DTrace tracing backend targetted for SystemTAP compatability This introduces a new tracing backend that targets the SystemTAP implementation of DTrace userspace tracing. The core functionality should be applicable and standard across any DTrace implementation on Solaris, OS-X, *BSD, but the Makefile rules will likely need some small additional changes to cope with OS specific build requirements. This backend builds a little differently from the other tracing backends. Specifically there is no 'trace.c' file, because the 'dtrace' command line tool generates a '.o' file directly from the dtrace probe definition file. The probe definition is usually named with a '.d' extension but QEMU uses '.d' files for its external makefile dependancy tracking, so this uses '.dtrace' as the extension for the probe definition file. The 'tracetool' program gains the ability to generate a trace.h file for DTrace, and also to generate the trace.d file containing the dtrace probe definition. Example usage of a dtrace probe in systemtap looks like: probe process("qemu").mark("qemu_malloc") { printf("Malloc %d %p\n", $arg1, $arg2); } * .gitignore: Ignore trace-dtrace.* * Makefile: Extra rules for generating DTrace files * Makefile.obj: Don't build trace.o for DTrace, use trace-dtrace.o generated by 'dtrace' instead * tracetool: Support for generating DTrace data files Signed-off-by: Daniel P. Berrange Signed-off-by: Anthony Liguori --- .gitignore | 2 + Makefile | 23 ++++++++++ Makefile.objs | 4 ++ configure | 14 +++++- tracetool | 116 +++++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 148 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index a43e4d1d98..3efb4ecc13 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ config-host.* config-target.* trace.h trace.c +trace-dtrace.h +trace-dtrace.dtrace *-timestamp *-softmmu *-darwin-user diff --git a/Makefile b/Makefile index 68963198f0..747e47c834 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,9 @@ # Makefile for QEMU. GENERATED_HEADERS = config-host.h trace.h qemu-options.def +ifeq ($(TRACE_BACKEND),dtrace) +GENERATED_HEADERS += trace-dtrace.h +endif ifneq ($(wildcard config-host.mak),) # Put the all: rule here so that config-host.mak can contain dependencies. @@ -108,7 +111,11 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS) bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS) +ifeq ($(TRACE_BACKEND),dtrace) +trace.h: trace.h-timestamp trace-dtrace.h +else trace.h: trace.h-timestamp +endif trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h") @cmp -s $@ trace.h || cp $@ trace.h @@ -120,6 +127,20 @@ trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak trace.o: trace.c $(GENERATED_HEADERS) +trace-dtrace.h: trace-dtrace.dtrace + $(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h") + +# Normal practice is to name DTrace probe file with a '.d' extension +# but that gets picked up by QEMU's Makefile as an external dependancy +# rule file. So we use '.dtrace' instead +trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp +trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak + $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace") + @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace + +trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS) + $(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o") + simpletrace.o: simpletrace.c $(GENERATED_HEADERS) version.o: $(SRC_PATH)/version.rc config-host.mak @@ -157,6 +178,8 @@ clean: rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d rm -f qemu-img-cmds.h rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp + rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp + rm -f trace-dtrace.h trace-dtrace.h-timestamp $(MAKE) -C tests clean for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \ if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \ diff --git a/Makefile.objs b/Makefile.objs index 15569afa14..23b17cefad 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -286,11 +286,15 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o ###################################################################### # trace +ifeq ($(TRACE_BACKEND),dtrace) +trace-obj-y = trace-dtrace.o +else trace-obj-y = trace.o ifeq ($(TRACE_BACKEND),simple) trace-obj-y += simpletrace.o user-obj-y += qemu-timer-common.o endif +endif vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) diff --git a/configure b/configure index 7025d2bf0d..f8dad3eb00 100755 --- a/configure +++ b/configure @@ -929,7 +929,7 @@ echo " --enable-docs enable documentation build" echo " --disable-docs disable documentation build" echo " --disable-vhost-net disable vhost-net acceleration support" echo " --enable-vhost-net enable vhost-net acceleration support" -echo " --trace-backend=B Trace backend nop simple ust" +echo " --trace-backend=B Trace backend nop simple ust dtrace" echo " --trace-file=NAME Full PATH,NAME of file to store traces" echo " Default:trace-" echo " --disable-spice disable spice" @@ -2193,6 +2193,18 @@ EOF exit 1 fi fi + +########################################## +# For 'dtrace' backend, test if 'dtrace' command is present +if test "$trace_backend" = "dtrace"; then + if ! has 'dtrace' ; then + echo + echo "Error: dtrace command is not found in PATH $PATH" + echo + exit 1 + fi +fi + ########################################## # End of CC checks # After here, no more $cc or $ld runs diff --git a/tracetool b/tracetool index 701085837f..5b6636ac27 100755 --- a/tracetool +++ b/tracetool @@ -20,10 +20,12 @@ Backends: --nop Tracing disabled --simple Simple built-in backend --ust LTTng User Space Tracing backend + --dtrace DTrace/SystemTAP backend Output formats: -h Generate .h file -c Generate .c file + -d Generate .d file (DTrace only) EOF exit 1 } @@ -46,8 +48,9 @@ get_args() # Get the argument name list of a trace event get_argnames() { - local nfields field name + local nfields field name sep nfields=0 + sep="$2" for field in $(get_args "$1"); do nfields=$((nfields + 1)) @@ -58,7 +61,7 @@ get_argnames() name=${field%,} test "$field" = "$name" && continue - printf "%s" "$name, " + printf "%s%s " $name $sep done # Last argument name @@ -73,7 +76,7 @@ get_argc() { local name argc argc=0 - for name in $(get_argnames "$1"); do + for name in $(get_argnames "$1", ","); do argc=$((argc + 1)) done echo $argc @@ -154,7 +157,7 @@ EOF cast_args_to_uint64_t() { local arg - for arg in $(get_argnames "$1"); do + for arg in $(get_argnames "$1", ","); do printf "%s" "(uint64_t)(uintptr_t)$arg" done } @@ -247,7 +250,7 @@ linetoh_ust() local name args argnames name=$(get_name "$1") args=$(get_args "$1") - argnames=$(get_argnames "$1") + argnames=$(get_argnames "$1", ",") cat < Date: Mon, 8 Nov 2010 19:33:08 +0000 Subject: [PATCH 038/105] Add support for generating a systemtap tapset static probes This introduces generation of a qemu.stp/qemu-system-XXX.stp files which provides tapsets with friendly names for static probes & their arguments. Instead of probe process("qemu").mark("qemu_malloc") { printf("Malloc %d %p\n", $arg1, $arg2); } It is now possible todo probe qemu.system.i386.qemu_malloc { printf("Malloc %d %p\n", size, ptr); } There is one tapset defined per target arch. * Makefile: Generate a qemu.stp file for systemtap * tracetool: Support for generating systemtap tapsets Signed-off-by: Daniel P. Berrange Signed-off-by: Anthony Liguori --- Makefile.target | 19 +++++++++- configure | 7 ++++ tracetool | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index 91e6e74399..a5e6410cec 100644 --- a/Makefile.target +++ b/Makefile.target @@ -40,7 +40,20 @@ kvm.o kvm-all.o vhost.o vhost_net.o: QEMU_CFLAGS+=$(KVM_CFLAGS) config-target.h: config-target.h-timestamp config-target.h-timestamp: config-target.mak -all: $(PROGS) +ifdef CONFIG_SYSTEMTAP_TRACE +trace: $(QEMU_PROG).stp + +$(QEMU_PROG).stp: + $(call quiet-command,sh $(SRC_PATH)/tracetool \ + --$(TRACE_BACKEND) \ + --bindir $(bindir) \ + --target $(TARGET_ARCH) \ + -s < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).stp") +else +trace: +endif + +all: $(PROGS) trace # Dummy command so that make thinks it has done something @true @@ -348,6 +361,10 @@ ifneq ($(STRIP),) $(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS)) endif endif +ifdef CONFIG_SYSTEMTAP_TRACE + $(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset" + $(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(datadir)/../systemtap/tapset" +endif # Include automatically generated dependency files -include $(wildcard *.d */*.d) diff --git a/configure b/configure index f8dad3eb00..e560f878a3 100755 --- a/configure +++ b/configure @@ -2192,6 +2192,10 @@ EOF echo exit 1 fi + trace_backend_stap="no" + if has 'stap' ; then + trace_backend_stap="yes" + fi fi ########################################## @@ -2645,6 +2649,9 @@ fi if test "$trace_backend" = "simple"; then trace_file="\"$trace_file-%u\"" fi +if test "$trace_backend" = "dtrace" -a "$trace_backend_stap" = "yes" ; then + echo "CONFIG_SYSTEMTAP_TRACE=y" >> $config_host_mak +fi echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak echo "TOOLS=$tools" >> $config_host_mak diff --git a/tracetool b/tracetool index 5b6636ac27..d797ab79a3 100755 --- a/tracetool +++ b/tracetool @@ -26,6 +26,12 @@ Output formats: -h Generate .h file -c Generate .c file -d Generate .d file (DTrace only) + -s Generate .stp file (DTrace with SystemTAP only) + +Options: + --bindir [bindir] QEMU binary install location + --target [arch] QEMU target architecture + EOF exit 1 } @@ -390,6 +396,54 @@ linetod_end_dtrace() EOF } +linetos_begin_dtrace() +{ + return +} + +linetos_dtrace() +{ + local name args arglist state + name=$(get_name "$1") + args=$(get_args "$1") + arglist=$(get_argnames "$1", "") + state=$(get_state "$1") + if [ "$state" = "0" ] ; then + name=${name##disable } + fi + + if [ "$target" = "i386" ] + then + binary="qemu" + else + binary="qemu-system-$target" + fi + + # Define prototype for probe arguments + cat < Date: Tue, 9 Nov 2010 09:36:53 +0200 Subject: [PATCH 039/105] Out off array access in usb-net Properly check array bounds before accessing array element. Signed-off-by: Gleb Natapov Signed-off-by: Anthony Liguori --- hw/usb-net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb-net.c b/hw/usb-net.c index 70f9263291..58c672f426 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1142,7 +1142,7 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value, break; default: - if (usb_net_stringtable[value & 0xff]) { + if (ARRAY_SIZE(usb_net_stringtable) > (value & 0xff)) { ret = set_usb_string(data, usb_net_stringtable[value & 0xff]); break; From 43ad7e3e986dea82831debad68e68cff552b6746 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Thu, 11 Nov 2010 16:10:04 +0100 Subject: [PATCH 040/105] Add missing braces This patch adds missing braces around if/else statements that call macros which are likely to result in errors if the macro is changed. It also makes the code comply better with CODING_STYLE. Signed-off-by: Jes Sorensen Signed-off-by: Anthony Liguori --- hw/e1000.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/hw/e1000.c b/hw/e1000.c index 677165f830..7811699ea9 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -447,9 +447,10 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) // data descriptor tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8; tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0; - } else + } else { // legacy descriptor tp->cptse = 0; + } if (vlan_enabled(s) && is_vlan_txd(txd_lower) && (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) { @@ -685,8 +686,9 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size) (void *)(buf + vlan_offset), size); desc.length = cpu_to_le16(size + fcs_len(s)); desc.status |= E1000_RXD_STAT_EOP|E1000_RXD_STAT_IXSM; - } else // as per intel docs; skip descriptors with null buf addr + } else { // as per intel docs; skip descriptors with null buf addr DBGOUT(RX, "Null RX descriptor!!\n"); + } cpu_physical_memory_write(base, (void *)&desc, sizeof(desc)); if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN]) @@ -858,13 +860,14 @@ e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) #ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val); #endif - if (index < NWRITEOPS && macreg_writeops[index]) + if (index < NWRITEOPS && macreg_writeops[index]) { macreg_writeops[index](s, index, val); - else if (index < NREADOPS && macreg_readops[index]) + } else if (index < NREADOPS && macreg_readops[index]) { DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04x\n", index<<2, val); - else + } else { DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08x\n", index<<2, val); + } } static void From 0f5160d1ea8bcd69d539f8a87a1b350d98fa5d52 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 10 Nov 2010 10:06:23 +0100 Subject: [PATCH 041/105] usb-linux: Store devpath into USBHostDevice when usb_fs_type == USB_FS_SYS This allows us to recreate the sysfspath used during scanning later (which will be used in a later patch in this series). Signed-off-by: Anthony Liguori --- usb-linux.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/usb-linux.c b/usb-linux.c index c3c38ec249..0b154c238f 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -62,8 +62,8 @@ struct usb_ctrlrequest { uint16_t wLength; }; -typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id, - int vendor_id, int product_id, +typedef int USBScanFunc(void *opaque, int bus_num, int addr, int devpath, + int class_id, int vendor_id, int product_id, const char *product_name, int speed); //#define DEBUG @@ -141,6 +141,7 @@ typedef struct USBHostDevice { /* Host side address */ int bus_num; int addr; + int devpath; struct USBAutoFilter match; QTAILQ_ENTRY(USBHostDevice) next; @@ -885,7 +886,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s) } static int usb_host_open(USBHostDevice *dev, int bus_num, - int addr, const char *prod_name) + int addr, int devpath, const char *prod_name) { int fd = -1, ret; struct usbdevfs_connectinfo ci; @@ -911,6 +912,7 @@ static int usb_host_open(USBHostDevice *dev, int bus_num, dev->bus_num = bus_num; dev->addr = addr; + dev->devpath = devpath; dev->fd = fd; /* read the device description */ @@ -1173,7 +1175,7 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func) if (line[0] == 'T' && line[1] == ':') { if (device_count && (vendor_id || product_id)) { /* New device. Add the previously discovered device. */ - ret = func(opaque, bus_num, addr, class_id, vendor_id, + ret = func(opaque, bus_num, addr, 0, class_id, vendor_id, product_id, product_name, speed); if (ret) { goto the_end; @@ -1226,7 +1228,7 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func) } if (device_count && (vendor_id || product_id)) { /* Add the last device. */ - ret = func(opaque, bus_num, addr, class_id, vendor_id, + ret = func(opaque, bus_num, addr, 0, class_id, vendor_id, product_id, product_name, speed); } the_end: @@ -1275,7 +1277,7 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func) { DIR *dir = NULL; char line[1024]; - int bus_num, addr, speed, class_id, product_id, vendor_id; + int bus_num, addr, devpath, speed, class_id, product_id, vendor_id; int ret = 0; char product_name[512]; struct dirent *de; @@ -1292,7 +1294,9 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func) if (!strncmp(de->d_name, "usb", 3)) { tmpstr += 3; } - bus_num = atoi(tmpstr); + if (sscanf(tmpstr, "%d-%d", &bus_num, &devpath) < 1) { + goto the_end; + } if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) { goto the_end; @@ -1343,7 +1347,7 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func) speed = USB_SPEED_FULL; } - ret = func(opaque, bus_num, addr, class_id, vendor_id, + ret = func(opaque, bus_num, addr, devpath, class_id, vendor_id, product_id, product_name, speed); if (ret) { goto the_end; @@ -1434,7 +1438,7 @@ static int usb_host_scan(void *opaque, USBScanFunc *func) static QEMUTimer *usb_auto_timer; -static int usb_host_auto_scan(void *opaque, int bus_num, int addr, +static int usb_host_auto_scan(void *opaque, int bus_num, int addr, int devpath, int class_id, int vendor_id, int product_id, const char *product_name, int speed) { @@ -1470,7 +1474,7 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr, } DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr); - usb_host_open(s, bus_num, addr, product_name); + usb_host_open(s, bus_num, addr, devpath, product_name); } return 0; @@ -1630,7 +1634,7 @@ static void usb_info_device(Monitor *mon, int bus_num, int addr, int class_id, } static int usb_host_info_device(void *opaque, int bus_num, int addr, - int class_id, + int devpath, int class_id, int vendor_id, int product_id, const char *product_name, int speed) From 71d71bbdeb39544ac1602c5e307d9e14c78f9d5d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 10 Nov 2010 10:06:24 +0100 Subject: [PATCH 042/105] usb-linux: introduce a usb_linux_get_configuration function The next patch in this series introduces multiple ways to get the configuration dependent upon usb_fs_type, it is cleaner to put this into its own function. Signed-off-by: Anthony Liguori --- usb-linux.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/usb-linux.c b/usb-linux.c index 0b154c238f..111fe1c788 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -775,13 +775,11 @@ static int usb_host_handle_packet(USBDevice *s, USBPacket *p) } } -/* returns 1 on problem encountered or 0 for success */ -static int usb_linux_update_endp_table(USBHostDevice *s) +static int usb_linux_get_configuration(USBHostDevice *s) { - uint8_t *descriptors; - uint8_t devep, type, configuration, alt_interface; + uint8_t configuration; struct usb_ctrltransfer ct; - int interface, ret, length, i; + int ret; ct.bRequestType = USB_DIR_IN; ct.bRequest = USB_REQ_GET_CONFIGURATION; @@ -793,15 +791,31 @@ static int usb_linux_update_endp_table(USBHostDevice *s) ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct); if (ret < 0) { - perror("usb_linux_update_endp_table"); - return 1; + perror("usb_linux_get_configuration"); + return -1; } /* in address state */ if (configuration == 0) { - return 1; + return -1; } + return configuration; +} + +/* returns 1 on problem encountered or 0 for success */ +static int usb_linux_update_endp_table(USBHostDevice *s) +{ + uint8_t *descriptors; + uint8_t devep, type, configuration, alt_interface; + struct usb_ctrltransfer ct; + int interface, ret, length, i; + + i = usb_linux_get_configuration(s); + if (i < 0) + return 1; + configuration = i; + /* get the desired configuration, interface, and endpoint descriptors * from device description */ descriptors = &s->descr[18]; From 2cc59d8cb0ebcfa9cf3476c0528e50478997ab0c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 10 Nov 2010 10:06:25 +0100 Subject: [PATCH 043/105] usb-linux: Get the active configuration from sysfs rather then asking the dev Some devices seem to choke on receiving a USB_REQ_GET_CONFIGURATION ctrl msg (witnessed with a digital picture frame usb id 1908:1320). When usb_fs_type == USB_FS_SYS, the active configuration can be read directly from sysfs, which allows using this device through qemu's usb redirection. More in general it seems a good idea to not send needless control msg's to devices, esp. as the code in question is called every time a set_interface is done. Which happens multiple times during virtual machine startup, and when device drivers are activating the usb device. Signed-off-by: Anthony Liguori --- usb-linux.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/usb-linux.c b/usb-linux.c index 111fe1c788..ccf70734e3 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -152,6 +152,8 @@ static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs) static int usb_host_close(USBHostDevice *dev); static int parse_filter(const char *spec, struct USBAutoFilter *f); static void usb_host_auto_check(void *unused); +static int usb_host_read_file(char *line, size_t line_size, + const char *device_file, const char *device_name); static int is_isoc(USBHostDevice *s, int ep) { @@ -781,6 +783,23 @@ static int usb_linux_get_configuration(USBHostDevice *s) struct usb_ctrltransfer ct; int ret; + if (usb_fs_type == USB_FS_SYS) { + char device_name[32], line[1024]; + int configuration; + + sprintf(device_name, "%d-%d", s->bus_num, s->devpath); + + if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue", + device_name)) { + goto usbdevfs; + } + if (sscanf(line, "%d", &configuration) != 1) { + goto usbdevfs; + } + return configuration; + } + +usbdevfs: ct.bRequestType = USB_DIR_IN; ct.bRequest = USB_REQ_GET_CONFIGURATION; ct.wValue = 0; From 0290b57bdfec83ca78b6d119ea9847bb17943328 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 3 Nov 2010 14:29:44 +0000 Subject: [PATCH 044/105] Delete IOHandlers after potentially running them Since commit 4bed9837309e58d208183f81d8344996744292cf an .fd_read() handler that deletes its IOHandler is exposed to .fd_write() being called on the deleted IOHandler. This patch fixes deletion so that .fd_read() and .fd_write() are never called on an IOHandler that is marked for deletion. Signed-off-by: Stefan Hajnoczi Signed-off-by: Anthony Liguori --- vl.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/vl.c b/vl.c index c58583da48..9ee6479b7c 100644 --- a/vl.c +++ b/vl.c @@ -1249,16 +1249,17 @@ void main_loop_wait(int nonblocking) IOHandlerRecord *pioh; QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) { + if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) { + ioh->fd_read(ioh->opaque); + } + if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) { + ioh->fd_write(ioh->opaque); + } + + /* Do this last in case read/write handlers marked it for deletion */ if (ioh->deleted) { QLIST_REMOVE(ioh, next); qemu_free(ioh); - continue; - } - if (ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) { - ioh->fd_read(ioh->opaque); - } - if (ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) { - ioh->fd_write(ioh->opaque); } } } From b88417062d5f73e2e8137e94b360ca4412942f33 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Nov 2010 20:07:07 +0000 Subject: [PATCH 045/105] Fix compilation failure with simple trace when srcdir==objdir Fix a makefile error that meant that qemu would not compile if the source and object directories were the same. Signed-off-by: Peter Maydell Signed-off-by: Anthony Liguori --- Makefile.target | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Makefile.target b/Makefile.target index a5e6410cec..652c7d2a57 100644 --- a/Makefile.target +++ b/Makefile.target @@ -30,6 +30,7 @@ endif endif PROGS=$(QEMU_PROG) +STPFILES= ifndef CONFIG_HAIKU LIBS+=-lm @@ -41,19 +42,17 @@ config-target.h: config-target.h-timestamp config-target.h-timestamp: config-target.mak ifdef CONFIG_SYSTEMTAP_TRACE -trace: $(QEMU_PROG).stp +STPFILES+=$(QEMU_PROG).stp $(QEMU_PROG).stp: $(call quiet-command,sh $(SRC_PATH)/tracetool \ --$(TRACE_BACKEND) \ --bindir $(bindir) \ --target $(TARGET_ARCH) \ - -s < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).stp") -else -trace: + -s < $(SRC_PATH)/trace-events > $@," GEN $@") endif -all: $(PROGS) trace +all: $(PROGS) $(STPFILES) # Dummy command so that make thinks it has done something @true @@ -363,7 +362,7 @@ endif endif ifdef CONFIG_SYSTEMTAP_TRACE $(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset" - $(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(datadir)/../systemtap/tapset" + $(INSTALL_DATA) $(STPFILES) "$(DESTDIR)$(datadir)/../systemtap/tapset" endif # Include automatically generated dependency files From 67d4b0c1907455f42ad8cea445ff10b81b49eebc Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 5 Nov 2010 15:40:38 -0600 Subject: [PATCH 046/105] pc: e820 qemu_cfg tables need to be packed We can't let the compiler define the alignment for qemu_cfg data. Signed-off-by: Alex Williamson Signed-off-by: Anthony Liguori --- hw/pc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 0e44df8103..e7f7ac6b0e 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -75,12 +75,12 @@ struct e820_entry { uint64_t address; uint64_t length; uint32_t type; -}; +} __attribute((__packed__, __aligned__(4))); struct e820_table { uint32_t count; struct e820_entry entry[E820_NR_ENTRIES]; -}; +} __attribute((__packed__, __aligned__(4))); static struct e820_table e820_table; From 8ca209ad90bdb678932a6b18caf32b461dbe5eee Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Sun, 7 Nov 2010 20:57:00 -0700 Subject: [PATCH 047/105] pc: Fix e820 fw_cfg for big endian Signed-off-by: Alex Williamson Signed-off-by: Anthony Liguori --- hw/pc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index e7f7ac6b0e..c34d194c25 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -467,19 +467,19 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) { - int index = e820_table.count; + int index = le32_to_cpu(e820_table.count); struct e820_entry *entry; if (index >= E820_NR_ENTRIES) return -EBUSY; - entry = &e820_table.entry[index]; + entry = &e820_table.entry[index++]; - entry->address = address; - entry->length = length; - entry->type = type; + entry->address = cpu_to_le64(address); + entry->length = cpu_to_le64(length); + entry->type = cpu_to_le32(type); - e820_table.count++; - return e820_table.count; + e820_table.count = cpu_to_le32(index); + return index; } static void *bochs_bios_init(void) From 1d00a07de980ecf643c7d7699dfc48e94bec15ae Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 27 Oct 2010 17:43:34 -0200 Subject: [PATCH 048/105] QMP: Revamp the Python class example This commit simplifies and fixes a number of problems in the Python QEMUMonitorProtocol example class. It's almost a rewrite and it DOES BREAK the qmp-shell script (which is going to be fixed in the next commit). However, I'm not going to split this in different commits because it could get up to 10 commits, it's really not worth it for a simple demo class. Highlights: o TCP sockets support o QMP events support o Add documentation o Fix a number of unhandled errors o Simplify methods that send commands to the Monitor Signed-off-by: Luiz Capitulino --- QMP/qmp.py | 161 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 108 insertions(+), 53 deletions(-) diff --git a/QMP/qmp.py b/QMP/qmp.py index 4062f84f36..14ce8b0d05 100644 --- a/QMP/qmp.py +++ b/QMP/qmp.py @@ -1,6 +1,6 @@ # QEMU Monitor Protocol Python class # -# Copyright (C) 2009 Red Hat Inc. +# Copyright (C) 2009, 2010 Red Hat Inc. # # Authors: # Luiz Capitulino @@ -8,7 +8,9 @@ # This work is licensed under the terms of the GNU GPL, version 2. See # the COPYING file in the top-level directory. -import socket, json +import json +import errno +import socket class QMPError(Exception): pass @@ -16,61 +18,114 @@ class QMPError(Exception): class QMPConnectError(QMPError): pass +class QMPCapabilitiesError(QMPError): + pass + class QEMUMonitorProtocol: - def connect(self): - self.sock.connect(self.filename) - data = self.__json_read() - if data == None: - raise QMPConnectError - if not data.has_key('QMP'): - raise QMPConnectError - return data['QMP']['capabilities'] + def __init__(self, address): + """ + Create a QEMUMonitorProtocol class. - def close(self): - self.sock.close() + @param address: QEMU address, can be either a unix socket path (string) + or a tuple in the form ( address, port ) for a TCP + connection + @note No connection is established, this is done by the connect() method + """ + self.__events = [] + self.__address = address + self.__sock = self.__get_sock() + self.__sockfile = self.__sock.makefile() - def send_raw(self, line): - self.sock.send(str(line)) - return self.__json_read() - - def send(self, cmdline): - cmd = self.__build_cmd(cmdline) - self.__json_send(cmd) - resp = self.__json_read() - if resp == None: - return - elif resp.has_key('error'): - return resp['error'] + def __get_sock(self): + if isinstance(self.__address, tuple): + family = socket.AF_INET else: - return resp['return'] - - def __build_cmd(self, cmdline): - cmdargs = cmdline.split() - qmpcmd = { 'execute': cmdargs[0], 'arguments': {} } - for arg in cmdargs[1:]: - opt = arg.split('=') - try: - value = int(opt[1]) - except ValueError: - value = opt[1] - qmpcmd['arguments'][opt[0]] = value - return qmpcmd - - def __json_send(self, cmd): - # XXX: We have to send any additional char, otherwise - # the Server won't read our input - self.sock.send(json.dumps(cmd) + ' ') + family = socket.AF_UNIX + return socket.socket(family, socket.SOCK_STREAM) def __json_read(self): - try: - while True: - line = json.loads(self.sockfile.readline()) - if not 'event' in line: - return line - except ValueError: - return + while True: + data = self.__sockfile.readline() + if not data: + return + resp = json.loads(data) + if 'event' in resp: + self.__events.append(resp) + continue + return resp - def __init__(self, filename): - self.filename = filename - self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.sockfile = self.sock.makefile() + error = socket.error + + def connect(self): + """ + Connect to the QMP Monitor and perform capabilities negotiation. + + @return QMP greeting dict + @raise socket.error on socket connection errors + @raise QMPConnectError if the greeting is not received + @raise QMPCapabilitiesError if fails to negotiate capabilities + """ + self.__sock.connect(self.__address) + greeting = self.__json_read() + if greeting is None or not greeting.has_key('QMP'): + raise QMPConnectError + # Greeting seems ok, negotiate capabilities + resp = self.cmd('qmp_capabilities') + if "return" in resp: + return greeting + raise QMPCapabilitiesError + + def cmd_obj(self, qmp_cmd): + """ + Send a QMP command to the QMP Monitor. + + @param qmp_cmd: QMP command to be sent as a Python dict + @return QMP response as a Python dict or None if the connection has + been closed + """ + try: + self.__sock.sendall(json.dumps(qmp_cmd)) + except socket.error, err: + if err[0] == errno.EPIPE: + return + raise socket.error(err) + return self.__json_read() + + def cmd(self, name, args=None, id=None): + """ + Build a QMP command and send it to the QMP Monitor. + + @param name: command name (string) + @param args: command arguments (dict) + @param id: command id (dict, list, string or int) + """ + qmp_cmd = { 'execute': name } + if args: + qmp_cmd['arguments'] = args + if id: + qmp_cmd['id'] = id + return self.cmd_obj(qmp_cmd) + + def get_events(self): + """ + Get a list of available QMP events. + """ + self.__sock.setblocking(0) + try: + self.__json_read() + except socket.error, err: + if err[0] == errno.EAGAIN: + # No data available + pass + self.__sock.setblocking(1) + return self.__events + + def clear_events(self): + """ + Clear current list of pending events. + """ + self.__events = [] + + def close(self): + self.__sock.close() + self.__sockfile.close() From 9bed0d0d1c5667a2e1124c8e44d31ac254ca2efb Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 27 Oct 2010 17:57:51 -0200 Subject: [PATCH 049/105] QMP: Revamp the qmp-shell script This commit updates the qmp-shell script to use the new interface introduced by the last commit. Additionally, the following fixes/features are also introduced: o TCP sockets support o Update/add documentation o Simple command-line completion o Fix a number of unhandled errors Signed-off-by: Luiz Capitulino --- QMP/qmp-shell | 179 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 144 insertions(+), 35 deletions(-) diff --git a/QMP/qmp-shell b/QMP/qmp-shell index a5b72d15d1..1fb7e767b0 100755 --- a/QMP/qmp-shell +++ b/QMP/qmp-shell @@ -1,8 +1,8 @@ #!/usr/bin/python # -# Simple QEMU shell on top of QMP +# Low-level QEMU shell on top of QMP. # -# Copyright (C) 2009 Red Hat Inc. +# Copyright (C) 2009, 2010 Red Hat Inc. # # Authors: # Luiz Capitulino @@ -14,60 +14,169 @@ # # Start QEMU with: # -# $ qemu [...] -monitor control,unix:./qmp,server +# # qemu [...] -qmp unix:./qmp-sock,server # # Run the shell: # -# $ qmp-shell ./qmp +# $ qmp-shell ./qmp-sock # # Commands have the following format: # -# < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ] +# < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ] # # For example: # -# (QEMU) info item=network +# (QEMU) device_add driver=e1000 id=net1 +# {u'return': {}} +# (QEMU) import qmp import readline -from sys import argv,exit +import sys -def shell_help(): - print 'bye exit from the shell' +class QMPCompleter(list): + def complete(self, text, state): + for cmd in self: + if cmd.startswith(text): + if not state: + return cmd + else: + state -= 1 -def main(): - if len(argv) != 2: - print 'qemu-shell ' - exit(1) +class QMPShellError(Exception): + pass - qemu = qmp.QEMUMonitorProtocol(argv[1]) - qemu.connect() - qemu.send("qmp_capabilities") +class QMPShellBadPort(QMPShellError): + pass - print 'Connected!' +# TODO: QMPShell's interface is a bit ugly (eg. _fill_completion() and +# _execute_cmd()). Let's design a better one. +class QMPShell(qmp.QEMUMonitorProtocol): + def __init__(self, address): + qmp.QEMUMonitorProtocol.__init__(self, self.__get_address(address)) + self._greeting = None + self._completer = None - while True: + def __get_address(self, arg): + """ + Figure out if the argument is in the port:host form, if it's not it's + probably a file path. + """ + addr = arg.split(':') + if len(addr) == 2: + try: + port = int(addr[1]) + except ValueError: + raise QMPShellBadPort + return ( addr[0], port ) + # socket path + return arg + + def _fill_completion(self): + for cmd in self.cmd('query-commands')['return']: + self._completer.append(cmd['name']) + + def __completer_setup(self): + self._completer = QMPCompleter() + self._fill_completion() + readline.set_completer(self._completer.complete) + readline.parse_and_bind("tab: complete") + # XXX: default delimiters conflict with some command names (eg. query-), + # clearing everything as it doesn't seem to matter + readline.set_completer_delims('') + + def __build_cmd(self, cmdline): + """ + Build a QMP input object from a user provided command-line in the + following format: + + < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ] + """ + cmdargs = cmdline.split() + qmpcmd = { 'execute': cmdargs[0], 'arguments': {} } + for arg in cmdargs[1:]: + opt = arg.split('=') + try: + value = int(opt[1]) + except ValueError: + value = opt[1] + qmpcmd['arguments'][opt[0]] = value + return qmpcmd + + def _execute_cmd(self, cmdline): try: - cmd = raw_input('(QEMU) ') + qmpcmd = self.__build_cmd(cmdline) + except: + print 'command format: ', + print '[arg-name1=arg1] ... [arg-nameN=argN]' + return True + resp = self.cmd_obj(qmpcmd) + if resp is None: + print 'Disconnected' + return False + print resp + return True + + def connect(self): + self._greeting = qmp.QEMUMonitorProtocol.connect(self) + self.__completer_setup() + + def show_banner(self, msg='Welcome to the QMP low-level shell!'): + print msg + version = self._greeting['QMP']['version']['qemu'] + print 'Connected to QEMU %d.%d.%d\n' % (version['major'],version['minor'],version['micro']) + + def read_exec_command(self, prompt): + """ + Read and execute a command. + + @return True if execution was ok, return False if disconnected. + """ + try: + cmdline = raw_input(prompt) except EOFError: print - break - if cmd == '': - continue - elif cmd == 'bye': - break - elif cmd == 'help': - shell_help() + return False + if cmdline == '': + for ev in self.get_events(): + print ev + self.clear_events() + return True else: - try: - resp = qemu.send(cmd) - if resp == None: - print 'Disconnected' - break - print resp - except IndexError: - print '-> command format: ', - print '[arg-name1=arg1] ... [arg-nameN=argN]' + return self._execute_cmd(cmdline) + +def die(msg): + sys.stderr.write('ERROR: %s\n' % msg) + sys.exit(1) + +def fail_cmdline(option=None): + if option: + sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option) + sys.stderr.write('qemu-shell [ -H ] < UNIX socket path> | < TCP address:port >\n') + sys.exit(1) + +def main(): + try: + if len(sys.argv) == 2: + qemu = QMPShell(sys.argv[1]) + else: + fail_cmdline() + except QMPShellBadPort: + die('bad port number in command-line') + + try: + qemu.connect() + except qmp.QMPConnectError: + die('Didn\'t get QMP greeting message') + except qmp.QMPCapabilitiesError: + die('Could not negotiate capabilities') + except qemu.error: + die('Could not connect to %s' % sys.argv[1]) + + qemu.show_banner() + while qemu.read_exec_command('(QEMU) '): + pass + qemu.close() if __name__ == '__main__': main() From 4cdbc094ca3865696c1456f1586818766bf9aae6 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 27 Oct 2010 18:03:01 -0200 Subject: [PATCH 050/105] QMP: Drop vm-info example script It's broken and not really useful, let's just drop it. Signed-off-by: Luiz Capitulino --- QMP/README | 5 +---- QMP/vm-info | 33 --------------------------------- 2 files changed, 1 insertion(+), 37 deletions(-) delete mode 100755 QMP/vm-info diff --git a/QMP/README b/QMP/README index 80503f2d7a..c95a08c234 100644 --- a/QMP/README +++ b/QMP/README @@ -19,10 +19,7 @@ o qmp-spec.txt QEMU Monitor Protocol current specification o qmp-commands.txt QMP supported commands (auto-generated at build-time) o qmp-events.txt List of available asynchronous events -There are also two simple Python scripts available: - -o qmp-shell A shell -o vm-info Show some information about the Virtual Machine +There is also a simple Python script called 'qmp-shell' available. IMPORTANT: It's strongly recommended to read the 'Stability Considerations' section in the qmp-commands.txt file before making any serious use of QMP. diff --git a/QMP/vm-info b/QMP/vm-info deleted file mode 100755 index be5b03843c..0000000000 --- a/QMP/vm-info +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/python -# -# Print Virtual Machine information -# -# Usage: -# -# Start QEMU with: -# -# $ qemu [...] -monitor control,unix:./qmp,server -# -# Run vm-info: -# -# $ vm-info ./qmp -# -# Luiz Capitulino - -import qmp -from sys import argv,exit - -def main(): - if len(argv) != 2: - print 'vm-info ' - exit(1) - - qemu = qmp.QEMUMonitorProtocol(argv[1]) - qemu.connect() - qemu.send("qmp_capabilities") - - for cmd in [ 'version', 'kvm', 'status', 'uuid', 'balloon' ]: - print cmd + ': ' + str(qemu.send('query-' + cmd)) - -if __name__ == '__main__': - main() From 999bd67c879cbd8bf0fe2b4ff0fb308a9a48ec72 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 22 Oct 2010 16:09:05 -0200 Subject: [PATCH 051/105] qemu-char: Introduce Memory driver This driver handles in-memory chardev operations. That's, all writes to this driver are stored in an internal buffer and it doesn't talk to the external world in any way. Right now it's very simple: it supports only writes. But it can be easily extended to support more operations. This is going to be used by the monitor's "HMP passthrough via QMP" feature, which needs to run monitor handlers without a backing device. Signed-off-by: Luiz Capitulino --- qemu-char.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++ qemu-char.h | 7 ++++++ 2 files changed, 71 insertions(+) diff --git a/qemu-char.c b/qemu-char.c index 88997f9d5a..edc9ad6851 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2275,6 +2275,70 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) return NULL; } +/***********************************************************/ +/* Memory chardev */ +typedef struct { + size_t outbuf_size; + size_t outbuf_capacity; + uint8_t *outbuf; +} MemoryDriver; + +static int mem_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + MemoryDriver *d = chr->opaque; + + /* TODO: the QString implementation has the same code, we should + * introduce a generic way to do this in cutils.c */ + if (d->outbuf_capacity < d->outbuf_size + len) { + /* grow outbuf */ + d->outbuf_capacity += len; + d->outbuf_capacity *= 2; + d->outbuf = qemu_realloc(d->outbuf, d->outbuf_capacity); + } + + memcpy(d->outbuf + d->outbuf_size, buf, len); + d->outbuf_size += len; + + return len; +} + +void qemu_chr_init_mem(CharDriverState *chr) +{ + MemoryDriver *d; + + d = qemu_malloc(sizeof(*d)); + d->outbuf_size = 0; + d->outbuf_capacity = 4096; + d->outbuf = qemu_mallocz(d->outbuf_capacity); + + memset(chr, 0, sizeof(*chr)); + chr->opaque = d; + chr->chr_write = mem_chr_write; +} + +QString *qemu_chr_mem_to_qs(CharDriverState *chr) +{ + MemoryDriver *d = chr->opaque; + return qstring_from_substr((char *) d->outbuf, 0, d->outbuf_size - 1); +} + +/* NOTE: this driver can not be closed with qemu_chr_close()! */ +void qemu_chr_close_mem(CharDriverState *chr) +{ + MemoryDriver *d = chr->opaque; + + qemu_free(d->outbuf); + qemu_free(chr->opaque); + chr->opaque = NULL; + chr->chr_write = NULL; +} + +size_t qemu_chr_mem_osize(const CharDriverState *chr) +{ + const MemoryDriver *d = chr->opaque; + return d->outbuf_size; +} + QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) { char host[65], port[33], width[8], height[8]; diff --git a/qemu-char.h b/qemu-char.h index 18ad12bb5d..e6ee6c4bc9 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -6,6 +6,7 @@ #include "qemu-option.h" #include "qemu-config.h" #include "qobject.h" +#include "qstring.h" /* character device */ @@ -100,6 +101,12 @@ CharDriverState *qemu_chr_open_eventfd(int eventfd); extern int term_escape_char; +/* memory chardev */ +void qemu_chr_init_mem(CharDriverState *chr); +void qemu_chr_close_mem(CharDriverState *chr); +QString *qemu_chr_mem_to_qs(CharDriverState *chr); +size_t qemu_chr_mem_osize(const CharDriverState *chr); + /* async I/O support */ int qemu_set_fd_handler2(int fd, From 0268d97c51207f35a5a01239ad92ef2c35dcd5ba Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 22 Oct 2010 10:08:02 -0200 Subject: [PATCH 052/105] QMP: Introduce Human Monitor passthrough command This command allows QMP clients to execute HMP commands. Please, check the documentation added to the qmp-commands.hx file for additional details about the interface and its limitations. Signed-off-by: Luiz Capitulino --- monitor.c | 38 ++++++++++++++++++++++++++++++++++++++ qmp-commands.hx | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/monitor.c b/monitor.c index 8cee35d77a..ec31eac8c1 100644 --- a/monitor.c +++ b/monitor.c @@ -491,6 +491,44 @@ static int do_qmp_capabilities(Monitor *mon, const QDict *params, return 0; } +static int mon_set_cpu(int cpu_index); +static void handle_user_command(Monitor *mon, const char *cmdline); + +static int do_hmp_passthrough(Monitor *mon, const QDict *params, + QObject **ret_data) +{ + int ret = 0; + Monitor *old_mon, hmp; + CharDriverState mchar; + + memset(&hmp, 0, sizeof(hmp)); + qemu_chr_init_mem(&mchar); + hmp.chr = &mchar; + + old_mon = cur_mon; + cur_mon = &hmp; + + if (qdict_haskey(params, "cpu-index")) { + ret = mon_set_cpu(qdict_get_int(params, "cpu-index")); + if (ret < 0) { + cur_mon = old_mon; + qerror_report(QERR_INVALID_PARAMETER_VALUE, "cpu-index", "a CPU number"); + goto out; + } + } + + handle_user_command(&hmp, qdict_get_str(params, "command-line")); + cur_mon = old_mon; + + if (qemu_chr_mem_osize(hmp.chr) > 0) { + *ret_data = QOBJECT(qemu_chr_mem_to_qs(hmp.chr)); + } + +out: + qemu_chr_close_mem(hmp.chr); + return ret; +} + static int compare_cmd(const char *name, const char *list) { const char *p, *pstart; diff --git a/qmp-commands.hx b/qmp-commands.hx index 793cf1c0f9..e5f157fe10 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -761,6 +761,51 @@ Example: Note: This command must be issued before issuing any other command. +EQMP + + { + .name = "human-monitor-command", + .args_type = "command-line:s,cpu-index:i?", + .params = "", + .help = "", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_hmp_passthrough, + }, + +SQMP +human-monitor-command +--------------------- + +Execute a Human Monitor command. + +Arguments: + +- command-line: the command name and its arguments, just like the + Human Monitor's shell (json-string) +- cpu-index: select the CPU number to be used by commands which access CPU + data, like 'info registers'. The Monitor selects CPU 0 if this + argument is not provided (json-int, optional) + +Example: + +-> { "execute": "human-monitor-command", "arguments": { "command-line": "info kvm" } } +<- { "return": "kvm support: enabled\r\n" } + +Notes: + +(1) The Human Monitor is NOT an stable interface, this means that command + names, arguments and responses can change or be removed at ANY time. + Applications that rely on long term stability guarantees should NOT + use this command + +(2) Limitations: + + o This command is stateless, this means that commands that depend + on state information (such as getfd) might not work + + o Commands that prompt the user for data (eg. 'cont' when the block + device is encrypted) don't currently work + 3. Query Commands ================= From 11217a757e7dda66fd2e78b10ea0cd8d6b290e42 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 28 Oct 2010 13:28:37 -0200 Subject: [PATCH 053/105] QMP/qmp-shell: Introduce HMP mode In which qmp-shell will exclusively use the HMP passthrough feature, this is useful for testing. Example: # ./qmp-shell -H qmp-sock Welcome to the HMP shell! Connected to QEMU 0.13.50 (QEMU) info network VLAN 0 devices: user.0: net=10.0.2.0, restricted=n e1000.0: model=e1000,macaddr=52:54:00:12:34:56 Devices not on any VLAN: (QEMU) Signed-off-by: Luiz Capitulino --- QMP/qmp-shell | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/QMP/qmp-shell b/QMP/qmp-shell index 1fb7e767b0..42dabc8c6d 100755 --- a/QMP/qmp-shell +++ b/QMP/qmp-shell @@ -145,6 +145,76 @@ class QMPShell(qmp.QEMUMonitorProtocol): else: return self._execute_cmd(cmdline) +class HMPShell(QMPShell): + def __init__(self, address): + QMPShell.__init__(self, address) + self.__cpu_index = 0 + + def __cmd_completion(self): + for cmd in self.__cmd_passthrough('help')['return'].split('\r\n'): + if cmd and cmd[0] != '[' and cmd[0] != '\t': + name = cmd.split()[0] # drop help text + if name == 'info': + continue + if name.find('|') != -1: + # Command in the form 'foobar|f' or 'f|foobar', take the + # full name + opt = name.split('|') + if len(opt[0]) == 1: + name = opt[1] + else: + name = opt[0] + self._completer.append(name) + self._completer.append('help ' + name) # help completion + + def __info_completion(self): + for cmd in self.__cmd_passthrough('info')['return'].split('\r\n'): + if cmd: + self._completer.append('info ' + cmd.split()[1]) + + def __other_completion(self): + # special cases + self._completer.append('help info') + + def _fill_completion(self): + self.__cmd_completion() + self.__info_completion() + self.__other_completion() + + def __cmd_passthrough(self, cmdline, cpu_index = 0): + return self.cmd_obj({ 'execute': 'human-monitor-command', 'arguments': + { 'command-line': cmdline, + 'cpu-index': cpu_index } }) + + def _execute_cmd(self, cmdline): + if cmdline.split()[0] == "cpu": + # trap the cpu command, it requires special setting + try: + idx = int(cmdline.split()[1]) + if not 'return' in self.__cmd_passthrough('info version', idx): + print 'bad CPU index' + return True + self.__cpu_index = idx + except ValueError: + print 'cpu command takes an integer argument' + return True + resp = self.__cmd_passthrough(cmdline, self.__cpu_index) + if resp is None: + print 'Disconnected' + return False + assert 'return' in resp or 'error' in resp + if 'return' in resp: + # Success + if len(resp['return']) > 0: + print resp['return'], + else: + # Error + print '%s: %s' % (resp['error']['class'], resp['error']['desc']) + return True + + def show_banner(self): + QMPShell.show_banner(self, msg='Welcome to the HMP shell!') + def die(msg): sys.stderr.write('ERROR: %s\n' % msg) sys.exit(1) @@ -156,9 +226,16 @@ def fail_cmdline(option=None): sys.exit(1) def main(): + addr = '' try: if len(sys.argv) == 2: qemu = QMPShell(sys.argv[1]) + addr = sys.argv[1] + elif len(sys.argv) == 3: + if sys.argv[1] != '-H': + fail_cmdline(sys.argv[1]) + qemu = HMPShell(sys.argv[2]) + addr = sys.argv[2] else: fail_cmdline() except QMPShellBadPort: @@ -171,7 +248,7 @@ def main(): except qmp.QMPCapabilitiesError: die('Could not negotiate capabilities') except qemu.error: - die('Could not connect to %s' % sys.argv[1]) + die('Could not connect to %s' % addr) qemu.show_banner() while qemu.read_exec_command('(QEMU) '): From a6f9dd02f75685934ca52f038b6fcb38b661c283 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 10 Nov 2010 15:59:57 -0200 Subject: [PATCH 054/105] Makefile: Fix check dependency breakage Commit b152aa84d52882bb1846485a89baf13aa07c86bc broke the unit-tests build, fix it. Signed-off-by: Luiz Capitulino --- Makefile | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 747e47c834..4e120a2d3a 100644 --- a/Makefile +++ b/Makefile @@ -163,12 +163,14 @@ qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS) -check-qint: check-qint.o qint.o qemu-malloc.o $(trace-obj-y) -check-qstring: check-qstring.o qstring.o qemu-malloc.o $(trace-obj-y) -check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qemu-malloc.o qlist.o $(trace-obj-y) -check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o $(trace-obj-y) -check-qfloat: check-qfloat.o qfloat.o qemu-malloc.o $(trace-obj-y) -check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o qemu-malloc.o $(trace-obj-y) +CHECK_PROG_DEPS = qemu-malloc.o $(oslib-obj-y) $(trace-obj-y) + +check-qint: check-qint.o qint.o $(CHECK_PROG_DEPS) +check-qstring: check-qstring.o qstring.o $(CHECK_PROG_DEPS) +check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(CHECK_PROG_DEPS) +check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS) +check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS) +check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o $(CHECK_PROG_DEPS) clean: # avoid old build problems by removing potentially incorrect old files From 39deb1e496de81957167daebf5cf5d1fbd5e47c2 Mon Sep 17 00:00:00 2001 From: malc Date: Thu, 18 Nov 2010 14:30:12 +0300 Subject: [PATCH 055/105] audio: Only use audio timer when necessary Originally proposed by Gerd Hoffmann. Signed-off-by: malc Acked-by: Gerd Hoffmann --- audio/audio.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index ade342e856..17074469b2 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1096,15 +1096,6 @@ static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info) /* * Timer */ -static void audio_timer (void *opaque) -{ - AudioState *s = opaque; - - audio_run ("timer"); - qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); -} - - static int audio_is_timer_needed (void) { HWVoiceIn *hwi = NULL; @@ -1119,10 +1110,8 @@ static int audio_is_timer_needed (void) return 0; } -static void audio_reset_timer (void) +static void audio_reset_timer (AudioState *s) { - AudioState *s = &glob_audio_state; - if (audio_is_timer_needed ()) { qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1); } @@ -1131,6 +1120,12 @@ static void audio_reset_timer (void) } } +static void audio_timer (void *opaque) +{ + audio_run ("timer"); + audio_reset_timer (opaque); +} + /* * Public API */ @@ -1195,7 +1190,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on) hw->enabled = 1; if (s->vm_running) { hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, conf.try_poll_out); - audio_reset_timer (); + audio_reset_timer (s); } } } @@ -1240,6 +1235,7 @@ void AUD_set_active_in (SWVoiceIn *sw, int on) hw->enabled = 1; if (s->vm_running) { hw->pcm_ops->ctl_in (hw, VOICE_ENABLE, conf.try_poll_in); + audio_reset_timer (s); } } sw->total_hw_samples_acquired = hw->total_samples_captured; @@ -1761,7 +1757,7 @@ static void audio_vm_change_state_handler (void *opaque, int running, while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) { hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in); } - audio_reset_timer (); + audio_reset_timer (s); } static void audio_atexit (void) From 371c338ecae44bb28cc19138484256b1df831e99 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 17 Nov 2010 18:05:58 -0600 Subject: [PATCH 056/105] Revert "Add support for generating a systemtap tapset static probes" This reverts commit 2834c3e0140c3b0ed4422909dfa0607b7213d95d. Conflicts: Makefile.target --- Makefile.target | 17 +-------- configure | 7 ---- tracetool | 92 ------------------------------------------------- 3 files changed, 1 insertion(+), 115 deletions(-) diff --git a/Makefile.target b/Makefile.target index 652c7d2a57..31c968c029 100644 --- a/Makefile.target +++ b/Makefile.target @@ -41,18 +41,7 @@ kvm.o kvm-all.o vhost.o vhost_net.o: QEMU_CFLAGS+=$(KVM_CFLAGS) config-target.h: config-target.h-timestamp config-target.h-timestamp: config-target.mak -ifdef CONFIG_SYSTEMTAP_TRACE -STPFILES+=$(QEMU_PROG).stp - -$(QEMU_PROG).stp: - $(call quiet-command,sh $(SRC_PATH)/tracetool \ - --$(TRACE_BACKEND) \ - --bindir $(bindir) \ - --target $(TARGET_ARCH) \ - -s < $(SRC_PATH)/trace-events > $@," GEN $@") -endif - -all: $(PROGS) $(STPFILES) +all: $(PROGS) # Dummy command so that make thinks it has done something @true @@ -360,10 +349,6 @@ ifneq ($(STRIP),) $(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS)) endif endif -ifdef CONFIG_SYSTEMTAP_TRACE - $(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset" - $(INSTALL_DATA) $(STPFILES) "$(DESTDIR)$(datadir)/../systemtap/tapset" -endif # Include automatically generated dependency files -include $(wildcard *.d */*.d) diff --git a/configure b/configure index e560f878a3..f8dad3eb00 100755 --- a/configure +++ b/configure @@ -2192,10 +2192,6 @@ EOF echo exit 1 fi - trace_backend_stap="no" - if has 'stap' ; then - trace_backend_stap="yes" - fi fi ########################################## @@ -2649,9 +2645,6 @@ fi if test "$trace_backend" = "simple"; then trace_file="\"$trace_file-%u\"" fi -if test "$trace_backend" = "dtrace" -a "$trace_backend_stap" = "yes" ; then - echo "CONFIG_SYSTEMTAP_TRACE=y" >> $config_host_mak -fi echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak echo "TOOLS=$tools" >> $config_host_mak diff --git a/tracetool b/tracetool index d797ab79a3..5b6636ac27 100755 --- a/tracetool +++ b/tracetool @@ -26,12 +26,6 @@ Output formats: -h Generate .h file -c Generate .c file -d Generate .d file (DTrace only) - -s Generate .stp file (DTrace with SystemTAP only) - -Options: - --bindir [bindir] QEMU binary install location - --target [arch] QEMU target architecture - EOF exit 1 } @@ -396,54 +390,6 @@ linetod_end_dtrace() EOF } -linetos_begin_dtrace() -{ - return -} - -linetos_dtrace() -{ - local name args arglist state - name=$(get_name "$1") - args=$(get_args "$1") - arglist=$(get_argnames "$1", "") - state=$(get_state "$1") - if [ "$state" = "0" ] ; then - name=${name##disable } - fi - - if [ "$target" = "i386" ] - then - binary="qemu" - else - binary="qemu-system-$target" - fi - - # Define prototype for probe arguments - cat < Date: Wed, 17 Nov 2010 18:06:06 -0600 Subject: [PATCH 057/105] Revert "Add a DTrace tracing backend targetted for SystemTAP compatability" This reverts commit 4addb1127f6327c7ebcbd150a6b589e7677adc92. --- .gitignore | 2 - Makefile | 23 ---------- Makefile.objs | 4 -- configure | 14 +----- tracetool | 116 +++++--------------------------------------------- 5 files changed, 11 insertions(+), 148 deletions(-) diff --git a/.gitignore b/.gitignore index 3efb4ecc13..a43e4d1d98 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,6 @@ config-host.* config-target.* trace.h trace.c -trace-dtrace.h -trace-dtrace.dtrace *-timestamp *-softmmu *-darwin-user diff --git a/Makefile b/Makefile index 747e47c834..68963198f0 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,6 @@ # Makefile for QEMU. GENERATED_HEADERS = config-host.h trace.h qemu-options.def -ifeq ($(TRACE_BACKEND),dtrace) -GENERATED_HEADERS += trace-dtrace.h -endif ifneq ($(wildcard config-host.mak),) # Put the all: rule here so that config-host.mak can contain dependencies. @@ -111,11 +108,7 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS) bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS) -ifeq ($(TRACE_BACKEND),dtrace) -trace.h: trace.h-timestamp trace-dtrace.h -else trace.h: trace.h-timestamp -endif trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h") @cmp -s $@ trace.h || cp $@ trace.h @@ -127,20 +120,6 @@ trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak trace.o: trace.c $(GENERATED_HEADERS) -trace-dtrace.h: trace-dtrace.dtrace - $(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h") - -# Normal practice is to name DTrace probe file with a '.d' extension -# but that gets picked up by QEMU's Makefile as an external dependancy -# rule file. So we use '.dtrace' instead -trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp -trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak - $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace") - @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace - -trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS) - $(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o") - simpletrace.o: simpletrace.c $(GENERATED_HEADERS) version.o: $(SRC_PATH)/version.rc config-host.mak @@ -178,8 +157,6 @@ clean: rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d rm -f qemu-img-cmds.h rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp - rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp - rm -f trace-dtrace.h trace-dtrace.h-timestamp $(MAKE) -C tests clean for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \ if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \ diff --git a/Makefile.objs b/Makefile.objs index 23b17cefad..15569afa14 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -286,15 +286,11 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o ###################################################################### # trace -ifeq ($(TRACE_BACKEND),dtrace) -trace-obj-y = trace-dtrace.o -else trace-obj-y = trace.o ifeq ($(TRACE_BACKEND),simple) trace-obj-y += simpletrace.o user-obj-y += qemu-timer-common.o endif -endif vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) diff --git a/configure b/configure index f8dad3eb00..7025d2bf0d 100755 --- a/configure +++ b/configure @@ -929,7 +929,7 @@ echo " --enable-docs enable documentation build" echo " --disable-docs disable documentation build" echo " --disable-vhost-net disable vhost-net acceleration support" echo " --enable-vhost-net enable vhost-net acceleration support" -echo " --trace-backend=B Trace backend nop simple ust dtrace" +echo " --trace-backend=B Trace backend nop simple ust" echo " --trace-file=NAME Full PATH,NAME of file to store traces" echo " Default:trace-" echo " --disable-spice disable spice" @@ -2193,18 +2193,6 @@ EOF exit 1 fi fi - -########################################## -# For 'dtrace' backend, test if 'dtrace' command is present -if test "$trace_backend" = "dtrace"; then - if ! has 'dtrace' ; then - echo - echo "Error: dtrace command is not found in PATH $PATH" - echo - exit 1 - fi -fi - ########################################## # End of CC checks # After here, no more $cc or $ld runs diff --git a/tracetool b/tracetool index 5b6636ac27..701085837f 100755 --- a/tracetool +++ b/tracetool @@ -20,12 +20,10 @@ Backends: --nop Tracing disabled --simple Simple built-in backend --ust LTTng User Space Tracing backend - --dtrace DTrace/SystemTAP backend Output formats: -h Generate .h file -c Generate .c file - -d Generate .d file (DTrace only) EOF exit 1 } @@ -48,9 +46,8 @@ get_args() # Get the argument name list of a trace event get_argnames() { - local nfields field name sep + local nfields field name nfields=0 - sep="$2" for field in $(get_args "$1"); do nfields=$((nfields + 1)) @@ -61,7 +58,7 @@ get_argnames() name=${field%,} test "$field" = "$name" && continue - printf "%s%s " $name $sep + printf "%s" "$name, " done # Last argument name @@ -76,7 +73,7 @@ get_argc() { local name argc argc=0 - for name in $(get_argnames "$1", ","); do + for name in $(get_argnames "$1"); do argc=$((argc + 1)) done echo $argc @@ -157,7 +154,7 @@ EOF cast_args_to_uint64_t() { local arg - for arg in $(get_argnames "$1", ","); do + for arg in $(get_argnames "$1"); do printf "%s" "(uint64_t)(uintptr_t)$arg" done } @@ -250,7 +247,7 @@ linetoh_ust() local name args argnames name=$(get_name "$1") args=$(get_args "$1") - argnames=$(get_argnames "$1", ",") + argnames=$(get_argnames "$1") cat < Date: Fri, 12 Nov 2010 13:20:24 +0000 Subject: [PATCH 058/105] Add a DTrace tracing backend targetted for SystemTAP compatability This introduces a new tracing backend that targets the SystemTAP implementation of DTrace userspace tracing. The core functionality should be applicable and standard across any DTrace implementation on Solaris, OS-X, *BSD, but the Makefile rules will likely need some small additional changes to cope with OS specific build requirements. This backend builds a little differently from the other tracing backends. Specifically there is no 'trace.c' file, because the 'dtrace' command line tool generates a '.o' file directly from the dtrace probe definition file. The probe definition is usually named with a '.d' extension but QEMU uses '.d' files for its external makefile dependancy tracking, so this uses '.dtrace' as the extension for the probe definition file. The 'tracetool' program gains the ability to generate a trace.h file for DTrace, and also to generate the trace.d file containing the dtrace probe definition. Example usage of a dtrace probe in systemtap looks like: probe process("qemu").mark("qemu_malloc") { printf("Malloc %d %p\n", $arg1, $arg2); } * .gitignore: Ignore trace-dtrace.* * Makefile: Extra rules for generating DTrace files * Makefile.obj: Don't build trace.o for DTrace, use trace-dtrace.o generated by 'dtrace' instead * tracetool: Support for generating DTrace data files Reviewed-by: Stefan Hajnoczi Signed-off-by: Daniel P. Berrange Signed-off-by: Anthony Liguori --- .gitignore | 2 + Makefile | 23 ++++++++++ Makefile.objs | 4 ++ configure | 14 +++++- tracetool | 122 +++++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 154 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index a43e4d1d98..3efb4ecc13 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ config-host.* config-target.* trace.h trace.c +trace-dtrace.h +trace-dtrace.dtrace *-timestamp *-softmmu *-darwin-user diff --git a/Makefile b/Makefile index 68963198f0..747e47c834 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,9 @@ # Makefile for QEMU. GENERATED_HEADERS = config-host.h trace.h qemu-options.def +ifeq ($(TRACE_BACKEND),dtrace) +GENERATED_HEADERS += trace-dtrace.h +endif ifneq ($(wildcard config-host.mak),) # Put the all: rule here so that config-host.mak can contain dependencies. @@ -108,7 +111,11 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS) bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS) +ifeq ($(TRACE_BACKEND),dtrace) +trace.h: trace.h-timestamp trace-dtrace.h +else trace.h: trace.h-timestamp +endif trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h") @cmp -s $@ trace.h || cp $@ trace.h @@ -120,6 +127,20 @@ trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak trace.o: trace.c $(GENERATED_HEADERS) +trace-dtrace.h: trace-dtrace.dtrace + $(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h") + +# Normal practice is to name DTrace probe file with a '.d' extension +# but that gets picked up by QEMU's Makefile as an external dependancy +# rule file. So we use '.dtrace' instead +trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp +trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak + $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace") + @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace + +trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS) + $(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o") + simpletrace.o: simpletrace.c $(GENERATED_HEADERS) version.o: $(SRC_PATH)/version.rc config-host.mak @@ -157,6 +178,8 @@ clean: rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d rm -f qemu-img-cmds.h rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp + rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp + rm -f trace-dtrace.h trace-dtrace.h-timestamp $(MAKE) -C tests clean for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \ if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \ diff --git a/Makefile.objs b/Makefile.objs index 15569afa14..23b17cefad 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -286,11 +286,15 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o ###################################################################### # trace +ifeq ($(TRACE_BACKEND),dtrace) +trace-obj-y = trace-dtrace.o +else trace-obj-y = trace.o ifeq ($(TRACE_BACKEND),simple) trace-obj-y += simpletrace.o user-obj-y += qemu-timer-common.o endif +endif vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) diff --git a/configure b/configure index 7025d2bf0d..f8dad3eb00 100755 --- a/configure +++ b/configure @@ -929,7 +929,7 @@ echo " --enable-docs enable documentation build" echo " --disable-docs disable documentation build" echo " --disable-vhost-net disable vhost-net acceleration support" echo " --enable-vhost-net enable vhost-net acceleration support" -echo " --trace-backend=B Trace backend nop simple ust" +echo " --trace-backend=B Trace backend nop simple ust dtrace" echo " --trace-file=NAME Full PATH,NAME of file to store traces" echo " Default:trace-" echo " --disable-spice disable spice" @@ -2193,6 +2193,18 @@ EOF exit 1 fi fi + +########################################## +# For 'dtrace' backend, test if 'dtrace' command is present +if test "$trace_backend" = "dtrace"; then + if ! has 'dtrace' ; then + echo + echo "Error: dtrace command is not found in PATH $PATH" + echo + exit 1 + fi +fi + ########################################## # End of CC checks # After here, no more $cc or $ld runs diff --git a/tracetool b/tracetool index 701085837f..1ade103baf 100755 --- a/tracetool +++ b/tracetool @@ -20,10 +20,12 @@ Backends: --nop Tracing disabled --simple Simple built-in backend --ust LTTng User Space Tracing backend + --dtrace DTrace/SystemTAP backend Output formats: -h Generate .h file -c Generate .c file + -d Generate .d file (DTrace only) EOF exit 1 } @@ -46,8 +48,9 @@ get_args() # Get the argument name list of a trace event get_argnames() { - local nfields field name + local nfields field name sep nfields=0 + sep="$2" for field in $(get_args "$1"); do nfields=$((nfields + 1)) @@ -58,7 +61,7 @@ get_argnames() name=${field%,} test "$field" = "$name" && continue - printf "%s" "$name, " + printf "%s%s " $name $sep done # Last argument name @@ -73,7 +76,7 @@ get_argc() { local name argc argc=0 - for name in $(get_argnames "$1"); do + for name in $(get_argnames "$1", ","); do argc=$((argc + 1)) done echo $argc @@ -154,7 +157,7 @@ EOF cast_args_to_uint64_t() { local arg - for arg in $(get_argnames "$1"); do + for arg in $(get_argnames "$1", ","); do printf "%s" "(uint64_t)(uintptr_t)$arg" done } @@ -247,7 +250,7 @@ linetoh_ust() local name args argnames name=$(get_name "$1") args=$(get_args "$1") - argnames=$(get_argnames "$1") + argnames=$(get_argnames "$1", ",") cat < Date: Fri, 12 Nov 2010 13:20:25 +0000 Subject: [PATCH 059/105] Add support for generating a systemtap tapset static probes This introduces generation of a qemu.stp/qemu-system-XXX.stp files which provides tapsets with friendly names for static probes & their arguments. Instead of probe process("qemu").mark("qemu_malloc") { printf("Malloc %d %p\n", $arg1, $arg2); } It is now possible todo probe qemu.system.i386.qemu_malloc { printf("Malloc %d %p\n", size, ptr); } There is one tapset defined per target arch, for both user and system emulators. * Makefile.target: Generate stp files for each target * tracetool: Support for generating systemtap tapsets * configure: Check for whether systemtap is available with the DTrace backend Reviewed-by: Stefan Hajnoczi Signed-off-by: Daniel P. Berrange Signed-off-by: Anthony Liguori --- Makefile.target | 29 ++++++++++- configure | 7 +++ tracetool | 126 ++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 145 insertions(+), 17 deletions(-) diff --git a/Makefile.target b/Makefile.target index 31c968c029..2800f473b7 100644 --- a/Makefile.target +++ b/Makefile.target @@ -41,7 +41,27 @@ kvm.o kvm-all.o vhost.o vhost_net.o: QEMU_CFLAGS+=$(KVM_CFLAGS) config-target.h: config-target.h-timestamp config-target.h-timestamp: config-target.mak -all: $(PROGS) +ifdef CONFIG_SYSTEMTAP_TRACE +stap: $(QEMU_PROG).stp + +ifdef CONFIG_USER_ONLY +TARGET_TYPE=user +else +TARGET_TYPE=system +endif + +$(QEMU_PROG).stp: + $(call quiet-command,sh $(SRC_PATH)/tracetool \ + --$(TRACE_BACKEND) \ + --binary $(bindir)/$(QEMU_PROG) \ + --target-arch $(TARGET_ARCH) \ + --target-type $(TARGET_TYPE) \ + --stap < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).stp") +else +stap: +endif + +all: $(PROGS) stap # Dummy command so that make thinks it has done something @true @@ -341,6 +361,9 @@ clean: rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o rm -f *.d */*.d tcg/*.o ide/*.o rm -f hmp-commands.h qmp-commands.h gdbstub-xml.c +ifdef CONFIG_SYSTEMTAP_TRACE + rm -f *.stp +endif install: all ifneq ($(PROGS),) @@ -349,6 +372,10 @@ ifneq ($(STRIP),) $(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS)) endif endif +ifdef CONFIG_SYSTEMTAP_TRACE + $(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset" + $(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(datadir)/../systemtap/tapset" +endif # Include automatically generated dependency files -include $(wildcard *.d */*.d) diff --git a/configure b/configure index f8dad3eb00..2917874f96 100755 --- a/configure +++ b/configure @@ -2203,6 +2203,10 @@ if test "$trace_backend" = "dtrace"; then echo exit 1 fi + trace_backend_stap="no" + if has 'stap' ; then + trace_backend_stap="yes" + fi fi ########################################## @@ -2645,6 +2649,9 @@ fi if test "$trace_backend" = "simple"; then trace_file="\"$trace_file-%u\"" fi +if test "$trace_backend" = "dtrace" -a "$trace_backend_stap" = "yes" ; then + echo "CONFIG_SYSTEMTAP_TRACE=y" >> $config_host_mak +fi echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak echo "TOOLS=$tools" >> $config_host_mak diff --git a/tracetool b/tracetool index 1ade103baf..fce491c505 100755 --- a/tracetool +++ b/tracetool @@ -23,9 +23,16 @@ Backends: --dtrace DTrace/SystemTAP backend Output formats: - -h Generate .h file - -c Generate .c file - -d Generate .d file (DTrace only) + -h Generate .h file + -c Generate .c file + -d Generate .d file (DTrace only) + --stap Generate .stp file (DTrace with SystemTAP only) + +Options: + --binary [path] Full path to QEMU binary + --target-arch [arch] QEMU emulator target arch + --target-type [type] QEMU emulator target type ('system' or 'user') + EOF exit 1 } @@ -396,6 +403,51 @@ linetod_end_dtrace() EOF } +linetostap_begin_dtrace() +{ + return +} + +linetostap_dtrace() +{ + local i arg name args arglist state + name=$(get_name "$1") + args=$(get_args "$1") + arglist=$(get_argnames "$1", "") + state=$(get_state "$1") + if [ "$state" = "0" ] ; then + name=${name##disable } + fi + + # Define prototype for probe arguments + cat < Date: Mon, 8 Nov 2010 17:02:54 -0200 Subject: [PATCH 060/105] block: fix shift in dirty bitmap calculation Otherwise upper 32 bits of bitmap entries are not correctly calculated. Reviewed-by: Kevin Wolf Signed-off-by: Marcelo Tosatti Signed-off-by: Anthony Liguori --- block.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/block.c b/block.c index 6b505fba1b..53a10de9dc 100644 --- a/block.c +++ b/block.c @@ -930,14 +930,14 @@ static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num, bit = start % (sizeof(unsigned long) * 8); val = bs->dirty_bitmap[idx]; if (dirty) { - if (!(val & (1 << bit))) { + if (!(val & (1UL << bit))) { bs->dirty_count++; - val |= 1 << bit; + val |= 1UL << bit; } } else { - if (val & (1 << bit)) { + if (val & (1UL << bit)) { bs->dirty_count--; - val &= ~(1 << bit); + val &= ~(1UL << bit); } } bs->dirty_bitmap[idx] = val; @@ -2685,8 +2685,8 @@ int bdrv_get_dirty(BlockDriverState *bs, int64_t sector) if (bs->dirty_bitmap && (sector << BDRV_SECTOR_BITS) < bdrv_getlength(bs)) { - return bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] & - (1 << (chunk % (sizeof(unsigned long) * 8))); + return !!(bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] & + (1UL << (chunk % (sizeof(unsigned long) * 8)))); } else { return 0; } From 4dcafbb1eba2ee201ec86027982659b669f99c70 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Mon, 8 Nov 2010 17:02:55 -0200 Subject: [PATCH 061/105] block: set sector dirty on AIO write completion Sectors are marked dirty in the bitmap on AIO submission. This is wrong since data has not reached storage. Set a given sector as dirty in the dirty bitmap on AIO completion, so that reading a sector marked as dirty is guaranteed to return uptodate data. Reviewed-by: Kevin Wolf Signed-off-by: Marcelo Tosatti Signed-off-by: Anthony Liguori --- block.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/block.c b/block.c index 53a10de9dc..63effd8769 100644 --- a/block.c +++ b/block.c @@ -2031,12 +2031,49 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num, return ret; } +typedef struct BlockCompleteData { + BlockDriverCompletionFunc *cb; + void *opaque; + BlockDriverState *bs; + int64_t sector_num; + int nb_sectors; +} BlockCompleteData; + +static void block_complete_cb(void *opaque, int ret) +{ + BlockCompleteData *b = opaque; + + if (b->bs->dirty_bitmap) { + set_dirty_bitmap(b->bs, b->sector_num, b->nb_sectors, 1); + } + b->cb(b->opaque, ret); + qemu_free(b); +} + +static BlockCompleteData *blk_dirty_cb_alloc(BlockDriverState *bs, + int64_t sector_num, + int nb_sectors, + BlockDriverCompletionFunc *cb, + void *opaque) +{ + BlockCompleteData *blkdata = qemu_mallocz(sizeof(BlockCompleteData)); + + blkdata->bs = bs; + blkdata->cb = cb; + blkdata->opaque = opaque; + blkdata->sector_num = sector_num; + blkdata->nb_sectors = nb_sectors; + + return blkdata; +} + BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque) { BlockDriver *drv = bs->drv; BlockDriverAIOCB *ret; + BlockCompleteData *blk_cb_data; trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque); @@ -2048,7 +2085,10 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, return NULL; if (bs->dirty_bitmap) { - set_dirty_bitmap(bs, sector_num, nb_sectors, 1); + blk_cb_data = blk_dirty_cb_alloc(bs, sector_num, nb_sectors, cb, + opaque); + cb = &block_complete_cb; + opaque = blk_cb_data; } ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors, From 33656af70230d5ccebe29e2f3bee38afe17db9b2 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Mon, 8 Nov 2010 17:02:56 -0200 Subject: [PATCH 062/105] block migration: do not submit multiple AIOs for same sector Block migration can submit multiple AIO reads for the same sector/chunk, but completion of such reads can happen out of order: migration guest - get_dirty(N) - aio_read(N) - clear_dirty(N) write(N) set_dirty(N) - get_dirty(N) - aio_read(N) If the first aio_read completes after the second, stale data will be migrated to the destination. Fix by not allowing multiple AIOs inflight for the same sector. Signed-off-by: Marcelo Tosatti Signed-off-by: Anthony Liguori --- block-migration.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/block-migration.c b/block-migration.c index 0bfdb73c8b..3e66f49350 100644 --- a/block-migration.c +++ b/block-migration.c @@ -49,12 +49,14 @@ typedef struct BlkMigDevState { int64_t total_sectors; int64_t dirty; QSIMPLEQ_ENTRY(BlkMigDevState) entry; + unsigned long *aio_bitmap; } BlkMigDevState; typedef struct BlkMigBlock { uint8_t *buf; BlkMigDevState *bmds; int64_t sector; + int nr_sectors; struct iovec iov; QEMUIOVector qiov; BlockDriverAIOCB *aiocb; @@ -140,6 +142,57 @@ static inline long double compute_read_bwidth(void) return (block_mig_state.reads * BLOCK_SIZE)/ block_mig_state.total_time; } +static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector) +{ + int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK; + + if (bmds->aio_bitmap && + (sector << BDRV_SECTOR_BITS) < bdrv_getlength(bmds->bs)) { + return !!(bmds->aio_bitmap[chunk / (sizeof(unsigned long) * 8)] & + (1UL << (chunk % (sizeof(unsigned long) * 8)))); + } else { + return 0; + } +} + +static void bmds_set_aio_inflight(BlkMigDevState *bmds, int64_t sector_num, + int nb_sectors, int set) +{ + int64_t start, end; + unsigned long val, idx, bit; + + start = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK; + end = (sector_num + nb_sectors - 1) / BDRV_SECTORS_PER_DIRTY_CHUNK; + + for (; start <= end; start++) { + idx = start / (sizeof(unsigned long) * 8); + bit = start % (sizeof(unsigned long) * 8); + val = bmds->aio_bitmap[idx]; + if (set) { + if (!(val & (1UL << bit))) { + val |= 1UL << bit; + } + } else { + if (val & (1UL << bit)) { + val &= ~(1UL << bit); + } + } + bmds->aio_bitmap[idx] = val; + } +} + +static void alloc_aio_bitmap(BlkMigDevState *bmds) +{ + BlockDriverState *bs = bmds->bs; + int64_t bitmap_size; + + bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) + + BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1; + bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8; + + bmds->aio_bitmap = qemu_mallocz(bitmap_size); +} + static void blk_mig_read_cb(void *opaque, int ret) { BlkMigBlock *blk = opaque; @@ -151,6 +204,7 @@ static void blk_mig_read_cb(void *opaque, int ret) add_avg_read_time(blk->time); QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry); + bmds_set_aio_inflight(blk->bmds, blk->sector, blk->nr_sectors, 0); block_mig_state.submitted--; block_mig_state.read_done++; @@ -194,6 +248,7 @@ static int mig_save_device_bulk(Monitor *mon, QEMUFile *f, blk->buf = qemu_malloc(BLOCK_SIZE); blk->bmds = bmds; blk->sector = cur_sector; + blk->nr_sectors = nr_sectors; blk->iov.iov_base = blk->buf; blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; @@ -248,6 +303,7 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs) bmds->total_sectors = sectors; bmds->completed_sectors = 0; bmds->shared_base = block_mig_state.shared_base; + alloc_aio_bitmap(bmds); block_mig_state.total_sector_sum += sectors; @@ -329,6 +385,8 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f, int nr_sectors; for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) { + if (bmds_aio_inflight(bmds, sector)) + qemu_aio_flush(); if (bdrv_get_dirty(bmds->bs, sector)) { if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) { @@ -340,6 +398,7 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f, blk->buf = qemu_malloc(BLOCK_SIZE); blk->bmds = bmds; blk->sector = sector; + blk->nr_sectors = nr_sectors; if (is_async) { blk->iov.iov_base = blk->buf; @@ -354,6 +413,7 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f, goto error; } block_mig_state.submitted++; + bmds_set_aio_inflight(bmds, sector, nr_sectors, 1); } else { if (bdrv_read(bmds->bs, sector, blk->buf, nr_sectors) < 0) { @@ -474,6 +534,7 @@ static void blk_mig_cleanup(Monitor *mon) while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) { QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry); + qemu_free(bmds->aio_bitmap); qemu_free(bmds); } From e71e00ed258202052570ae631536f4d7b65792fa Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 12 Nov 2010 12:55:46 -0200 Subject: [PATCH 063/105] Makefile: Fix check dependency breakage Commit b152aa84d52882bb1846485a89baf13aa07c86bc broke the unit-tests build, fix it. Signed-off-by: Luiz Capitulino Signed-off-by: Anthony Liguori --- Makefile | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 747e47c834..4e120a2d3a 100644 --- a/Makefile +++ b/Makefile @@ -163,12 +163,14 @@ qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS) -check-qint: check-qint.o qint.o qemu-malloc.o $(trace-obj-y) -check-qstring: check-qstring.o qstring.o qemu-malloc.o $(trace-obj-y) -check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qemu-malloc.o qlist.o $(trace-obj-y) -check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o $(trace-obj-y) -check-qfloat: check-qfloat.o qfloat.o qemu-malloc.o $(trace-obj-y) -check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o qemu-malloc.o $(trace-obj-y) +CHECK_PROG_DEPS = qemu-malloc.o $(oslib-obj-y) $(trace-obj-y) + +check-qint: check-qint.o qint.o $(CHECK_PROG_DEPS) +check-qstring: check-qstring.o qstring.o $(CHECK_PROG_DEPS) +check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(CHECK_PROG_DEPS) +check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS) +check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS) +check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o $(CHECK_PROG_DEPS) clean: # avoid old build problems by removing potentially incorrect old files From 33bbd1de5ec9b8802d63e811908f2351ba83884c Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 16 Nov 2010 16:33:17 +0200 Subject: [PATCH 064/105] optionrom: fix bugs in signrom.sh signrom.sh has multiple bugs: - the last byte is considered when calculating the existing checksum, but not when computing the correction - apprently the 'expr' expression overflows and produces incorrect results with larger roms - if the checksum happened to be zero, we calculated the correction byte to be 256 Instead of rewriting this in half a line of python, this patch fixes the bugs. Signed-off-by: Avi Kivity Signed-off-by: Anthony Liguori --- pc-bios/optionrom/signrom.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pc-bios/optionrom/signrom.sh b/pc-bios/optionrom/signrom.sh index 975b27dd60..9dc5c63dde 100755 --- a/pc-bios/optionrom/signrom.sh +++ b/pc-bios/optionrom/signrom.sh @@ -31,14 +31,13 @@ x=`dd if="$1" bs=1 count=1 skip=2 2>/dev/null | od -t u1 -A n` size=$(( $x * 512 - 1 )) # now get the checksum -nums=`od -A n -t u1 -v "$1"` +nums=`od -A n -t u1 -v -N $size "$1"` for i in ${nums}; do # add each byte's value to sum - sum=`expr $sum + $i` + sum=`expr \( $sum + $i \) % 256` done -sum=$(( $sum % 256 )) -sum=$(( 256 - $sum )) +sum=$(( (256 - $sum) % 256 )) sum_octal=$( printf "%o" $sum ) # and write the output file From 0550f9c1b58896a6ca1d1256e26c78f84de2ed55 Mon Sep 17 00:00:00 2001 From: Bernhard Kohl Date: Tue, 16 Nov 2010 13:28:37 +0100 Subject: [PATCH 065/105] pc: disable the BOCHS BIOS panic port We have an OS which writes to port 0x400 when probing for special hardware. This causes an exit of the VM. With SeaBIOS this port isn't used anyway. Signed-off-by: Alexander Graf Reviewed-By: Paolo Bonzini Signed-off-by: Bernhard Kohl Signed-off-by: Anthony Liguori --- hw/pc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index c34d194c25..119c1106c2 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -430,8 +430,8 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) /* Bochs BIOS messages */ case 0x400: case 0x401: - fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val); - exit(1); + /* used to be panic, now unused */ + break; case 0x402: case 0x403: #ifdef DEBUG_BIOS From 9eca6cc64392b4ad8bd8723e840f491fa36524ad Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Mon, 15 Nov 2010 21:15:26 +0100 Subject: [PATCH 066/105] slirp: Remove unused code for bad sprintf Neither DECLARE_SPRINTF nor BAD_SPRINTF are needed for QEMU. QEMU won't support systems with missing or bad declarations for sprintf. The unused code was detected while looking for functions with missing format checking. Instead of adding GCC_FMT_ATTR, the unused code was removed. Cc: Blue Swirl Signed-off-by: Stefan Weil Signed-off-by: Anthony Liguori --- slirp/misc.c | 42 ------------------------------------------ slirp/slirp.h | 14 -------------- slirp/slirp_config.h | 6 ------ 3 files changed, 62 deletions(-) diff --git a/slirp/misc.c b/slirp/misc.c index 1aeb401082..19dbec491f 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -264,48 +264,6 @@ void lprint(const char *format, ...) va_end(args); } -#ifdef BAD_SPRINTF - -#undef vsprintf -#undef sprintf - -/* - * Some BSD-derived systems have a sprintf which returns char * - */ - -int -vsprintf_len(string, format, args) - char *string; - const char *format; - va_list args; -{ - vsprintf(string, format, args); - return strlen(string); -} - -int -#ifdef __STDC__ -sprintf_len(char *string, const char *format, ...) -#else -sprintf_len(va_alist) va_dcl -#endif -{ - va_list args; -#ifdef __STDC__ - va_start(args, format); -#else - char *string; - char *format; - va_start(args); - string = va_arg(args, char *); - format = va_arg(args, char *); -#endif - vsprintf(string, format, args); - return strlen(string); -} - -#endif - void u_sleep(int usec) { diff --git a/slirp/slirp.h b/slirp/slirp.h index 462292d577..dfd977aa0c 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -237,20 +237,6 @@ void if_start(Slirp *); void if_start(struct ttys *); #endif -#ifdef BAD_SPRINTF -# define vsprintf vsprintf_len -# define sprintf sprintf_len - extern int vsprintf_len(char *, const char *, va_list); - extern int sprintf_len(char *, const char *, ...); -#endif - -#ifdef DECLARE_SPRINTF -# ifndef BAD_SPRINTF - extern int vsprintf(char *, const char *, va_list); -# endif - extern int vfprintf(FILE *, const char *, va_list); -#endif - #ifndef HAVE_STRERROR extern char *strerror(int error); #endif diff --git a/slirp/slirp_config.h b/slirp/slirp_config.h index f19c7034ca..18db45c8e4 100644 --- a/slirp/slirp_config.h +++ b/slirp/slirp_config.h @@ -85,9 +85,6 @@ /* Define if the machine is big endian */ //#undef HOST_WORDS_BIGENDIAN -/* Define if your sprintf returns char * instead of int */ -#undef BAD_SPRINTF - /* Define if you have readv */ #undef HAVE_READV @@ -97,9 +94,6 @@ #define DECLARE_IOVEC #endif -/* Define if a declaration of sprintf/fprintf is needed */ -#undef DECLARE_SPRINTF - /* Define if you have a POSIX.1 sys/wait.h */ #undef HAVE_SYS_WAIT_H From 0b2c508856fa23695900c29b6ada57c07843bc6f Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Mon, 15 Nov 2010 21:17:06 +0100 Subject: [PATCH 067/105] trace: Use fprintf_function (format checking) fprintf_function adds format checking with GCC_FMT_ATTR. Cc: Blue Swirl Signed-off-by: Stefan Weil Signed-off-by: Anthony Liguori --- simpletrace.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/simpletrace.h b/simpletrace.h index 72614ec1d1..2f44ed3c3c 100644 --- a/simpletrace.h +++ b/simpletrace.h @@ -29,10 +29,10 @@ void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3); void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4); void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5); void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6); -void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...)); -void st_print_trace_events(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...)); +void st_print_trace(FILE *stream, fprintf_function stream_printf); +void st_print_trace_events(FILE *stream, fprintf_function stream_printf); bool st_change_trace_event_state(const char *tname, bool tstate); -void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...)); +void st_print_trace_file_status(FILE *stream, fprintf_function stream_printf); void st_set_trace_file_enabled(bool enable); bool st_set_trace_file(const char *file); void st_flush_trace_buffer(void); From b903a0f721f28283e5eaab00a3cb2ada96c2eae0 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 11 Nov 2010 12:59:25 +0100 Subject: [PATCH 068/105] pc: add 0.13 pc machine type Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/pc_piix.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 12359a75c9..e17e878f07 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -212,7 +212,7 @@ static void pc_init_isa(ram_addr_t ram_size, } static QEMUMachine pc_machine = { - .name = "pc-0.13", + .name = "pc-0.14", .alias = "pc", .desc = "Standard PC", .init = pc_init_pci, @@ -220,6 +220,13 @@ static QEMUMachine pc_machine = { .is_default = 1, }; +static QEMUMachine pc_machine_v0_13 = { + .name = "pc-0.13", + .desc = "Standard PC", + .init = pc_init_pci, + .max_cpus = 255, +}; + static QEMUMachine pc_machine_v0_12 = { .name = "pc-0.12", .desc = "Standard PC", @@ -331,6 +338,7 @@ static QEMUMachine isapc_machine = { static void pc_machine_init(void) { qemu_register_machine(&pc_machine); + qemu_register_machine(&pc_machine_v0_13); qemu_register_machine(&pc_machine_v0_12); qemu_register_machine(&pc_machine_v0_11); qemu_register_machine(&pc_machine_v0_10); From 9dbcca5aa13cb9ab40788ac4c56bc227d94ca920 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 11 Nov 2010 12:59:26 +0100 Subject: [PATCH 069/105] virtfs: enable MSI-X This patch enables MSI-X for virtfs-9p-pci. It also adds a compat property to pc-0.13 which turns it of there to stay compatible to 0.13-stable. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/pc_piix.c | 8 ++++++++ hw/virtio-pci.c | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/hw/pc_piix.c b/hw/pc_piix.c index e17e878f07..31c80d273b 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -225,6 +225,14 @@ static QEMUMachine pc_machine_v0_13 = { .desc = "Standard PC", .init = pc_init_pci, .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + { + .driver = "virtio-9p-pci", + .property = "vectors", + .value = stringify(0), + }, + { /* end of list */ } + }, }; static QEMUMachine pc_machine_v0_12 = { diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 729917d891..3610d7e233 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -684,12 +684,14 @@ static int virtio_9p_init_pci(PCIDevice *pci_dev) VirtIODevice *vdev; vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf); + vdev->nvectors = proxy->nvectors; virtio_init_pci(proxy, vdev, PCI_VENDOR_ID_REDHAT_QUMRANET, 0x1009, 0x2, 0x00); - + /* make the actual value visible */ + proxy->nvectors = vdev->nvectors; return 0; } #endif @@ -758,6 +760,7 @@ static PCIDeviceInfo virtio_info[] = { .qdev.size = sizeof(VirtIOPCIProxy), .init = virtio_9p_init_pci, .qdev.props = (Property[]) { + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag), DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id), From 94b0b5ff5f5c3ab946fa926d464738edb3713ed4 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 16 Nov 2010 12:20:25 +0000 Subject: [PATCH 070/105] trace: Trace vm_start()/vm_stop() VM state change notifications are invoked from vm_start()/vm_stop(). Trace these state changes so we can reason about the state of the VM from trace output. Signed-off-by: Stefan Hajnoczi Signed-off-by: Anthony Liguori --- trace-events | 3 +++ vl.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/trace-events b/trace-events index 947f8b08cb..da03d4be12 100644 --- a/trace-events +++ b/trace-events @@ -189,3 +189,6 @@ disable sun4m_iommu_mem_writel_pgflush(uint32_t val) "page flush %x" disable sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags addr %"PRIx64" => pte %"PRIx64", *pte = %x" disable sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x" disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64"" + +# vl.c +disable vm_state_notify(int running, int reason) "running %d reason %d" diff --git a/vl.c b/vl.c index 9ee6479b7c..805e11f5c5 100644 --- a/vl.c +++ b/vl.c @@ -158,6 +158,7 @@ int main(int argc, char **argv) #include "slirp/libslirp.h" +#include "trace.h" #include "qemu-queue.h" #include "cpus.h" #include "arch_init.h" @@ -1074,6 +1075,8 @@ void vm_state_notify(int running, int reason) { VMChangeStateEntry *e; + trace_vm_state_notify(running, reason); + for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) { e->cb(e->opaque, running, reason); } From acd1c812b5548c8426e093075362b6d4119db6ac Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 17 Nov 2010 11:50:09 +0200 Subject: [PATCH 071/105] Type-safe ioport callbacks The current ioport callbacks are not type-safe, in that they accept an "opaque" pointer as an argument whose type must match the argument to the registration function; this is not checked by the compiler. This patch adds an alternative that is type-safe. Instead of an opaque argument, both registation and the callback use a new IOPort type. The callback then uses container_of() to access its main structures. Currently the old and new methods exist side by side; once the old way is gone, we can also save a bunch of memory since the new method requires one pointer per ioport instead of 6. Acked-by: Anthony Liguori Signed-off-by: Avi Kivity Signed-off-by: Anthony Liguori --- ioport.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ ioport.h | 2 ++ iorange.h | 30 ++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 iorange.h diff --git a/ioport.c b/ioport.c index ec3dc65cdd..aa4188a40f 100644 --- a/ioport.c +++ b/ioport.c @@ -174,6 +174,70 @@ int register_ioport_write(pio_addr_t start, int length, int size, return 0; } +static uint32_t ioport_readb_thunk(void *opaque, uint32_t addr) +{ + IORange *ioport = opaque; + uint64_t data; + + ioport->ops->read(ioport, addr - ioport->base, 1, &data); + return data; +} + +static uint32_t ioport_readw_thunk(void *opaque, uint32_t addr) +{ + IORange *ioport = opaque; + uint64_t data; + + ioport->ops->read(ioport, addr - ioport->base, 2, &data); + return data; +} + +static uint32_t ioport_readl_thunk(void *opaque, uint32_t addr) +{ + IORange *ioport = opaque; + uint64_t data; + + ioport->ops->read(ioport, addr - ioport->base, 4, &data); + return data; +} + +static void ioport_writeb_thunk(void *opaque, uint32_t addr, uint32_t data) +{ + IORange *ioport = opaque; + + ioport->ops->write(ioport, addr - ioport->base, 1, data); +} + +static void ioport_writew_thunk(void *opaque, uint32_t addr, uint32_t data) +{ + IORange *ioport = opaque; + + ioport->ops->write(ioport, addr - ioport->base, 2, data); +} + +static void ioport_writel_thunk(void *opaque, uint32_t addr, uint32_t data) +{ + IORange *ioport = opaque; + + ioport->ops->write(ioport, addr - ioport->base, 4, data); +} + +void ioport_register(IORange *ioport) +{ + register_ioport_read(ioport->base, ioport->len, 1, + ioport_readb_thunk, ioport); + register_ioport_read(ioport->base, ioport->len, 2, + ioport_readw_thunk, ioport); + register_ioport_read(ioport->base, ioport->len, 4, + ioport_readl_thunk, ioport); + register_ioport_write(ioport->base, ioport->len, 1, + ioport_writeb_thunk, ioport); + register_ioport_write(ioport->base, ioport->len, 2, + ioport_writew_thunk, ioport); + register_ioport_write(ioport->base, ioport->len, 4, + ioport_writel_thunk, ioport); +} + void isa_unassign_ioport(pio_addr_t start, int length) { int i; diff --git a/ioport.h b/ioport.h index 3d3c8a3efd..5ae62a3a2c 100644 --- a/ioport.h +++ b/ioport.h @@ -25,6 +25,7 @@ #define IOPORT_H #include "qemu-common.h" +#include "iorange.h" typedef uint32_t pio_addr_t; #define FMT_pioaddr PRIx32 @@ -36,6 +37,7 @@ typedef uint32_t pio_addr_t; typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data); typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address); +void ioport_register(IORange *iorange); int register_ioport_read(pio_addr_t start, int length, int size, IOPortReadFunc *func, void *opaque); int register_ioport_write(pio_addr_t start, int length, int size, diff --git a/iorange.h b/iorange.h new file mode 100644 index 0000000000..97831683f0 --- /dev/null +++ b/iorange.h @@ -0,0 +1,30 @@ +#ifndef IORANGE_H +#define IORANGE_H + +#include + +typedef struct IORange IORange; +typedef struct IORangeOps IORangeOps; + +struct IORangeOps { + void (*read)(IORange *iorange, uint64_t offset, unsigned width, + uint64_t *data); + void (*write)(IORange *iorange, uint64_t offset, unsigned width, + uint64_t data); +}; + +struct IORange { + const IORangeOps *ops; + uint64_t base; + uint64_t len; +}; + +static inline void iorange_init(IORange *iorange, const IORangeOps *ops, + uint64_t base, uint64_t len) +{ + iorange->ops = ops; + iorange->base = base; + iorange->len = len; +} + +#endif From 2871a3f6b64966bc78fce0d4033bf32fcd42401c Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 17 Nov 2010 11:50:10 +0200 Subject: [PATCH 072/105] piix4 acpi: convert io BAR to type-safe ioport callbacks Acked-by: Anthony Liguori Signed-off-by: Avi Kivity Signed-off-by: Anthony Liguori --- hw/acpi_piix4.c | 55 ++++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index f549089a55..173d78148d 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -52,6 +52,7 @@ struct pci_status { typedef struct PIIX4PMState { PCIDevice dev; + IORange ioport; uint16_t pmsts; uint16_t pmen; uint16_t pmcntrl; @@ -128,10 +129,16 @@ static void pm_tmr_timer(void *opaque) pm_update_sci(s); } -static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val) +static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width, + uint64_t val) { - PIIX4PMState *s = opaque; - addr &= 0x3f; + PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport); + + if (width != 2) { + PIIX4_DPRINTF("PM write port=0x%04x width=%d val=0x%08x\n", + (unsigned)addr, width, (unsigned)val); + } + switch(addr) { case 0x00: { @@ -184,12 +191,12 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val) PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", addr, val); } -static uint32_t pm_ioport_readw(void *opaque, uint32_t addr) +static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width, + uint64_t *data) { - PIIX4PMState *s = opaque; + PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport); uint32_t val; - addr &= 0x3f; switch(addr) { case 0x00: val = get_pmsts(s); @@ -200,27 +207,6 @@ static uint32_t pm_ioport_readw(void *opaque, uint32_t addr) case 0x04: val = s->pmcntrl; break; - default: - val = 0; - break; - } - PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", addr, val); - return val; -} - -static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val) -{ - // PIIX4PMState *s = opaque; - PIIX4_DPRINTF("PM writel port=0x%04x val=0x%08x\n", addr & 0x3f, val); -} - -static uint32_t pm_ioport_readl(void *opaque, uint32_t addr) -{ - PIIX4PMState *s = opaque; - uint32_t val; - - addr &= 0x3f; - switch(addr) { case 0x08: val = get_pmtmr(s); break; @@ -228,10 +214,15 @@ static uint32_t pm_ioport_readl(void *opaque, uint32_t addr) val = 0; break; } - PIIX4_DPRINTF("PM readl port=0x%04x val=0x%08x\n", addr, val); - return val; + PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", addr, val); + *data = val; } +static const IORangeOps pm_iorange_ops = { + .read = pm_ioport_read, + .write = pm_ioport_write, +}; + static void apm_ctrl_changed(uint32_t val, void *arg) { PIIX4PMState *s = arg; @@ -265,10 +256,8 @@ static void pm_io_space_update(PIIX4PMState *s) /* XXX: need to improve memory and ioport allocation */ PIIX4_DPRINTF("PM: mapping to 0x%x\n", pm_io_base); - register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s); - register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s); - register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s); - register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s); + iorange_init(&s->ioport, &pm_iorange_ops, pm_io_base, 64); + ioport_register(&s->ioport); } } From c1ded3dc9f2d6caeb62eb3005510837a62b795d2 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 19 Oct 2010 17:03:24 +0200 Subject: [PATCH 073/105] pcnet: Do not receive external frames in loopback mode While not explicitly stated in the spec, it was observed on real systems that enabling loopback testing on the pcnet controller disables reception of external frames. And some legacy software relies on it, so provide this behavior. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- hw/pcnet.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/pcnet.c b/hw/pcnet.c index b52935adf1..f970bdaf3c 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -1048,9 +1048,10 @@ ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_) int crc_err = 0; int size = size_; - if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) + if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size || + (CSR_LOOP(s) && !s->looptest)) { return -1; - + } #ifdef PCNET_DEBUG printf("pcnet_receive size=%d\n", size); #endif From 281a26b15b4adcecb8604216738975abd754bea8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 17 Nov 2010 12:06:44 +0100 Subject: [PATCH 074/105] vgabios update: handle compatibility with older qemu versions As pointed out by avi the vgabios update is guest-visible and thus has migration implications. One change is that the vga has a valid pci rom bar now. We already have a pci bus property to enable/disable the rom bar and we'll load the bios via fw_cfg as fallback for the no-rom-bar case. So we just have to add compat properties to handle this case. A second change is that the magic bochs lfb @ 0xe0000000 is gone. When live-migrating a guest from a older qemu version it might be using the lfb though, so we have to keep it for the old machine types. The patch enables the bochs lfb in case we don't have the pci rom bar enabled (i.e. we are in 0.13+older compat mode). This patch depends on these patches which add (and use) the pc-0.13 machine type: http://patchwork.ozlabs.org/patch/70797/ http://patchwork.ozlabs.org/patch/70798/ Signed-off-by: Gerd Hoffmann Cc: avi@redhat.com Signed-off-by: Anthony Liguori --- hw/pc_piix.c | 16 ++++++++++++++++ hw/vga-pci.c | 5 +++++ hw/vmware_vga.c | 5 +++++ 3 files changed, 26 insertions(+) diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 31c80d273b..7d29d43190 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -230,6 +230,14 @@ static QEMUMachine pc_machine_v0_13 = { .driver = "virtio-9p-pci", .property = "vectors", .value = stringify(0), + },{ + .driver = "VGA", + .property = "rombar", + .value = stringify(0), + },{ + .driver = "vmware-svga", + .property = "rombar", + .value = stringify(0), }, { /* end of list */ } }, @@ -249,6 +257,14 @@ static QEMUMachine pc_machine_v0_12 = { .driver = "virtio-serial-pci", .property = "vectors", .value = stringify(0), + },{ + .driver = "VGA", + .property = "rombar", + .value = stringify(0), + },{ + .driver = "vmware-svga", + .property = "rombar", + .value = stringify(0), }, { /* end of list */ } } diff --git a/hw/vga-pci.c b/hw/vga-pci.c index b09789cd11..791ca22763 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -92,6 +92,11 @@ static int pci_vga_initfn(PCIDevice *dev) pci_register_bar(&d->dev, 0, VGA_RAM_SIZE, PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map); + if (!dev->rom_bar) { + /* compatibility with pc-0.13 and older */ + vga_init_vbe(s); + } + return 0; } diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 9337fdbfef..d0f4e1b5b5 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -1301,6 +1301,11 @@ static int pci_vmsvga_initfn(PCIDevice *dev) vmsvga_init(&s->chip, VGA_RAM_SIZE); + if (!dev->rom_bar) { + /* compatibility with pc-0.13 and older */ + vga_init_vbe(&s->chip.vga); + } + return 0; } From 870cef1dae88f131ee3e17fe0aaf45d609798ce1 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 15 Nov 2010 20:44:35 +0000 Subject: [PATCH 075/105] virtio-blk: Convert fprintf() to error_report() Errors should be logged using error_report() so they go to the appropriate monitor. Signed-off-by: Stefan Hajnoczi Signed-off-by: Anthony Liguori --- hw/virtio-blk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 49528a9977..e5f9b2795a 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -324,13 +324,13 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) { if (req->elem.out_num < 1 || req->elem.in_num < 1) { - fprintf(stderr, "virtio-blk missing headers\n"); + error_report("virtio-blk missing headers"); exit(1); } if (req->elem.out_sg[0].iov_len < sizeof(*req->out) || req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) { - fprintf(stderr, "virtio-blk header not in correct element\n"); + error_report("virtio-blk header not in correct element"); exit(1); } From cd92f4cc22fbe12a7bf60c9430731f768dc1537c Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 15 Nov 2010 20:44:36 +0000 Subject: [PATCH 076/105] virtio: Convert fprintf() to error_report() Signed-off-by: Stefan Hajnoczi Signed-off-by: Anthony Liguori --- hw/virtio.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/hw/virtio.c b/hw/virtio.c index a2a657e132..849a60faaa 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -14,6 +14,7 @@ #include #include "trace.h" +#include "qemu-error.h" #include "virtio.h" #include "sysemu.h" @@ -253,8 +254,8 @@ static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx) /* Check it isn't doing very strange things with descriptor numbers. */ if (num_heads > vq->vring.num) { - fprintf(stderr, "Guest moved used index from %u to %u", - idx, vring_avail_idx(vq)); + error_report("Guest moved used index from %u to %u", + idx, vring_avail_idx(vq)); exit(1); } @@ -271,7 +272,7 @@ static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx) /* If their number is silly, that's a fatal mistake. */ if (head >= vq->vring.num) { - fprintf(stderr, "Guest says index %u is available", head); + error_report("Guest says index %u is available", head); exit(1); } @@ -293,7 +294,7 @@ static unsigned virtqueue_next_desc(target_phys_addr_t desc_pa, wmb(); if (next >= max) { - fprintf(stderr, "Desc next is %u", next); + error_report("Desc next is %u", next); exit(1); } @@ -320,13 +321,13 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes) if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) { if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) { - fprintf(stderr, "Invalid size for indirect buffer table\n"); + error_report("Invalid size for indirect buffer table"); exit(1); } /* If we've got too many, that implies a descriptor loop. */ if (num_bufs >= max) { - fprintf(stderr, "Looped descriptor"); + error_report("Looped descriptor"); exit(1); } @@ -340,7 +341,7 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes) do { /* If we've got too many, that implies a descriptor loop. */ if (++num_bufs > max) { - fprintf(stderr, "Looped descriptor"); + error_report("Looped descriptor"); exit(1); } @@ -374,7 +375,7 @@ void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr, len = sg[i].iov_len; sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write); if (sg[i].iov_base == NULL || len != sg[i].iov_len) { - fprintf(stderr, "virtio: trying to map MMIO memory\n"); + error_report("virtio: trying to map MMIO memory"); exit(1); } } @@ -397,7 +398,7 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) { if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) { - fprintf(stderr, "Invalid size for indirect buffer table\n"); + error_report("Invalid size for indirect buffer table"); exit(1); } @@ -423,7 +424,7 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) /* If we've got too many, that implies a descriptor loop. */ if ((elem->in_num + elem->out_num) > max) { - fprintf(stderr, "Looped descriptor"); + error_report("Looped descriptor"); exit(1); } } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max); @@ -694,8 +695,8 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) qemu_get_be16s(f, &vdev->queue_sel); qemu_get_be32s(f, &features); if (features & ~supported_features) { - fprintf(stderr, "Features 0x%x unsupported. Allowed features: 0x%x\n", - features, supported_features); + error_report("Features 0x%x unsupported. Allowed features: 0x%x", + features, supported_features); return -1; } if (vdev->set_features) @@ -717,11 +718,11 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) num_heads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx; /* Check it isn't doing very strange things with descriptor numbers. */ if (num_heads > vdev->vq[i].vring.num) { - fprintf(stderr, "VQ %d size 0x%x Guest index 0x%x " - "inconsistent with Host index 0x%x: delta 0x%x\n", - i, vdev->vq[i].vring.num, - vring_avail_idx(&vdev->vq[i]), - vdev->vq[i].last_avail_idx, num_heads); + error_report("VQ %d size 0x%x Guest index 0x%x " + "inconsistent with Host index 0x%x: delta 0x%x", + i, vdev->vq[i].vring.num, + vring_avail_idx(&vdev->vq[i]), + vdev->vq[i].last_avail_idx, num_heads); return -1; } if (vdev->binding->load_queue) { From e7b43f7e60a0a170356e82b01b8ffdcecafad7ed Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 15 Nov 2010 20:44:37 +0000 Subject: [PATCH 077/105] virtio-net: Convert fprintf() to error_report() Signed-off-by: Stefan Hajnoczi Signed-off-by: Anthony Liguori --- hw/virtio-net.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 7e1688cf69..1d61f191b6 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -120,8 +120,8 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) if (!n->vhost_started) { int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), &n->vdev); if (r < 0) { - fprintf(stderr, "unable to start vhost net: %d: " - "falling back on userspace virtio\n", -r); + error_report("unable to start vhost net: %d: " + "falling back on userspace virtio", -r); } else { n->vhost_started = 1; } @@ -271,7 +271,7 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, uint8_t on; if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(on)) { - fprintf(stderr, "virtio-net ctrl invalid rx mode command\n"); + error_report("virtio-net ctrl invalid rx mode command"); exit(1); } @@ -353,7 +353,7 @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd, uint16_t vid; if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(vid)) { - fprintf(stderr, "virtio-net ctrl invalid vlan command\n"); + error_report("virtio-net ctrl invalid vlan command"); return VIRTIO_NET_ERR; } @@ -381,13 +381,13 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) while (virtqueue_pop(vq, &elem)) { if ((elem.in_num < 1) || (elem.out_num < 1)) { - fprintf(stderr, "virtio-net ctrl missing headers\n"); + error_report("virtio-net ctrl missing headers"); exit(1); } if (elem.out_sg[0].iov_len < sizeof(ctrl) || elem.in_sg[elem.in_num - 1].iov_len < sizeof(status)) { - fprintf(stderr, "virtio-net ctrl header not in correct element\n"); + error_report("virtio-net ctrl header not in correct element"); exit(1); } @@ -591,21 +591,21 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_ if (virtqueue_pop(n->rx_vq, &elem) == 0) { if (i == 0) return -1; - fprintf(stderr, "virtio-net unexpected empty queue: " + error_report("virtio-net unexpected empty queue: " "i %zd mergeable %d offset %zd, size %zd, " - "guest hdr len %zd, host hdr len %zd guest features 0x%x\n", + "guest hdr len %zd, host hdr len %zd guest features 0x%x", i, n->mergeable_rx_bufs, offset, size, guest_hdr_len, host_hdr_len, n->vdev.guest_features); exit(1); } if (elem.in_num < 1) { - fprintf(stderr, "virtio-net receive queue contains no in buffers\n"); + error_report("virtio-net receive queue contains no in buffers"); exit(1); } if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != guest_hdr_len) { - fprintf(stderr, "virtio-net header not in first element\n"); + error_report("virtio-net header not in first element"); exit(1); } @@ -630,12 +630,11 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_ * Otherwise, drop it. */ if (!n->mergeable_rx_bufs && offset < size) { #if 0 - fprintf(stderr, "virtio-net truncated non-mergeable packet: " - - "i %zd mergeable %d offset %zd, size %zd, " - "guest hdr len %zd, host hdr len %zd\n", - i, n->mergeable_rx_bufs, - offset, size, guest_hdr_len, host_hdr_len); + error_report("virtio-net truncated non-mergeable packet: " + "i %zd mergeable %d offset %zd, size %zd, " + "guest hdr len %zd, host hdr len %zd", + i, n->mergeable_rx_bufs, + offset, size, guest_hdr_len, host_hdr_len); #endif return size; } @@ -695,7 +694,7 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq) sizeof(struct virtio_net_hdr); if (out_num < 1 || out_sg->iov_len != hdr_len) { - fprintf(stderr, "virtio-net header not in first element\n"); + error_report("virtio-net header not in first element"); exit(1); } @@ -981,10 +980,10 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); if (net->tx && strcmp(net->tx, "timer") && strcmp(net->tx, "bh")) { - fprintf(stderr, "virtio-net: " - "Unknown option tx=%s, valid options: \"timer\" \"bh\"\n", - net->tx); - fprintf(stderr, "Defaulting to \"bh\"\n"); + error_report("virtio-net: " + "Unknown option tx=%s, valid options: \"timer\" \"bh\"", + net->tx); + error_report("Defaulting to \"bh\""); } if (net->tx && !strcmp(net->tx, "timer")) { From 4e02d460dd4b60847a1e8b689cb676e3e1f3de95 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 15 Nov 2010 20:44:38 +0000 Subject: [PATCH 078/105] virtio-pci: Convert fprintf() to error_report() Signed-off-by: Stefan Hajnoczi Signed-off-by: Anthony Liguori --- hw/virtio-pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 3610d7e233..c65765a273 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -254,8 +254,8 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) virtio_queue_set_vector(vdev, vdev->queue_sel, val); break; default: - fprintf(stderr, "%s: unexpected address 0x%x value 0x%x\n", - __func__, addr, val); + error_report("%s: unexpected address 0x%x value 0x%x", + __func__, addr, val); break; } } From f711df67d611e4762966a249742a5f7499e19f99 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 22 Nov 2010 14:57:52 -0800 Subject: [PATCH 079/105] microblaze: target-ify target_ucontext Rename the members of target_ucontext so that they don't conflict with possible host macros for ucontext members. This has already been done for the other targets. Signed-off-by: Richard Henderson Signed-off-by: Edgar E. Iglesias --- linux-user/signal.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 77683f7534..7c62fac938 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -3071,11 +3071,11 @@ struct target_stack_t { }; struct target_ucontext { - abi_ulong uc_flags; - abi_ulong uc_link; - struct target_stack_t uc_stack; - struct target_sigcontext sc; - uint32_t extramask[TARGET_NSIG_WORDS - 1]; + abi_ulong tuc_flags; + abi_ulong tuc_link; + struct target_stack_t tuc_stack; + struct target_sigcontext tuc_mcontext; + uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1]; }; /* Signal frames. */ @@ -3189,7 +3189,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, goto badframe; /* Save the mask. */ - err |= __put_user(set->sig[0], &frame->uc.sc.oldmask); + err |= __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask); if (err) goto badframe; @@ -3198,7 +3198,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, goto badframe; } - setup_sigcontext(&frame->uc.sc, env); + setup_sigcontext(&frame->uc.tuc_mcontext, env); /* Set up to return from userspace. If provided, use a stub already in userspace. */ @@ -3261,7 +3261,7 @@ long do_sigreturn(CPUState *env) goto badframe; /* Restore blocked signals */ - if (__get_user(target_set.sig[0], &frame->uc.sc.oldmask)) + if (__get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask)) goto badframe; for(i = 1; i < TARGET_NSIG_WORDS; i++) { if (__get_user(target_set.sig[i], &frame->extramask[i - 1])) @@ -3270,7 +3270,7 @@ long do_sigreturn(CPUState *env) target_to_host_sigset_internal(&set, &target_set); sigprocmask(SIG_SETMASK, &set, NULL); - restore_sigcontext(&frame->uc.sc, env); + restore_sigcontext(&frame->uc.tuc_mcontext, env); /* We got here through a sigreturn syscall, our path back is via an rtb insn so setup r14 for that. */ env->regs[14] = env->sregs[SR_PC]; From 6fa2c95f279dda62aa7e3292cc424ff3fab6a602 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Fri, 12 Nov 2010 09:57:11 +0000 Subject: [PATCH 080/105] scsi-disk: Move active request asserts SCSI read/write requests should not be re-issued before the current fragment of I/O completes. There are asserts in scsi-disk.c that guard this constraint but they trigger on SPARC Linux 2.4. It turns out that the asserts are too early in the code path and don't allow for read requests to terminate. Only the read assert needs to be moved but move the write assert too for consistency. Reported-by: Nigel Horne Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- hw/scsi-disk.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index dc719578b0..7d85899ca8 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -170,6 +170,9 @@ static void scsi_read_request(SCSIDiskReq *r) return; } + /* No data transfer may already be in progress */ + assert(r->req.aiocb == NULL); + n = r->sector_count; if (n > SCSI_DMA_BUF_SIZE / 512) n = SCSI_DMA_BUF_SIZE / 512; @@ -197,9 +200,6 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) return; } - /* No data transfer may already be in progress */ - assert(r->req.aiocb == NULL); - scsi_read_request(r); } @@ -269,6 +269,9 @@ static void scsi_write_request(SCSIDiskReq *r) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); uint32_t n; + /* No data transfer may already be in progress */ + assert(r->req.aiocb == NULL); + n = r->iov.iov_len / 512; if (n) { qemu_iovec_init_external(&r->qiov, &r->iov, 1); @@ -298,9 +301,6 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) return 1; } - /* No data transfer may already be in progress */ - assert(r->req.aiocb == NULL); - scsi_write_request(r); return 0; From 9063f81415f3518ef8206e74085c2a92c96890a0 Mon Sep 17 00:00:00 2001 From: Ryan Harper Date: Fri, 12 Nov 2010 11:07:13 -0600 Subject: [PATCH 081/105] Implement drive_del to decouple block removal from device removal Currently device hotplug removal code is tied to device removal via ACPI. All pci devices that are removable via device_del() require the guest to respond to the request. In some cases the guest may not respond leaving the device still accessible to the guest. The management layer doesn't currently have a reliable way to revoke access to host resource in the presence of an uncooperative guest. This patch implements a new monitor command, drive_del, which provides an explicit command to revoke access to a host block device. drive_del first quiesces the block device (qemu_aio_flush; bdrv_flush() and bdrv_close()). This prevents further IO from being submitted against the host device. Finally, drive_del cleans up pointers between the drive object (host resource) and the device object (guest resource). Signed-off-by: Ryan Harper Signed-off-by: Kevin Wolf --- blockdev.c | 39 +++++++++++++++++++++++++++++++++++++++ blockdev.h | 1 + hmp-commands.hx | 18 ++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/blockdev.c b/blockdev.c index 6cb179a409..f6ac4398b8 100644 --- a/blockdev.c +++ b/blockdev.c @@ -14,6 +14,8 @@ #include "qemu-option.h" #include "qemu-config.h" #include "sysemu.h" +#include "hw/qdev.h" +#include "block_int.h" static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives); @@ -597,3 +599,40 @@ int do_change_block(Monitor *mon, const char *device, } return monitor_read_bdrv_key_start(mon, bs, NULL, NULL); } + +int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + const char *id = qdict_get_str(qdict, "id"); + BlockDriverState *bs; + BlockDriverState **ptr; + Property *prop; + + bs = bdrv_find(id); + if (!bs) { + qerror_report(QERR_DEVICE_NOT_FOUND, id); + return -1; + } + + /* quiesce block driver; prevent further io */ + qemu_aio_flush(); + bdrv_flush(bs); + bdrv_close(bs); + + /* clean up guest state from pointing to host resource by + * finding and removing DeviceState "drive" property */ + for (prop = bs->peer->info->props; prop && prop->name; prop++) { + if (prop->info->type == PROP_TYPE_DRIVE) { + ptr = qdev_get_prop_ptr(bs->peer, prop); + if ((*ptr) == bs) { + bdrv_detach(bs, bs->peer); + *ptr = NULL; + break; + } + } + } + + /* clean up host side */ + drive_uninit(drive_get_by_blockdev(bs)); + + return 0; +} diff --git a/blockdev.h b/blockdev.h index 653affcc9b..2a0559ef65 100644 --- a/blockdev.h +++ b/blockdev.h @@ -51,5 +51,6 @@ int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data); int do_block_set_passwd(Monitor *mon, const QDict *qdict, QObject **ret_data); int do_change_block(Monitor *mon, const char *device, const char *filename, const char *fmt); +int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data); #endif diff --git a/hmp-commands.hx b/hmp-commands.hx index e5585ba0e9..23024ba6f2 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -65,6 +65,24 @@ STEXI @item eject [-f] @var{device} @findex eject Eject a removable medium (use -f to force it). +ETEXI + + { + .name = "drive_del", + .args_type = "id:s", + .params = "device", + .help = "remove host block device", + .user_print = monitor_user_noop, + .mhandler.cmd_new = do_drive_del, + }, + +STEXI +@item drive_del @var{device} +@findex drive_del +Remove host block device. The result is that guest generated IO is no longer +submitted against the host device underlying the disk. Once a drive has +been deleted, the QEMU Block layer returns -EIO which results in IO +errors in the guest for applications that are reading/writing to the device. ETEXI { From 62155e2b51e3c282ddc30adbb6d7b8d3bb7c386e Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Fri, 12 Nov 2010 16:07:50 -0200 Subject: [PATCH 082/105] block migration: do not submit multiple AIOs for same sector (v2) An old version of this patch was applied to master, so this contains the differences between v1 and v2. Signed-off-by: Marcelo Tosatti Signed-off-by: Kevin Wolf --- block-migration.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/block-migration.c b/block-migration.c index 3e66f49350..14753254d6 100644 --- a/block-migration.c +++ b/block-migration.c @@ -146,8 +146,7 @@ static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector) { int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK; - if (bmds->aio_bitmap && - (sector << BDRV_SECTOR_BITS) < bdrv_getlength(bmds->bs)) { + if ((sector << BDRV_SECTOR_BITS) < bdrv_getlength(bmds->bs)) { return !!(bmds->aio_bitmap[chunk / (sizeof(unsigned long) * 8)] & (1UL << (chunk % (sizeof(unsigned long) * 8)))); } else { @@ -169,13 +168,9 @@ static void bmds_set_aio_inflight(BlkMigDevState *bmds, int64_t sector_num, bit = start % (sizeof(unsigned long) * 8); val = bmds->aio_bitmap[idx]; if (set) { - if (!(val & (1UL << bit))) { - val |= 1UL << bit; - } + val |= 1UL << bit; } else { - if (val & (1UL << bit)) { - val &= ~(1UL << bit); - } + val &= ~(1UL << bit); } bmds->aio_bitmap[idx] = val; } @@ -385,8 +380,9 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f, int nr_sectors; for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) { - if (bmds_aio_inflight(bmds, sector)) + if (bmds_aio_inflight(bmds, sector)) { qemu_aio_flush(); + } if (bdrv_get_dirty(bmds->bs, sector)) { if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) { From 9fbef1ac7cc888f29435e9f636b5dd14cd3260df Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 21 Nov 2010 18:29:52 +0200 Subject: [PATCH 083/105] ide: convert bmdma address ioport to ioport_register() cmd646, via compile tested, pci lightly boot tested. Signed-off-by: Avi Kivity Signed-off-by: Kevin Wolf --- hw/ide/cmd646.c | 8 ++--- hw/ide/internal.h | 2 ++ hw/ide/pci.c | 75 +++++++++++++---------------------------------- hw/ide/pci.h | 7 +---- hw/ide/piix.c | 8 ++--- hw/ide/via.c | 8 ++--- 6 files changed, 29 insertions(+), 79 deletions(-) diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index ff80dd557f..dfe6091e75 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -179,12 +179,8 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num, register_ioport_read(addr, 4, 1, bmdma_readb_1, d); } - register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm); - register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm); - register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm); - register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm); - register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm); - register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm); + iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4); + ioport_register(&bm->addr_ioport); addr += 8; } } diff --git a/hw/ide/internal.h b/hw/ide/internal.h index d652e06c45..85f4a1607b 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -8,6 +8,7 @@ */ #include #include "block_int.h" +#include "iorange.h" /* debug IDE devices */ //#define DEBUG_IDE @@ -496,6 +497,7 @@ struct BMDMAState { QEMUIOVector qiov; int64_t sector_num; uint32_t nsector; + IORange addr_ioport; QEMUBH *bh; }; diff --git a/hw/ide/pci.c b/hw/ide/pci.c index ec90f266e9..3722b774b2 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -73,72 +73,37 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) } } -uint32_t bmdma_addr_readb(void *opaque, uint32_t addr) +static void bmdma_addr_read(IORange *ioport, uint64_t addr, + unsigned width, uint64_t *data) { - BMDMAState *bm = opaque; - uint32_t val; - val = (bm->addr >> ((addr & 3) * 8)) & 0xff; + BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport); + uint32_t mask = (1ULL << (width * 8)) - 1; + + *data = (bm->addr >> (addr * 8)) & mask; #ifdef DEBUG_IDE - printf("%s: 0x%08x\n", __func__, val); + printf("%s: 0x%08x\n", __func__, (unsigned)*data); #endif - return val; } -void bmdma_addr_writeb(void *opaque, uint32_t addr, uint32_t val) +static void bmdma_addr_write(IORange *ioport, uint64_t addr, + unsigned width, uint64_t data) { - BMDMAState *bm = opaque; - int shift = (addr & 3) * 8; + BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport); + int shift = addr * 8; + uint32_t mask = (1ULL << (width * 8)) - 1; + #ifdef DEBUG_IDE - printf("%s: 0x%08x\n", __func__, val); + printf("%s: 0x%08x\n", __func__, (unsigned)data); #endif - bm->addr &= ~(0xFF << shift); - bm->addr |= ((val & 0xFF) << shift) & ~3; + bm->addr &= ~(mask << shift); + bm->addr |= ((data & mask) << shift) & ~3; bm->cur_addr = bm->addr; } -uint32_t bmdma_addr_readw(void *opaque, uint32_t addr) -{ - BMDMAState *bm = opaque; - uint32_t val; - val = (bm->addr >> ((addr & 3) * 8)) & 0xffff; -#ifdef DEBUG_IDE - printf("%s: 0x%08x\n", __func__, val); -#endif - return val; -} - -void bmdma_addr_writew(void *opaque, uint32_t addr, uint32_t val) -{ - BMDMAState *bm = opaque; - int shift = (addr & 3) * 8; -#ifdef DEBUG_IDE - printf("%s: 0x%08x\n", __func__, val); -#endif - bm->addr &= ~(0xFFFF << shift); - bm->addr |= ((val & 0xFFFF) << shift) & ~3; - bm->cur_addr = bm->addr; -} - -uint32_t bmdma_addr_readl(void *opaque, uint32_t addr) -{ - BMDMAState *bm = opaque; - uint32_t val; - val = bm->addr; -#ifdef DEBUG_IDE - printf("%s: 0x%08x\n", __func__, val); -#endif - return val; -} - -void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val) -{ - BMDMAState *bm = opaque; -#ifdef DEBUG_IDE - printf("%s: 0x%08x\n", __func__, val); -#endif - bm->addr = val & ~3; - bm->cur_addr = bm->addr; -} +const IORangeOps bmdma_addr_ioport_ops = { + .read = bmdma_addr_read, + .write = bmdma_addr_write, +}; static bool ide_bmdma_current_needed(void *opaque) { diff --git a/hw/ide/pci.h b/hw/ide/pci.h index d46a95eb90..b81b26c532 100644 --- a/hw/ide/pci.h +++ b/hw/ide/pci.h @@ -11,12 +11,7 @@ typedef struct PCIIDEState { } PCIIDEState; void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val); -uint32_t bmdma_addr_readb(void *opaque, uint32_t addr); -void bmdma_addr_writeb(void *opaque, uint32_t addr, uint32_t val); -uint32_t bmdma_addr_readw(void *opaque, uint32_t addr); -void bmdma_addr_writew(void *opaque, uint32_t addr, uint32_t val); -uint32_t bmdma_addr_readl(void *opaque, uint32_t addr); -void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val); +extern const IORangeOps bmdma_addr_ioport_ops; void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table); extern const VMStateDescription vmstate_ide_pci; diff --git a/hw/ide/piix.c b/hw/ide/piix.c index 07483e845c..e02b89a38c 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -85,12 +85,8 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num, register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm); register_ioport_read(addr, 4, 1, bmdma_readb, bm); - register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm); - register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm); - register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm); - register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm); - register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm); - register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm); + iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4); + ioport_register(&bm->addr_ioport); addr += 8; } } diff --git a/hw/ide/via.c b/hw/ide/via.c index b2c7cad622..3e41d005b1 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -87,12 +87,8 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num, register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm); register_ioport_read(addr, 4, 1, bmdma_readb, bm); - register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm); - register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm); - register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm); - register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm); - register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm); - register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm); + iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4); + ioport_register(&bm->addr_ioport); addr += 8; } } From 5cbdebe39e08caf5a373ef1c03a0292d5af955ce Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Wed, 24 Nov 2010 13:08:03 +0000 Subject: [PATCH 084/105] qemu and qemu-xen: support empty write barriers in xen_disk This patch can be applied to both qemu-xen and qemu and adds support for empty write barriers to xen_disk. Signed-off-by: Stefano Stabellini Acked-by: Gerd Hoffmann Signed-off-by: Kevin Wolf --- hw/xen_disk.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/hw/xen_disk.c b/hw/xen_disk.c index 134ac3388e..85a1c85524 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -181,6 +181,10 @@ static int ioreq_parse(struct ioreq *ioreq) ioreq->prot = PROT_WRITE; /* to memory */ break; case BLKIF_OP_WRITE_BARRIER: + if (!ioreq->req.nr_segments) { + ioreq->presync = 1; + return 0; + } if (!syncwrite) ioreq->presync = ioreq->postsync = 1; /* fall through */ @@ -305,7 +309,7 @@ static int ioreq_runio_qemu_sync(struct ioreq *ioreq) int i, rc, len = 0; off_t pos; - if (ioreq_map(ioreq) == -1) + if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) goto err; if (ioreq->presync) bdrv_flush(blkdev->bs); @@ -329,6 +333,8 @@ static int ioreq_runio_qemu_sync(struct ioreq *ioreq) break; case BLKIF_OP_WRITE: case BLKIF_OP_WRITE_BARRIER: + if (!ioreq->req.nr_segments) + break; pos = ioreq->start; for (i = 0; i < ioreq->v.niov; i++) { rc = bdrv_write(blkdev->bs, pos / BLOCK_SIZE, @@ -386,7 +392,7 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) { struct XenBlkDev *blkdev = ioreq->blkdev; - if (ioreq_map(ioreq) == -1) + if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) goto err; ioreq->aio_inflight++; @@ -403,6 +409,8 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) case BLKIF_OP_WRITE: case BLKIF_OP_WRITE_BARRIER: ioreq->aio_inflight++; + if (!ioreq->req.nr_segments) + break; bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE, &ioreq->v, ioreq->v.size / BLOCK_SIZE, qemu_aio_complete, ioreq); From 80465c5016f23d8b39efb36db2ca77a35f67eaef Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 16 Nov 2010 18:55:01 +0100 Subject: [PATCH 085/105] block: Remove unused s->hd in various drivers All drivers use bs->file instead of s->hd for quite a while now, so it's time to remove s->hd. Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- block/qcow.c | 1 - block/qcow2.h | 1 - block/vdi.c | 1 - block/vmdk.c | 1 - block/vpc.c | 2 -- 5 files changed, 6 deletions(-) diff --git a/block/qcow.c b/block/qcow.c index 9cd547dc02..f67d3d39f2 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -54,7 +54,6 @@ typedef struct QCowHeader { #define L2_CACHE_SIZE 16 typedef struct BDRVQcowState { - BlockDriverState *hd; int cluster_bits; int cluster_size; int cluster_sectors; diff --git a/block/qcow2.h b/block/qcow2.h index 2d22e5ec47..5217bea8a2 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -79,7 +79,6 @@ typedef struct QCowSnapshot { } QCowSnapshot; typedef struct BDRVQcowState { - BlockDriverState *hd; int cluster_bits; int cluster_size; int cluster_sectors; diff --git a/block/vdi.c b/block/vdi.c index 3b51e532c4..ab8f70f17e 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -186,7 +186,6 @@ typedef struct { } VdiHeader; typedef struct { - BlockDriverState *hd; /* The block map entries are little endian (even in memory). */ uint32_t *bmap; /* Size of block (bytes). */ diff --git a/block/vmdk.c b/block/vmdk.c index 872aebac9b..8fc9d67208 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -61,7 +61,6 @@ typedef struct { #define L2_CACHE_SIZE 16 typedef struct BDRVVmdkState { - BlockDriverState *hd; int64_t l1_table_offset; int64_t l1_backup_table_offset; uint32_t *l1_table; diff --git a/block/vpc.c b/block/vpc.c index 416f48900c..21e2a6870c 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -110,8 +110,6 @@ struct vhd_dyndisk_header { }; typedef struct BDRVVPCState { - BlockDriverState *hd; - uint8_t footer_buf[HEADER_SIZE]; uint64_t free_data_block_offset; int max_table_entries; From 622b520fb4ca50b5028485f1d225317ece0a42b9 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 24 Nov 2010 12:15:56 +0100 Subject: [PATCH 086/105] scsi: Increase the number of possible devices The SCSI parallel interface has a limit of 8 devices, but not the SCSI stack in general. So we should be removing the hard-coded limit and use MAX_SCSI_DEVS instead. And we only need to scan those devices which are allocated by the bus. Signed-off-by: Hannes Reinecke Acked-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- blockdev.h | 2 +- hw/scsi-bus.c | 2 +- hw/scsi.h | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/blockdev.h b/blockdev.h index 2a0559ef65..4cb8ca93d4 100644 --- a/blockdev.h +++ b/blockdev.h @@ -32,7 +32,7 @@ struct DriveInfo { }; #define MAX_IDE_DEVS 2 -#define MAX_SCSI_DEVS 7 +#define MAX_SCSI_DEVS 255 DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit); int drive_get_max_bus(BlockInterfaceType type); diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 5a3fd4b7ac..74a08b7da6 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -108,7 +108,7 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus) int res = 0, unit; loc_push_none(&loc); - for (unit = 0; unit < MAX_SCSI_DEVS; unit++) { + for (unit = 0; unit < bus->ndev; unit++) { dinfo = drive_get(IF_SCSI, bus->busnr, unit); if (dinfo == NULL) { continue; diff --git a/hw/scsi.h b/hw/scsi.h index cb06d6d824..9c798ae795 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -3,6 +3,7 @@ #include "qdev.h" #include "block.h" +#include "blockdev.h" #include "block_int.h" #define SCSI_CMD_BUF_SIZE 16 @@ -86,7 +87,7 @@ struct SCSIBus { int tcq, ndev; scsi_completionfn complete; - SCSIDevice *devs[8]; + SCSIDevice *devs[MAX_SCSI_DEVS]; }; void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev, From f017132793065abcdc4b9b78d7ca575eeb3de484 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 24 Nov 2010 12:15:57 +0100 Subject: [PATCH 087/105] scsi: Return SAM status codes Traditionally, the linux stack is using SCSI status codes which are shifted by one as compared to those defined in SAM. A SCSI emulation should naturally return the SAM defined codes, not the linux ones. So to avoid any confusion this patch modifies the existing definitions to match those found in SAM and removes any (now obsolete) byte-shift from the returned status codes. Signed-off-by: Hannes Reinecke Acked-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- hw/scsi-defs.h | 20 +++++++++++--------- hw/scsi-generic.c | 10 +++++----- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h index a4a3518eb8..1473ecbddc 100644 --- a/hw/scsi-defs.h +++ b/hw/scsi-defs.h @@ -111,18 +111,20 @@ #define BLANK 0xa1 /* - * Status codes + * SAM Status codes */ #define GOOD 0x00 -#define CHECK_CONDITION 0x01 -#define CONDITION_GOOD 0x02 -#define BUSY 0x04 -#define INTERMEDIATE_GOOD 0x08 -#define INTERMEDIATE_C_GOOD 0x0a -#define RESERVATION_CONFLICT 0x0c -#define COMMAND_TERMINATED 0x11 -#define QUEUE_FULL 0x14 +#define CHECK_CONDITION 0x02 +#define CONDITION_GOOD 0x04 +#define BUSY 0x08 +#define INTERMEDIATE_GOOD 0x10 +#define INTERMEDIATE_C_GOOD 0x14 +#define RESERVATION_CONFLICT 0x18 +#define COMMAND_TERMINATED 0x22 +#define TASK_SET_FULL 0x28 +#define ACA_ACTIVE 0x30 +#define TASK_ABORTED 0x40 #define STATUS_MASK 0x3e diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 7212091695..9be1cca4c3 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -96,17 +96,17 @@ static void scsi_command_complete(void *opaque, int ret) s->senselen = r->io_header.sb_len_wr; if (ret != 0) - r->req.status = BUSY << 1; + r->req.status = BUSY; else { if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) { - r->req.status = BUSY << 1; + r->req.status = BUSY; BADF("Driver Timeout\n"); } else if (r->io_header.status) r->req.status = r->io_header.status; else if (s->driver_status & SG_ERR_DRIVER_SENSE) - r->req.status = CHECK_CONDITION << 1; + r->req.status = CHECK_CONDITION; else - r->req.status = GOOD << 1; + r->req.status = GOOD; } DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", r, r->req.tag, r->req.status); @@ -333,7 +333,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, s->senselen = 7; s->driver_status = SG_ERR_DRIVER_SENSE; bus = scsi_bus_from_device(d); - bus->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION << 1); + bus->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION); return 0; } From 39d989823f2c177415a22b84b354716a1f734b70 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 24 Nov 2010 12:15:58 +0100 Subject: [PATCH 088/105] scsi: INQUIRY VPD fixes We should announce and support the block device characterics page only on block devices, not on CDROMs. And the VPD page 0x83 has an off-by-one error. Signed-off-by: Hannes Reinecke Acked-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- hw/scsi-disk.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 7d85899ca8..c41dcfc78b 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -398,15 +398,20 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) switch (page_code) { case 0x00: /* Supported page codes, mandatory */ + { + int pages; DPRINTF("Inquiry EVPD[Supported pages] " "buffer size %zd\n", req->cmd.xfer); - outbuf[buflen++] = 4; // number of pages + pages = buflen++; outbuf[buflen++] = 0x00; // list of supported pages (this page) outbuf[buflen++] = 0x80; // unit serial number outbuf[buflen++] = 0x83; // device identification - outbuf[buflen++] = 0xb0; // block device characteristics + if (bdrv_get_type_hint(s->bs) != BDRV_TYPE_CDROM) { + outbuf[buflen++] = 0xb0; // block device characteristics + } + outbuf[pages] = buflen - pages - 1; // number of pages break; - + } case 0x80: /* Device serial number, optional */ { int l = strlen(s->serial); @@ -434,7 +439,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) DPRINTF("Inquiry EVPD[Device identification] " "buffer size %zd\n", req->cmd.xfer); - outbuf[buflen++] = 3 + id_len; + outbuf[buflen++] = 4 + id_len; outbuf[buflen++] = 0x2; // ASCII outbuf[buflen++] = 0; // not officially assigned outbuf[buflen++] = 0; // reserved @@ -451,6 +456,11 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) unsigned int opt_io_size = s->qdev.conf.opt_io_size / s->qdev.blocksize; + if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { + DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n", + page_code); + return -1; + } /* required VPD size with unmap support */ outbuf[3] = buflen = 0x3c; From a6d96eb78bd1f87ab9d6a377f863f99be4b71538 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 24 Nov 2010 12:15:59 +0100 Subject: [PATCH 089/105] scsi: Move sense handling into the driver The current sense handling in scsi-bus is only used by the scsi-disk driver; the scsi-generic driver is using its own. So we should move the current sense handling into the scsi-disk driver. Signed-off-by: Hannes Reinecke Acked-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- hw/scsi-bus.c | 10 ---------- hw/scsi-disk.c | 33 +++++++++++++++++++++++++-------- hw/scsi.h | 8 -------- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 74a08b7da6..93f0e9abc1 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -123,16 +123,6 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus) return res; } -void scsi_dev_clear_sense(SCSIDevice *dev) -{ - memset(&dev->sense, 0, sizeof(dev->sense)); -} - -void scsi_dev_set_sense(SCSIDevice *dev, uint8_t key) -{ - dev->sense.key = key; -} - SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun) { SCSIRequest *req; diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index c41dcfc78b..d692fb02ef 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -49,6 +49,10 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0) typedef struct SCSIDiskState SCSIDiskState; +typedef struct SCSISense { + uint8_t key; +} SCSISense; + typedef struct SCSIDiskReq { SCSIRequest req; /* ??? We should probably keep track of whether the data transfer is @@ -72,6 +76,7 @@ struct SCSIDiskState QEMUBH *bh; char *version; char *serial; + SCSISense sense; }; static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type); @@ -100,10 +105,22 @@ static SCSIDiskReq *scsi_find_request(SCSIDiskState *s, uint32_t tag) return DO_UPCAST(SCSIDiskReq, req, scsi_req_find(&s->qdev, tag)); } -static void scsi_req_set_status(SCSIRequest *req, int status, int sense_code) +static void scsi_disk_clear_sense(SCSIDiskState *s) { - req->status = status; - scsi_dev_set_sense(req->dev, sense_code); + memset(&s->sense, 0, sizeof(s->sense)); +} + +static void scsi_disk_set_sense(SCSIDiskState *s, uint8_t key) +{ + s->sense.key = key; +} + +static void scsi_req_set_status(SCSIDiskReq *r, int status, int sense_code) +{ + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + + r->req.status = status; + scsi_disk_set_sense(s, sense_code); } /* Helper function for command completion. */ @@ -111,7 +128,7 @@ static void scsi_command_complete(SCSIDiskReq *r, int status, int sense) { DPRINTF("Command complete tag=0x%x status=%d sense=%d\n", r->req.tag, status, sense); - scsi_req_set_status(&r->req, status, sense); + scsi_req_set_status(r, status, sense); scsi_req_complete(&r->req); scsi_remove_request(r); } @@ -822,7 +839,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) goto illegal_request; memset(outbuf, 0, 4); buflen = 4; - if (req->dev->sense.key == NOT_READY && req->cmd.xfer >= 18) { + if (s->sense.key == NOT_READY && req->cmd.xfer >= 18) { memset(outbuf, 0, 18); buflen = 18; outbuf[7] = 10; @@ -832,8 +849,8 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) } outbuf[0] = 0xf0; outbuf[1] = 0; - outbuf[2] = req->dev->sense.key; - scsi_dev_clear_sense(req->dev); + outbuf[2] = s->sense.key; + scsi_disk_clear_sense(s); break; case INQUIRY: buflen = scsi_disk_emulate_inquiry(req, outbuf); @@ -966,7 +983,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) default: goto illegal_request; } - scsi_req_set_status(req, GOOD, NO_SENSE); + scsi_req_set_status(r, GOOD, NO_SENSE); return buflen; not_ready: diff --git a/hw/scsi.h b/hw/scsi.h index 9c798ae795..bf02adfbe2 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -26,10 +26,6 @@ enum SCSIXferMode { SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */ }; -typedef struct SCSISense { - uint8_t key; -} SCSISense; - typedef struct SCSIRequest { SCSIBus *bus; SCSIDevice *dev; @@ -57,7 +53,6 @@ struct SCSIDevice QTAILQ_HEAD(, SCSIRequest) requests; int blocksize; int type; - struct SCSISense sense; }; /* cdrom.c */ @@ -102,9 +97,6 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d) SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int unit); int scsi_bus_legacy_handle_cmdline(SCSIBus *bus); -void scsi_dev_clear_sense(SCSIDevice *dev); -void scsi_dev_set_sense(SCSIDevice *dev, uint8_t key); - SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun); SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag); void scsi_req_free(SCSIRequest *req); From 2dd791b6302c73345f92dc9b107635787fcff938 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 24 Nov 2010 12:16:00 +0100 Subject: [PATCH 090/105] scsi-disk: Remove duplicate cdb parsing We parse the CDB twice, which is completely unnecessary. Signed-off-by: Hannes Reinecke Acked-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- hw/scsi-disk.c | 74 ++++++++++++++------------------------------------ 1 file changed, 21 insertions(+), 53 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index d692fb02ef..6e49404d87 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -1004,9 +1004,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, uint8_t *buf, int lun) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); - uint64_t lba; uint32_t len; - int cmdlen; int is_write; uint8_t command; uint8_t *outbuf; @@ -1025,55 +1023,21 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, outbuf = (uint8_t *)r->iov.iov_base; is_write = 0; DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); - switch (command >> 5) { - case 0: - lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) | - (((uint64_t) buf[1] & 0x1f) << 16); - len = buf[4]; - cmdlen = 6; - break; - case 1: - case 2: - lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) | - ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24); - len = buf[8] | (buf[7] << 8); - cmdlen = 10; - break; - case 4: - lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) | - ((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) | - ((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) | - ((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56); - len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24); - cmdlen = 16; - break; - case 5: - lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) | - ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24); - len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24); - cmdlen = 12; - break; - default: + + if (scsi_req_parse(&r->req, buf) != 0) { BADF("Unsupported command length, command %x\n", command); goto fail; } #ifdef DEBUG_SCSI { int i; - for (i = 1; i < cmdlen; i++) { + for (i = 1; i < r->req.cmd.len; i++) { printf(" 0x%02x", buf[i]); } printf("\n"); } #endif - if (scsi_req_parse(&r->req, buf) != 0) { - BADF("Unsupported command length, command %x\n", command); - goto fail; - } - assert(r->req.cmd.len == cmdlen); - assert(r->req.cmd.lba == lba); - if (lun || buf[1] >> 5) { /* Only LUN 0 supported. */ DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); @@ -1111,10 +1075,11 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case READ_10: case READ_12: case READ_16: - DPRINTF("Read (sector %" PRId64 ", count %d)\n", lba, len); - if (lba > s->max_lba) + len = r->req.cmd.xfer / d->blocksize; + DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len); + if (r->req.cmd.lba > s->max_lba) goto illegal_lba; - r->sector = lba * s->cluster_size; + r->sector = r->req.cmd.lba * s->cluster_size; r->sector_count = len * s->cluster_size; break; case WRITE_6: @@ -1124,42 +1089,45 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case WRITE_VERIFY: case WRITE_VERIFY_12: case WRITE_VERIFY_16: + len = r->req.cmd.xfer / d->blocksize; DPRINTF("Write %s(sector %" PRId64 ", count %d)\n", - (command & 0xe) == 0xe ? "And Verify " : "", lba, len); - if (lba > s->max_lba) + (command & 0xe) == 0xe ? "And Verify " : "", + r->req.cmd.lba, len); + if (r->req.cmd.lba > s->max_lba) goto illegal_lba; - r->sector = lba * s->cluster_size; + r->sector = r->req.cmd.lba * s->cluster_size; r->sector_count = len * s->cluster_size; is_write = 1; break; case MODE_SELECT: - DPRINTF("Mode Select(6) (len %d)\n", len); + DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer); /* We don't support mode parameter changes. Allow the mode parameter header + block descriptors only. */ - if (len > 12) { + if (r->req.cmd.xfer > 12) { goto fail; } break; case MODE_SELECT_10: - DPRINTF("Mode Select(10) (len %d)\n", len); + DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer); /* We don't support mode parameter changes. Allow the mode parameter header + block descriptors only. */ - if (len > 16) { + if (r->req.cmd.xfer > 16) { goto fail; } break; case SEEK_6: case SEEK_10: - DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10, lba); - if (lba > s->max_lba) { + DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10, + r->req.cmd.lba); + if (r->req.cmd.lba > s->max_lba) { goto illegal_lba; } break; default: - DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); + DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); fail: scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST); - return 0; + return 0; illegal_lba: scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); return 0; From 11a3cb8159278f7452b5bec8b9e17292a3ef53c3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 26 Nov 2010 14:32:34 +0100 Subject: [PATCH 091/105] raw-posix: raw_pwrite comment fixup Signed-off-by: Christoph Hellwig Signed-off-by: Kevin Wolf --- block/raw-posix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index d0960b85c4..9286fb8b0d 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -463,7 +463,7 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset, count -= ret; sum += ret; } - /* here, count < 512 because (count & ~sector_mask) == 0 */ + /* here, count < sector_size because (count & ~sector_mask) == 0 */ if (count) { ret = raw_pread_aligned(bs, offset, s->aligned_buf, bs->buffer_alignment); From 6e14404aab26f74a448747d1e793ac16bde8a92b Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Fri, 26 Nov 2010 18:46:03 +0000 Subject: [PATCH 092/105] Add missing dependency. Teach Makefile that cmd.o depends on a generated header (specifically config-host.h). Signed-off-by: Paul Brook --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4e120a2d3a..338977548e 100644 --- a/Makefile +++ b/Makefile @@ -150,7 +150,7 @@ version-obj-$(CONFIG_WIN32) += version.o ###################################################################### qemu-img.o: qemu-img-cmds.h -qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o: $(GENERATED_HEADERS) +qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o: $(GENERATED_HEADERS) qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o From bd9141bb2e53195e3c1abf29275365d7f554beb5 Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Fri, 26 Nov 2010 18:47:45 +0000 Subject: [PATCH 093/105] Include directives in default configs Allow default configs to be split into several files. Signed-off-by: Paul Brook --- Makefile | 11 ++++++----- Makefile.objs | 3 ++- make_device_config.sh | 27 +++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 make_device_config.sh diff --git a/Makefile b/Makefile index 338977548e..d3bc0f2c74 100644 --- a/Makefile +++ b/Makefile @@ -39,18 +39,19 @@ endif SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS)) +SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS)) config-all-devices.mak: $(SUBDIR_DEVICES_MAK) $(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@," GEN $@") +-include $(SUBDIR_DEVICES_MAK_DEP) + %/config-devices.mak: default-configs/%.mak - $(call quiet-command,cat $< > $@.tmp, " GEN $@") + $(call quiet-command,$(SHELL) $(SRC_PATH)/make_device_config.sh $@ $<, " GEN $@") @if test -f $@; then \ if cmp -s $@.old $@; then \ - if ! cmp -s $@ $@.tmp; then \ - mv $@.tmp $@; \ - cp -p $@ $@.old; \ - fi; \ + mv $@.tmp $@; \ + cp -p $@ $@.old; \ else \ if test -f $@.old; then \ echo "WARNING: $@ (user modified) out of date.";\ diff --git a/Makefile.objs b/Makefile.objs index 23b17cefad..4f4aba3472 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -160,7 +160,8 @@ user-obj-y += cutils.o cache-utils.o hw-obj-y = hw-obj-y += vl.o loader.o hw-obj-y += virtio.o virtio-console.o -hw-obj-y += fw_cfg.o pci.o pci_host.o pcie_host.o pci_bridge.o +hw-obj-y += fw_cfg.o +hw-obj-$(CONFIG_PCI) += pci.o pci_host.o pcie_host.o pci_bridge.o hw-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.o hw-obj-y += watchdog.o hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o diff --git a/make_device_config.sh b/make_device_config.sh new file mode 100644 index 0000000000..59f267b5ef --- /dev/null +++ b/make_device_config.sh @@ -0,0 +1,27 @@ +#! /bin/sh +# Construct a target device config file from a default, pulling in any +# files from include directives. + +dest=$1.tmp +dep=$1.d +src=$2 +src_dir=`dirname $src` +all_includes= + +process_includes () { + cat $1 | grep '^include' | \ + while read include file ; do + all_includes="$all_includes $src_dir/$file" + process_includes $src_dir/$file + done +} + +f=$src +while [ -n "$f" ] ; do + f=`awk '/^include / {print "'$src_dir'/" $2}' $f` + all_includes="$all_includes $f" +done +process_includes $src > $dest + +cat $src $all_includes | grep -v '^include' > $dest +echo "$1: $all_includes" > $dep From f8f5cfbaa49387a513fddd9c9bf1aeb0ecc64cce Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Fri, 26 Nov 2010 21:39:42 +0000 Subject: [PATCH 094/105] PCI config include Split PCI config options into a separate file Signed-off-by: Paul Brook --- Makefile.objs | 20 +++++++++++--------- Makefile.target | 4 ++-- default-configs/arm-softmmu.mak | 3 +-- default-configs/cris-softmmu.mak | 2 +- default-configs/i386-softmmu.mak | 4 +--- default-configs/m68k-softmmu.mak | 2 +- default-configs/microblaze-softmmu.mak | 1 - default-configs/mips-softmmu.mak | 3 +-- default-configs/mips64-softmmu.mak | 3 +-- default-configs/mips64el-softmmu.mak | 3 +-- default-configs/mipsel-softmmu.mak | 3 +-- default-configs/ppc-softmmu.mak | 3 +-- default-configs/ppc64-softmmu.mak | 3 +-- default-configs/ppcemb-softmmu.mak | 3 +-- default-configs/sh4-softmmu.mak | 3 +-- default-configs/sh4eb-softmmu.mak | 3 +-- default-configs/sparc-softmmu.mak | 2 +- default-configs/sparc64-softmmu.mak | 2 +- default-configs/x86_64-softmmu.mak | 4 +--- 19 files changed, 29 insertions(+), 42 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index 4f4aba3472..9e85b0438b 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -161,8 +161,11 @@ hw-obj-y = hw-obj-y += vl.o loader.o hw-obj-y += virtio.o virtio-console.o hw-obj-y += fw_cfg.o -hw-obj-$(CONFIG_PCI) += pci.o pci_host.o pcie_host.o pci_bridge.o -hw-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.o +# FIXME: Core PCI code and its direct dependencies are required by the +# QMP query-pci command. +hw-obj-y += pci.o pci_bridge.o msix.o msi.o +hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o +hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o hw-obj-y += watchdog.o hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o hw-obj-$(CONFIG_ECC) += ecc.o @@ -207,15 +210,14 @@ hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o hw-obj-$(CONFIG_PIIX4) += piix4.o # PCI watchdog devices -hw-obj-y += wdt_i6300esb.o +hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o -hw-obj-y += pcie.o pcie_port.o -hw-obj-y += msix.o msi.o +hw-obj-$(CONFIG_PCI) += pcie.o pcie_port.o # PCI network cards -hw-obj-y += ne2000.o -hw-obj-y += eepro100.o -hw-obj-y += pcnet.o +hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o +hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o +hw-obj-$(CONFIG_PCNET_PCI) += pcnet.o hw-obj-$(CONFIG_SMC91C111) += smc91c111.o hw-obj-$(CONFIG_LAN9118) += lan9118.o @@ -232,7 +234,7 @@ hw-obj-$(CONFIG_IDE_MACIO) += ide/macio.o hw-obj-$(CONFIG_IDE_VIA) += ide/via.o # SCSI layer -hw-obj-y += lsi53c895a.o +hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o hw-obj-$(CONFIG_ESP) += esp.o hw-obj-y += dma-helpers.o sysbus.o isa-bus.o diff --git a/Makefile.target b/Makefile.target index 2800f473b7..853045a21c 100644 --- a/Makefile.target +++ b/Makefile.target @@ -210,8 +210,8 @@ obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o obj-$(CONFIG_USB_OHCI) += usb-ohci.o # PCI network cards -obj-y += rtl8139.o -obj-y += e1000.o +obj-$(CONFIG_RTL8139_PCI) += rtl8139.o +obj-$(CONFIG_E1000_PCI) += e1000.o # Inter-VM PCI shared memory obj-$(CONFIG_KVM) += ivshmem.o diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index e7a4e84481..ac48dc1565 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -1,7 +1,7 @@ # Default configuration for arm-softmmu +include pci.mak CONFIG_GDBSTUB_XML=y -CONFIG_USB_OHCI=y CONFIG_ISA_MMIO=y CONFIG_NAND=y CONFIG_ECC=y @@ -25,6 +25,5 @@ CONFIG_SSI_SD=y CONFIG_LAN9118=y CONFIG_SMC91C111=y CONFIG_DS1338=y -CONFIG_VIRTIO_PCI=y CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI02=y diff --git a/default-configs/cris-softmmu.mak b/default-configs/cris-softmmu.mak index e0d2cabb2d..5f1fd1e868 100644 --- a/default-configs/cris-softmmu.mak +++ b/default-configs/cris-softmmu.mak @@ -1,6 +1,6 @@ # Default configuration for cris-softmmu +#include pci.mak CONFIG_NAND=y CONFIG_PTIMER=y -CONFIG_VIRTIO_PCI=y CONFIG_PFLASH_CFI02=y diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index ed00471da2..ce905d23d1 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -1,6 +1,6 @@ # Default configuration for i386-softmmu -CONFIG_USB_OHCI=y +include pci.mak CONFIG_VGA_PCI=y CONFIG_VGA_ISA=y CONFIG_VMWARE_VGA=y @@ -9,7 +9,6 @@ CONFIG_PARALLEL=y CONFIG_I8254=y CONFIG_PCSPK=y CONFIG_PCKBD=y -CONFIG_USB_UHCI=y CONFIG_FDC=y CONFIG_ACPI=y CONFIG_APM=y @@ -22,4 +21,3 @@ CONFIG_IDE_PIIX=y CONFIG_NE2000_ISA=y CONFIG_PIIX_PCI=y CONFIG_SOUND=y -CONFIG_VIRTIO_PCI=y diff --git a/default-configs/m68k-softmmu.mak b/default-configs/m68k-softmmu.mak index 69ca3ed08e..3e2ec3716c 100644 --- a/default-configs/m68k-softmmu.mak +++ b/default-configs/m68k-softmmu.mak @@ -1,5 +1,5 @@ # Default configuration for m68k-softmmu +include pci.mak CONFIG_GDBSTUB_XML=y CONFIG_PTIMER=y -CONFIG_VIRTIO_PCI=y diff --git a/default-configs/microblaze-softmmu.mak b/default-configs/microblaze-softmmu.mak index 6c4f4f2f22..4399b8b361 100644 --- a/default-configs/microblaze-softmmu.mak +++ b/default-configs/microblaze-softmmu.mak @@ -1,5 +1,4 @@ # Default configuration for microblaze-softmmu CONFIG_PTIMER=y -CONFIG_VIRTIO_PCI=y CONFIG_PFLASH_CFI01=y diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak index 3d0af83165..565e611c53 100644 --- a/default-configs/mips-softmmu.mak +++ b/default-configs/mips-softmmu.mak @@ -1,5 +1,6 @@ # Default configuration for mips-softmmu +include pci.mak CONFIG_ISA_MMIO=y CONFIG_ESP=y CONFIG_VGA_PCI=y @@ -11,7 +12,6 @@ CONFIG_PARALLEL=y CONFIG_I8254=y CONFIG_PCSPK=y CONFIG_PCKBD=y -CONFIG_USB_UHCI=y CONFIG_FDC=y CONFIG_ACPI=y CONFIG_APM=y @@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y CONFIG_IDE_PIIX=y CONFIG_NE2000_ISA=y CONFIG_SOUND=y -CONFIG_VIRTIO_PCI=y CONFIG_RC4030=y CONFIG_DP8393X=y CONFIG_DS1225Y=y diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak index 0030de45dc..03bd8ebf8d 100644 --- a/default-configs/mips64-softmmu.mak +++ b/default-configs/mips64-softmmu.mak @@ -1,5 +1,6 @@ # Default configuration for mips64-softmmu +include pci.mak CONFIG_ISA_MMIO=y CONFIG_ESP=y CONFIG_VGA_PCI=y @@ -11,7 +12,6 @@ CONFIG_PARALLEL=y CONFIG_I8254=y CONFIG_PCSPK=y CONFIG_PCKBD=y -CONFIG_USB_UHCI=y CONFIG_FDC=y CONFIG_ACPI=y CONFIG_APM=y @@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y CONFIG_IDE_PIIX=y CONFIG_NE2000_ISA=y CONFIG_SOUND=y -CONFIG_VIRTIO_PCI=y CONFIG_RC4030=y CONFIG_DP8393X=y CONFIG_DS1225Y=y diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak index fa2a3ffa45..4661617700 100644 --- a/default-configs/mips64el-softmmu.mak +++ b/default-configs/mips64el-softmmu.mak @@ -1,5 +1,6 @@ # Default configuration for mips64el-softmmu +include pci.mak CONFIG_ISA_MMIO=y CONFIG_ESP=y CONFIG_VGA_PCI=y @@ -11,7 +12,6 @@ CONFIG_PARALLEL=y CONFIG_I8254=y CONFIG_PCSPK=y CONFIG_PCKBD=y -CONFIG_USB_UHCI=y CONFIG_FDC=y CONFIG_ACPI=y CONFIG_APM=y @@ -25,7 +25,6 @@ CONFIG_IDE_PIIX=y CONFIG_IDE_VIA=y CONFIG_NE2000_ISA=y CONFIG_SOUND=y -CONFIG_VIRTIO_PCI=y CONFIG_RC4030=y CONFIG_DP8393X=y CONFIG_DS1225Y=y diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak index 238b73ace1..92fc473318 100644 --- a/default-configs/mipsel-softmmu.mak +++ b/default-configs/mipsel-softmmu.mak @@ -1,5 +1,6 @@ # Default configuration for mipsel-softmmu +include pci.mak CONFIG_ISA_MMIO=y CONFIG_ESP=y CONFIG_VGA_PCI=y @@ -11,7 +12,6 @@ CONFIG_PARALLEL=y CONFIG_I8254=y CONFIG_PCSPK=y CONFIG_PCKBD=y -CONFIG_USB_UHCI=y CONFIG_FDC=y CONFIG_ACPI=y CONFIG_APM=y @@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y CONFIG_IDE_PIIX=y CONFIG_NE2000_ISA=y CONFIG_SOUND=y -CONFIG_VIRTIO_PCI=y CONFIG_RC4030=y CONFIG_DP8393X=y CONFIG_DS1225Y=y diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index 940f4bf375..f1cb99e408 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -1,7 +1,7 @@ # Default configuration for ppc-softmmu +include pci.mak CONFIG_GDBSTUB_XML=y -CONFIG_USB_OHCI=y CONFIG_ISA_MMIO=y CONFIG_ESCC=y CONFIG_M48T59=y @@ -31,7 +31,6 @@ CONFIG_IDE_CMD646=y CONFIG_IDE_MACIO=y CONFIG_NE2000_ISA=y CONFIG_SOUND=y -CONFIG_VIRTIO_PCI=y CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI02=y CONFIG_PTIMER=y diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index e1bc6b8f80..83cbe97f1e 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -1,7 +1,7 @@ # Default configuration for ppc64-softmmu +include pci.mak CONFIG_GDBSTUB_XML=y -CONFIG_USB_OHCI=y CONFIG_ISA_MMIO=y CONFIG_ESCC=y CONFIG_M48T59=y @@ -31,7 +31,6 @@ CONFIG_IDE_CMD646=y CONFIG_IDE_MACIO=y CONFIG_NE2000_ISA=y CONFIG_SOUND=y -CONFIG_VIRTIO_PCI=y CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI02=y CONFIG_PTIMER=y diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak index 8f1cc09add..2b52d4a3f3 100644 --- a/default-configs/ppcemb-softmmu.mak +++ b/default-configs/ppcemb-softmmu.mak @@ -1,7 +1,7 @@ # Default configuration for ppcemb-softmmu +include pci.mak CONFIG_GDBSTUB_XML=y -CONFIG_USB_OHCI=y CONFIG_ISA_MMIO=y CONFIG_ESCC=y CONFIG_M48T59=y @@ -31,7 +31,6 @@ CONFIG_IDE_CMD646=y CONFIG_IDE_MACIO=y CONFIG_NE2000_ISA=y CONFIG_SOUND=y -CONFIG_VIRTIO_PCI=y CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI02=y CONFIG_PTIMER=y diff --git a/default-configs/sh4-softmmu.mak b/default-configs/sh4-softmmu.mak index 866ed7de34..87247a4e53 100644 --- a/default-configs/sh4-softmmu.mak +++ b/default-configs/sh4-softmmu.mak @@ -1,9 +1,8 @@ # Default configuration for sh4-softmmu -CONFIG_USB_OHCI=y +include pci.mak CONFIG_SERIAL=y CONFIG_PTIMER=y -CONFIG_VIRTIO_PCI=y CONFIG_IDE_CORE=y CONFIG_PFLASH_CFI02=y CONFIG_ISA_MMIO=y diff --git a/default-configs/sh4eb-softmmu.mak b/default-configs/sh4eb-softmmu.mak index e3e08b7f1a..5b8a16eea2 100644 --- a/default-configs/sh4eb-softmmu.mak +++ b/default-configs/sh4eb-softmmu.mak @@ -1,9 +1,8 @@ # Default configuration for sh4eb-softmmu -CONFIG_USB_OHCI=y +include pci.mak CONFIG_SERIAL=y CONFIG_PTIMER=y -CONFIG_VIRTIO_PCI=y CONFIG_IDE_CORE=y CONFIG_PFLASH_CFI02=y CONFIG_ISA_MMIO=y diff --git a/default-configs/sparc-softmmu.mak b/default-configs/sparc-softmmu.mak index becf88096c..7c788b8c76 100644 --- a/default-configs/sparc-softmmu.mak +++ b/default-configs/sparc-softmmu.mak @@ -1,10 +1,10 @@ # Default configuration for sparc-softmmu +include pci.mak CONFIG_ECC=y CONFIG_ESP=y CONFIG_ESCC=y CONFIG_M48T59=y CONFIG_PTIMER=y CONFIG_FDC=y -CONFIG_VIRTIO_PCI=y CONFIG_EMPTY_SLOT=y diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak index 1cc3f13079..ecc31228ba 100644 --- a/default-configs/sparc64-softmmu.mak +++ b/default-configs/sparc64-softmmu.mak @@ -1,5 +1,6 @@ # Default configuration for sparc64-softmmu +include pci.mak CONFIG_ISA_MMIO=y CONFIG_M48T59=y CONFIG_PTIMER=y @@ -13,4 +14,3 @@ CONFIG_IDE_QDEV=y CONFIG_IDE_PCI=y CONFIG_IDE_ISA=y CONFIG_IDE_CMD646=y -CONFIG_VIRTIO_PCI=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 518320377f..7f22599fc8 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -1,6 +1,6 @@ # Default configuration for x86_64-softmmu -CONFIG_USB_OHCI=y +include pci.mak CONFIG_VGA_PCI=y CONFIG_VGA_ISA=y CONFIG_VMWARE_VGA=y @@ -9,7 +9,6 @@ CONFIG_PARALLEL=y CONFIG_I8254=y CONFIG_PCSPK=y CONFIG_PCKBD=y -CONFIG_USB_UHCI=y CONFIG_FDC=y CONFIG_ACPI=y CONFIG_APM=y @@ -22,4 +21,3 @@ CONFIG_IDE_PIIX=y CONFIG_NE2000_ISA=y CONFIG_PIIX_PCI=y CONFIG_SOUND=y -CONFIG_VIRTIO_PCI=y From 01af7daf5596e8860c71e72349e1d539b81d9c80 Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Fri, 26 Nov 2010 22:08:48 +0000 Subject: [PATCH 095/105] VirtIO config option Make virtio devices optional. Selecting individual devices is not useful as the host bindings are all in one file. Signed-off-by: Paul Brook --- Makefile.objs | 10 ++++++++-- Makefile.target | 4 ++-- default-configs/s390x-softmmu.mak | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index 9e85b0438b..72c6c7f8f1 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -42,6 +42,11 @@ net-nested-$(CONFIG_SLIRP) += slirp.o net-nested-$(CONFIG_VDE) += vde.o net-obj-y += $(addprefix net/, $(net-nested-y)) +ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS),yy) +# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add. +# only pull in the actual virtio-9p device if we also enabled virtio. +CONFIG_REALLY_VIRTFS=y +endif fsdev-nested-$(CONFIG_VIRTFS) = qemu-fsdev.o fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y)) @@ -159,7 +164,7 @@ user-obj-y += cutils.o cache-utils.o hw-obj-y = hw-obj-y += vl.o loader.o -hw-obj-y += virtio.o virtio-console.o +hw-obj-$(CONFIG_VIRTIO) += virtio.o virtio-console.o hw-obj-y += fw_cfg.o # FIXME: Core PCI code and its direct dependencies are required by the # QMP query-pci command. @@ -264,7 +269,8 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0 hw-obj-$(CONFIG_SOUND) += $(sound-obj-y) -hw-obj-$(CONFIG_VIRTFS) += virtio-9p-debug.o virtio-9p-local.o virtio-9p-xattr.o +hw-obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p-debug.o +hw-obj-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o hw-obj-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o ###################################################################### diff --git a/Makefile.target b/Makefile.target index 853045a21c..578484452b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -188,11 +188,11 @@ ifdef CONFIG_SOFTMMU obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o # virtio has to be here due to weird dependency between PCI and virtio-net. # need to fix this properly -obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o +obj-$(CONFIG_VIRTIO) += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o obj-y += vhost_net.o obj-$(CONFIG_VHOST_NET) += vhost.o -obj-$(CONFIG_VIRTFS) += virtio-9p.o +obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p.o obj-y += rwhandler.o obj-$(CONFIG_KVM) += kvm.o kvm-all.o obj-$(CONFIG_NO_KVM) += kvm-stub.o diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak index e69de29bb2..16d72590ee 100644 --- a/default-configs/s390x-softmmu.mak +++ b/default-configs/s390x-softmmu.mak @@ -0,0 +1 @@ +include virtio.mak From 050e27c8c942151c0685342fe2cbac6a80eb1325 Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Sat, 27 Nov 2010 00:34:15 +0000 Subject: [PATCH 096/105] Fix previous commit Fix breakage from previous commit (missing pci.mak, and incorrect include in default-configs/s390x-softmmu.mak). Signed-off-by: Paul Brook --- default-configs/cris-softmmu.mak | 1 - default-configs/pci.mak | 11 +++++++++++ default-configs/s390x-softmmu.mak | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 default-configs/pci.mak diff --git a/default-configs/cris-softmmu.mak b/default-configs/cris-softmmu.mak index 5f1fd1e868..1a479cd8d3 100644 --- a/default-configs/cris-softmmu.mak +++ b/default-configs/cris-softmmu.mak @@ -1,6 +1,5 @@ # Default configuration for cris-softmmu -#include pci.mak CONFIG_NAND=y CONFIG_PTIMER=y CONFIG_PFLASH_CFI02=y diff --git a/default-configs/pci.mak b/default-configs/pci.mak new file mode 100644 index 0000000000..0ddfb37fd3 --- /dev/null +++ b/default-configs/pci.mak @@ -0,0 +1,11 @@ +CONFIG_PCI=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO=y +CONFIG_USB_UHCI=y +CONFIG_USB_OHCI=y +CONFIG_NE2000_PCI=y +CONFIG_EEPRO100_PCI=y +CONFIG_PCNET_PCI=y +CONFIG_LSI_SCSI_PCI=y +CONFIG_RTL8139_PCI=y +CONFIG_E1000_PCI=y diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak index 16d72590ee..3005729204 100644 --- a/default-configs/s390x-softmmu.mak +++ b/default-configs/s390x-softmmu.mak @@ -1 +1 @@ -include virtio.mak +CONFIG_VIRTIO=y From cf66924f81f022942e14b4e613f1bf0dd2bdf0eb Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Sat, 27 Nov 2010 00:43:04 +0000 Subject: [PATCH 097/105] Detect missing config includes Terminate make_device_config.sh if the awk command fails. Typically this means a missing file. Signed-off-by: Paul Brook --- make_device_config.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/make_device_config.sh b/make_device_config.sh index 59f267b5ef..8abadfef7c 100644 --- a/make_device_config.sh +++ b/make_device_config.sh @@ -18,7 +18,8 @@ process_includes () { f=$src while [ -n "$f" ] ; do - f=`awk '/^include / {print "'$src_dir'/" $2}' $f` + f=`awk '/^include / {ORS=" " ; print "'$src_dir'/" $2}' $f` + [ $? = 0 ] || exit 1 all_includes="$all_includes $f" done process_includes $src > $dest From 129cac5b5af110cfa94eae1a570c33ce795f0104 Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Sat, 27 Nov 2010 10:33:55 +0000 Subject: [PATCH 098/105] Remove PCI from sparc32 target None of the (current) sparc32 machines have a PCI bus, so remove the PCI code from these configs. Signed-off-by: Paul Brook --- default-configs/sparc-softmmu.mak | 1 - 1 file changed, 1 deletion(-) diff --git a/default-configs/sparc-softmmu.mak b/default-configs/sparc-softmmu.mak index 7c788b8c76..436d2a6560 100644 --- a/default-configs/sparc-softmmu.mak +++ b/default-configs/sparc-softmmu.mak @@ -1,6 +1,5 @@ # Default configuration for sparc-softmmu -include pci.mak CONFIG_ECC=y CONFIG_ESP=y CONFIG_ESCC=y From a4c75a21f3749b8dc5a8cc252bc57adb3f43453c Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Sat, 27 Nov 2010 11:23:34 +0000 Subject: [PATCH 099/105] Split out common pcnet code The core pcnet emulation code is used by both the PCI "pcnet" device and the SPARC "lance" device. Split the common code frm the PCI code so that that can be configures independantly. Signed-off-by: Paul Brook --- Makefile.objs | 3 +- default-configs/pci.mak | 1 + default-configs/sparc-softmmu.mak | 1 + hw/pcnet.c | 311 +----------------------------- hw/pcnet.h | 3 + 5 files changed, 11 insertions(+), 308 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index 72c6c7f8f1..13ba26fdcb 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -222,7 +222,8 @@ hw-obj-$(CONFIG_PCI) += pcie.o pcie_port.o # PCI network cards hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o -hw-obj-$(CONFIG_PCNET_PCI) += pcnet.o +hw-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o +hw-obj-$(CONFIG_PCNET_COMMON) += pcnet.o hw-obj-$(CONFIG_SMC91C111) += smc91c111.o hw-obj-$(CONFIG_LAN9118) += lan9118.o diff --git a/default-configs/pci.mak b/default-configs/pci.mak index 0ddfb37fd3..c74a99f5c9 100644 --- a/default-configs/pci.mak +++ b/default-configs/pci.mak @@ -6,6 +6,7 @@ CONFIG_USB_OHCI=y CONFIG_NE2000_PCI=y CONFIG_EEPRO100_PCI=y CONFIG_PCNET_PCI=y +CONFIG_PCNET_COMMON=y CONFIG_LSI_SCSI_PCI=y CONFIG_RTL8139_PCI=y CONFIG_E1000_PCI=y diff --git a/default-configs/sparc-softmmu.mak b/default-configs/sparc-softmmu.mak index 436d2a6560..b0310c51e2 100644 --- a/default-configs/sparc-softmmu.mak +++ b/default-configs/sparc-softmmu.mak @@ -7,3 +7,4 @@ CONFIG_M48T59=y CONFIG_PTIMER=y CONFIG_FDC=y CONFIG_EMPTY_SLOT=y +CONFIG_PCNET_COMMON=y diff --git a/hw/pcnet.c b/hw/pcnet.c index f970bdaf3c..37010b8fcf 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -35,9 +35,8 @@ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt */ -#include "pci.h" +#include "qdev.h" #include "net.h" -#include "loader.h" #include "qemu-timer.h" #include "qemu_socket.h" @@ -52,11 +51,6 @@ //#define PCNET_DEBUG_MATCH -typedef struct { - PCIDevice pci_dev; - PCNetState state; -} PCIPCNetState; - struct qemu_ether_header { uint8_t ether_dhost[6]; uint8_t ether_shost[6]; @@ -704,7 +698,6 @@ static void pcnet_poll_timer(void *opaque); static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap); static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value); static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val); -static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap); static void pcnet_s_reset(PCNetState *s) { @@ -1538,7 +1531,7 @@ static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val) } } -static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap) +uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap) { uint32_t val; rap &= 127; @@ -1595,27 +1588,6 @@ void pcnet_h_reset(void *opaque) pcnet_poll_timer(s); } -static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) -{ - PCNetState *s = opaque; -#ifdef PCNET_DEBUG - printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val); -#endif - /* Check APROMWE bit to enable write access */ - if (pcnet_bcr_readw(s,2) & 0x100) - s->prom[addr & 15] = val; -} - -static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr) -{ - PCNetState *s = opaque; - uint32_t val = s->prom[addr & 15]; -#ifdef PCNET_DEBUG - printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val); -#endif - return val; -} - void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val) { PCNetState *s = opaque; @@ -1668,7 +1640,7 @@ uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr) return val; } -static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val) +void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val) { PCNetState *s = opaque; pcnet_poll_timer(s); @@ -1698,7 +1670,7 @@ static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val) pcnet_update_irq(s); } -static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr) +uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr) { PCNetState *s = opaque; uint32_t val = -1; @@ -1727,125 +1699,6 @@ static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr) return val; } -static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, - pcibus_t addr, pcibus_t size, int type) -{ - PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state; - -#ifdef PCNET_DEBUG_IO - printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n", - addr, size); -#endif - - register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d); - register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d); - - register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d); - register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d); - register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d); - register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d); -} - -static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCNetState *d = opaque; -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr, - val); -#endif - if (!(addr & 0x10)) - pcnet_aprom_writeb(d, addr & 0x0f, val); -} - -static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) -{ - PCNetState *d = opaque; - uint32_t val = -1; - if (!(addr & 0x10)) - val = pcnet_aprom_readb(d, addr & 0x0f); -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr, - val & 0xff); -#endif - return val; -} - -static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCNetState *d = opaque; -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr, - val); -#endif - if (addr & 0x10) - pcnet_ioport_writew(d, addr & 0x0f, val); - else { - addr &= 0x0f; - pcnet_aprom_writeb(d, addr, val & 0xff); - pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); - } -} - -static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) -{ - PCNetState *d = opaque; - uint32_t val = -1; - if (addr & 0x10) - val = pcnet_ioport_readw(d, addr & 0x0f); - else { - addr &= 0x0f; - val = pcnet_aprom_readb(d, addr+1); - val <<= 8; - val |= pcnet_aprom_readb(d, addr); - } -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr, - val & 0xffff); -#endif - return val; -} - -static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCNetState *d = opaque; -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr, - val); -#endif - if (addr & 0x10) - pcnet_ioport_writel(d, addr & 0x0f, val); - else { - addr &= 0x0f; - pcnet_aprom_writeb(d, addr, val & 0xff); - pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); - pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16); - pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24); - } -} - -static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) -{ - PCNetState *d = opaque; - uint32_t val; - if (addr & 0x10) - val = pcnet_ioport_readl(d, addr & 0x0f); - else { - addr &= 0x0f; - val = pcnet_aprom_readb(d, addr+3); - val <<= 8; - val |= pcnet_aprom_readb(d, addr+2); - val <<= 8; - val |= pcnet_aprom_readb(d, addr+1); - val <<= 8; - val |= pcnet_aprom_readb(d, addr); - } -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, - val); -#endif - return val; -} - static bool is_version_2(void *opaque, int version_id) { return version_id == 2; @@ -1875,18 +1728,6 @@ const VMStateDescription vmstate_pcnet = { } }; -static const VMStateDescription vmstate_pci_pcnet = { - .name = "pcnet", - .version_id = 3, - .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField []) { - VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState), - VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState), - VMSTATE_END_OF_LIST() - } -}; - void pcnet_common_cleanup(PCNetState *d) { d->nic = NULL; @@ -1901,147 +1742,3 @@ int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info) qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); return 0; } - -/* PCI interface */ - -static CPUWriteMemoryFunc * const pcnet_mmio_write[] = { - &pcnet_mmio_writeb, - &pcnet_mmio_writew, - &pcnet_mmio_writel -}; - -static CPUReadMemoryFunc * const pcnet_mmio_read[] = { - &pcnet_mmio_readb, - &pcnet_mmio_readw, - &pcnet_mmio_readl -}; - -static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, - pcibus_t addr, pcibus_t size, int type) -{ - PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev); - -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n", - addr, size); -#endif - - cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->state.mmio_index); -} - -static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr, - uint8_t *buf, int len, int do_bswap) -{ - cpu_physical_memory_write(addr, buf, len); -} - -static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, - uint8_t *buf, int len, int do_bswap) -{ - cpu_physical_memory_read(addr, buf, len); -} - -static void pci_pcnet_cleanup(VLANClientState *nc) -{ - PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque; - - pcnet_common_cleanup(d); -} - -static int pci_pcnet_uninit(PCIDevice *dev) -{ - PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev); - - cpu_unregister_io_memory(d->state.mmio_index); - qemu_del_timer(d->state.poll_timer); - qemu_free_timer(d->state.poll_timer); - qemu_del_vlan_client(&d->state.nic->nc); - return 0; -} - -static NetClientInfo net_pci_pcnet_info = { - .type = NET_CLIENT_TYPE_NIC, - .size = sizeof(NICState), - .can_receive = pcnet_can_receive, - .receive = pcnet_receive, - .cleanup = pci_pcnet_cleanup, -}; - -static int pci_pcnet_init(PCIDevice *pci_dev) -{ - PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev); - PCNetState *s = &d->state; - uint8_t *pci_conf; - -#if 0 - printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n", - sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD)); -#endif - - pci_conf = pci_dev->config; - - pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD); - pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE); - pci_set_word(pci_conf + PCI_STATUS, - PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM); - pci_conf[PCI_REVISION_ID] = 0x10; - pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET); - - pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0); - pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0); - - pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0 - pci_conf[PCI_MIN_GNT] = 0x06; - pci_conf[PCI_MAX_LAT] = 0xff; - - /* Handler for memory-mapped I/O */ - s->mmio_index = - cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state); - - pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE, - PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map); - - pci_register_bar(pci_dev, 1, PCNET_PNPMMIO_SIZE, - PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map); - - s->irq = pci_dev->irq[0]; - s->phys_mem_read = pci_physical_memory_read; - s->phys_mem_write = pci_physical_memory_write; - - if (!pci_dev->qdev.hotplugged) { - static int loaded = 0; - if (!loaded) { - rom_add_option("pxe-pcnet.bin"); - loaded = 1; - } - } - - return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info); -} - -static void pci_reset(DeviceState *dev) -{ - PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev); - - pcnet_h_reset(&d->state); -} - -static PCIDeviceInfo pcnet_info = { - .qdev.name = "pcnet", - .qdev.size = sizeof(PCIPCNetState), - .qdev.reset = pci_reset, - .qdev.vmsd = &vmstate_pci_pcnet, - .init = pci_pcnet_init, - .exit = pci_pcnet_uninit, - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf), - DEFINE_PROP_END_OF_LIST(), - } -}; - -static void pcnet_register_devices(void) -{ - pci_qdev_register(&pcnet_info); -} - -device_init(pcnet_register_devices) diff --git a/hw/pcnet.h b/hw/pcnet.h index efacc9fa59..534bdf9c2b 100644 --- a/hw/pcnet.h +++ b/hw/pcnet.h @@ -32,6 +32,9 @@ struct PCNetState_st { void pcnet_h_reset(void *opaque); void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val); uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr); +void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val); +uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr); +uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap); int pcnet_can_receive(VLANClientState *nc); ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_); void pcnet_common_cleanup(PCNetState *d); From 661a1799ba6544a54888283db19dd51469da01e5 Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Sat, 27 Nov 2010 11:56:02 +0000 Subject: [PATCH 100/105] Add pcnet-pci.c Add file missing from last commit. Signed-off-by: Paul Brook --- hw/pcnet-pci.c | 345 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 345 insertions(+) create mode 100644 hw/pcnet-pci.c diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c new file mode 100644 index 0000000000..3dfbe46472 --- /dev/null +++ b/hw/pcnet-pci.c @@ -0,0 +1,345 @@ +/* + * QEMU AMD PC-Net II (Am79C970A) PCI emulation + * + * Copyright (c) 2004 Antony T Curtis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* This software was written to be compatible with the specification: + * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet + * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 + */ + +#include "pci.h" +#include "net.h" +#include "loader.h" +#include "qemu-timer.h" + +#include "pcnet.h" + +//#define PCNET_DEBUG +//#define PCNET_DEBUG_IO +//#define PCNET_DEBUG_BCR +//#define PCNET_DEBUG_CSR +//#define PCNET_DEBUG_RMD +//#define PCNET_DEBUG_TMD +//#define PCNET_DEBUG_MATCH + + +typedef struct { + PCIDevice pci_dev; + PCNetState state; +} PCIPCNetState; + +static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + PCNetState *s = opaque; +#ifdef PCNET_DEBUG + printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val); +#endif + /* Check APROMWE bit to enable write access */ + if (pcnet_bcr_readw(s,2) & 0x100) + s->prom[addr & 15] = val; +} + +static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr) +{ + PCNetState *s = opaque; + uint32_t val = s->prom[addr & 15]; +#ifdef PCNET_DEBUG + printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val); +#endif + return val; +} + +static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, + pcibus_t addr, pcibus_t size, int type) +{ + PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state; + +#ifdef PCNET_DEBUG_IO + printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n", + addr, size); +#endif + + register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d); + register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d); + + register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d); + register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d); + register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d); + register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d); +} + +static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PCNetState *d = opaque; +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr, + val); +#endif + if (!(addr & 0x10)) + pcnet_aprom_writeb(d, addr & 0x0f, val); +} + +static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) +{ + PCNetState *d = opaque; + uint32_t val = -1; + if (!(addr & 0x10)) + val = pcnet_aprom_readb(d, addr & 0x0f); +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr, + val & 0xff); +#endif + return val; +} + +static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PCNetState *d = opaque; +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr, + val); +#endif + if (addr & 0x10) + pcnet_ioport_writew(d, addr & 0x0f, val); + else { + addr &= 0x0f; + pcnet_aprom_writeb(d, addr, val & 0xff); + pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); + } +} + +static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) +{ + PCNetState *d = opaque; + uint32_t val = -1; + if (addr & 0x10) + val = pcnet_ioport_readw(d, addr & 0x0f); + else { + addr &= 0x0f; + val = pcnet_aprom_readb(d, addr+1); + val <<= 8; + val |= pcnet_aprom_readb(d, addr); + } +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr, + val & 0xffff); +#endif + return val; +} + +static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + PCNetState *d = opaque; +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr, + val); +#endif + if (addr & 0x10) + pcnet_ioport_writel(d, addr & 0x0f, val); + else { + addr &= 0x0f; + pcnet_aprom_writeb(d, addr, val & 0xff); + pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); + pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16); + pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24); + } +} + +static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) +{ + PCNetState *d = opaque; + uint32_t val; + if (addr & 0x10) + val = pcnet_ioport_readl(d, addr & 0x0f); + else { + addr &= 0x0f; + val = pcnet_aprom_readb(d, addr+3); + val <<= 8; + val |= pcnet_aprom_readb(d, addr+2); + val <<= 8; + val |= pcnet_aprom_readb(d, addr+1); + val <<= 8; + val |= pcnet_aprom_readb(d, addr); + } +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, + val); +#endif + return val; +} + +static const VMStateDescription vmstate_pci_pcnet = { + .name = "pcnet", + .version_id = 3, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .fields = (VMStateField []) { + VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState), + VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState), + VMSTATE_END_OF_LIST() + } +}; + +/* PCI interface */ + +static CPUWriteMemoryFunc * const pcnet_mmio_write[] = { + &pcnet_mmio_writeb, + &pcnet_mmio_writew, + &pcnet_mmio_writel +}; + +static CPUReadMemoryFunc * const pcnet_mmio_read[] = { + &pcnet_mmio_readb, + &pcnet_mmio_readw, + &pcnet_mmio_readl +}; + +static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, + pcibus_t addr, pcibus_t size, int type) +{ + PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev); + +#ifdef PCNET_DEBUG_IO + printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n", + addr, size); +#endif + + cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->state.mmio_index); +} + +static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int do_bswap) +{ + cpu_physical_memory_write(addr, buf, len); +} + +static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int do_bswap) +{ + cpu_physical_memory_read(addr, buf, len); +} + +static void pci_pcnet_cleanup(VLANClientState *nc) +{ + PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque; + + pcnet_common_cleanup(d); +} + +static int pci_pcnet_uninit(PCIDevice *dev) +{ + PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev); + + cpu_unregister_io_memory(d->state.mmio_index); + qemu_del_timer(d->state.poll_timer); + qemu_free_timer(d->state.poll_timer); + qemu_del_vlan_client(&d->state.nic->nc); + return 0; +} + +static NetClientInfo net_pci_pcnet_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = pcnet_can_receive, + .receive = pcnet_receive, + .cleanup = pci_pcnet_cleanup, +}; + +static int pci_pcnet_init(PCIDevice *pci_dev) +{ + PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev); + PCNetState *s = &d->state; + uint8_t *pci_conf; + +#if 0 + printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n", + sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD)); +#endif + + pci_conf = pci_dev->config; + + pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD); + pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE); + pci_set_word(pci_conf + PCI_STATUS, + PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM); + pci_conf[PCI_REVISION_ID] = 0x10; + pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET); + + pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0); + pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0); + + pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0 + pci_conf[PCI_MIN_GNT] = 0x06; + pci_conf[PCI_MAX_LAT] = 0xff; + + /* Handler for memory-mapped I/O */ + s->mmio_index = + cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state); + + pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE, + PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map); + + pci_register_bar(pci_dev, 1, PCNET_PNPMMIO_SIZE, + PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map); + + s->irq = pci_dev->irq[0]; + s->phys_mem_read = pci_physical_memory_read; + s->phys_mem_write = pci_physical_memory_write; + + if (!pci_dev->qdev.hotplugged) { + static int loaded = 0; + if (!loaded) { + rom_add_option("pxe-pcnet.bin"); + loaded = 1; + } + } + + return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info); +} + +static void pci_reset(DeviceState *dev) +{ + PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev); + + pcnet_h_reset(&d->state); +} + +static PCIDeviceInfo pcnet_info = { + .qdev.name = "pcnet", + .qdev.size = sizeof(PCIPCNetState), + .qdev.reset = pci_reset, + .qdev.vmsd = &vmstate_pci_pcnet, + .init = pci_pcnet_init, + .exit = pci_pcnet_uninit, + .qdev.props = (Property[]) { + DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static void pci_pcnet_register_devices(void) +{ + pci_qdev_register(&pcnet_info); +} + +device_init(pci_pcnet_register_devices) From 8337606d3588f80aea656db74127423bd6b61443 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 26 Nov 2010 16:31:37 +0100 Subject: [PATCH 101/105] ide: Factor ide_dma_set_inactive out Several places that stop a DMA transfer duplicate this code. Factor it out into a common function. Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- hw/ide/core.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index 484e0ca96f..7136adef4f 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -473,6 +473,14 @@ static void dma_buf_commit(IDEState *s, int is_write) qemu_sglist_destroy(&s->sg); } +static void ide_dma_set_inactive(BMDMAState *bm) +{ + bm->status &= ~BM_STATUS_DMAING; + bm->dma_cb = NULL; + bm->unit = -1; + bm->aiocb = NULL; +} + void ide_dma_error(IDEState *s) { ide_transfer_stop(s); @@ -587,11 +595,8 @@ static void ide_read_dma_cb(void *opaque, int ret) s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); eot: - bm->status &= ~BM_STATUS_DMAING; bm->status |= BM_STATUS_INT; - bm->dma_cb = NULL; - bm->unit = -1; - bm->aiocb = NULL; + ide_dma_set_inactive(bm); return; } @@ -733,11 +738,8 @@ static void ide_write_dma_cb(void *opaque, int ret) s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); eot: - bm->status &= ~BM_STATUS_DMAING; bm->status |= BM_STATUS_INT; - bm->dma_cb = NULL; - bm->unit = -1; - bm->aiocb = NULL; + ide_dma_set_inactive(bm); return; } @@ -1061,11 +1063,8 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; ide_set_irq(s->bus); eot: - bm->status &= ~BM_STATUS_DMAING; bm->status |= BM_STATUS_INT; - bm->dma_cb = NULL; - bm->unit = -1; - bm->aiocb = NULL; + ide_dma_set_inactive(bm); return; } @@ -2954,12 +2953,10 @@ void ide_dma_cancel(BMDMAState *bm) printf("aio_cancel\n"); #endif bdrv_aio_cancel(bm->aiocb); - bm->aiocb = NULL; } - bm->status &= ~BM_STATUS_DMAING; + /* cancel DMA request */ - bm->unit = -1; - bm->dma_cb = NULL; + ide_dma_set_inactive(bm); } } From e3982b3cf6d17fbba6839d5252f5f757a8d585dc Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 26 Nov 2010 16:47:42 +0100 Subject: [PATCH 102/105] ide: Set bus master inactive on error BMIDEA in the status register must be cleared on error. This makes FreeBSD respond (more) correctly to I/O errors. Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- hw/ide/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/ide/core.c b/hw/ide/core.c index 7136adef4f..430350f873 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -486,6 +486,8 @@ void ide_dma_error(IDEState *s) ide_transfer_stop(s); s->error = ABRT_ERR; s->status = READY_STAT | ERR_STAT; + ide_dma_set_inactive(s->bus->bmdma); + s->bus->bmdma->status |= BM_STATUS_INT; ide_set_irq(s->bus); } From c29947bbb0978d312074ec73be968bfab1b6c977 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 26 Nov 2010 16:44:53 +0100 Subject: [PATCH 103/105] ide: Ignore double DMA transfer starts/stops You can only start a DMA transfer if it's not running yet, and you can only cancel it if it's running. Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- hw/ide/pci.c | 60 ++++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 3722b774b2..404f045a98 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -39,38 +39,42 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) #ifdef DEBUG_IDE printf("%s: 0x%08x\n", __func__, val); #endif - if (!(val & BM_CMD_START)) { - /* - * We can't cancel Scatter Gather DMA in the middle of the - * operation or a partial (not full) DMA transfer would reach - * the storage so we wait for completion instead (we beahve - * like if the DMA was completed by the time the guest trying - * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not - * set). - * - * In the future we'll be able to safely cancel the I/O if the - * whole DMA operation will be submitted to disk with a single - * aio operation with preadv/pwritev. - */ - if (bm->aiocb) { - qemu_aio_flush(); + + /* Ignore writes to SSBM if it keeps the old value */ + if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) { + if (!(val & BM_CMD_START)) { + /* + * We can't cancel Scatter Gather DMA in the middle of the + * operation or a partial (not full) DMA transfer would reach + * the storage so we wait for completion instead (we beahve + * like if the DMA was completed by the time the guest trying + * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not + * set). + * + * In the future we'll be able to safely cancel the I/O if the + * whole DMA operation will be submitted to disk with a single + * aio operation with preadv/pwritev. + */ + if (bm->aiocb) { + qemu_aio_flush(); #ifdef DEBUG_IDE - if (bm->aiocb) - printf("ide_dma_cancel: aiocb still pending"); - if (bm->status & BM_STATUS_DMAING) - printf("ide_dma_cancel: BM_STATUS_DMAING still pending"); + if (bm->aiocb) + printf("ide_dma_cancel: aiocb still pending"); + if (bm->status & BM_STATUS_DMAING) + printf("ide_dma_cancel: BM_STATUS_DMAING still pending"); #endif + } + } else { + if (!(bm->status & BM_STATUS_DMAING)) { + bm->status |= BM_STATUS_DMAING; + /* start dma transfer if possible */ + if (bm->dma_cb) + bm->dma_cb(bm, 0); + } } - bm->cmd = val & 0x09; - } else { - if (!(bm->status & BM_STATUS_DMAING)) { - bm->status |= BM_STATUS_DMAING; - /* start dma transfer if possible */ - if (bm->dma_cb) - bm->dma_cb(bm, 0); - } - bm->cmd = val & 0x09; } + + bm->cmd = val & 0x09; } static void bmdma_addr_read(IORange *ioport, uint64_t addr, From b76876e602ca09ff848d99595a506feb1fd54ff4 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 26 Nov 2010 16:36:16 +0100 Subject: [PATCH 104/105] ide: Reset current_addr after stopping DMA Whenever SSBM is reset in the command register all state information is lost. Restarting DMA means that current_addr must be reset to the base address of the PRD table. The OS is not required to change the base address register before starting a DMA operation, it can reuse the value it wrote for an earlier request. Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- hw/ide/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 404f045a98..ad406ee24d 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -65,6 +65,7 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) #endif } } else { + bm->cur_addr = bm->addr; if (!(bm->status & BM_STATUS_DMAING)) { bm->status |= BM_STATUS_DMAING; /* start dma transfer if possible */ @@ -101,7 +102,6 @@ static void bmdma_addr_write(IORange *ioport, uint64_t addr, #endif bm->addr &= ~(mask << shift); bm->addr |= ((data & mask) << shift) & ~3; - bm->cur_addr = bm->addr; } const IORangeOps bmdma_addr_ioport_ops = { From fd5d5c566af040be15f2cae1b14a47919974453d Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Thu, 9 Sep 2010 14:51:31 -0500 Subject: [PATCH 105/105] Use a Linux-style MAINTAINERS file I make no claims that this is accurate or exhaustive but I think it's a reasonable place to start. As the file mentions, the purpose of this file is to give contributors information about who they can go to with questions about a particular piece of code or who they can ask for review. If you sign up for a piece of code and indicate that it's Maintained or Supported, please be prepared to be responsive to questions about that subsystem. Signed-off-by: Anthony Liguori --- v1 -> v2 - Sort alphabetically - Copy in instructions from linux MAINTAINERS - Fix entries based on review feedback --- MAINTAINERS | 490 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 415 insertions(+), 75 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index e5165fbae8..59effc7143 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1,88 +1,428 @@ QEMU Maintainers ================ -Project leaders: ----------------- +The intention of this file is not to establish who owns what portions of the +code base, but to provide a set of names that developers can consult when they +have a question about a particular subset and also to provide a set of names +to be CC'd when submitting a patch to obtain appropriate review. -Fabrice Bellard -Paul Brook +In general, if you have a question about inclusion of a patch, you should +consult qemu-devel and not any specific individual privately. -CPU cores: ----------- +Descriptions of section entries: -x86 Fabrice Bellard -ARM Paul Brook -SPARC Blue Swirl -MIPS ? -PowerPC Alexander Graf -M68K Paul Brook -SH4 ? -CRIS Edgar E. Iglesias -Alpha ? -MicroBlaze Edgar E. Iglesias -S390 ? + M: Mail patches to: FullName + L: Mailing list that is relevant to this area + W: Web-page with status/info + Q: Patchwork web based patch tracking system site + T: SCM tree type and location. Type is one of: git, hg, quilt, stgit. + S: Status, one of the following: + Supported: Someone is actually paid to look after this. + Maintained: Someone actually looks after it. + Odd Fixes: It has a maintainer but they don't have time to do + much other than throw the odd patch in. See below.. + Orphan: No current maintainer [but maybe you could take the + role as you write your new code]. + Obsolete: Old code. Something tagged obsolete generally means + it has been replaced by a better system and you + should be using that. + F: Files and directories with wildcard patterns. + A trailing slash includes all files and subdirectory files. + F: drivers/net/ all files in and below drivers/net + F: drivers/net/* all files in drivers/net, but not below + F: */net/* all files in "any top level directory"/net + One pattern per line. Multiple F: lines acceptable. + X: Files and directories that are NOT maintained, same rules as F: + Files exclusions are tested before file matches. + Can be useful for excluding a specific subdirectory, for instance: + F: net/ + X: net/ipv6/ + matches all files in and below net excluding net/ipv6/ + K: Keyword perl extended regex pattern to match content in a + patch or file. For instance: + K: of_get_profile + matches patches or files that contain "of_get_profile" + K: \b(printk|pr_(info|err))\b + matches patches or files that contain one or more of the words + printk, pr_info or pr_err + One regex pattern per line. Multiple K: lines acceptable. -Machines (sorted by CPU): -------------------------- -x86 - pc.c Fabrice Bellard (new maintainer needed) -ARM - integratorcp.c Paul Brook - versatilepb.c Paul Brook - Real View Paul Brook - spitz.c Andrzej Zaborowski - palm.c Andrzej Zaborowski - nseries.c Andrzej Zaborowski - stellaris.c Paul Brook - gumstix.c Thorsten Zitterell - mainstone.c Armin Kuster - musicpal.c Jan Kiszka -SPARC - sun4u.c Blue Swirl - sun4m.c Blue Swirl -MIPS - mips_r4k.c Aurelien Jarno - mips_malta.c Aurelien Jarno - mips_jazz.c Hervé Poussineau - mips_mipssim.c ? -PowerPC - ppc_prep.c ? - ppc_oldworld.c Alexander Graf - ppc_newworld.c Alexander Graf - ppc405_boards.c Alexander Graf -M86K - mcf5208.c Paul Brook - an5206.c Paul Brook - dummy_m68k.c Paul Brook -SH4 - shix.c ? - r2d.c Magnus Damm -CRIS - etraxfs.c Edgar E. Iglesias - axis_dev88.c Edgar E. Iglesias +General Project Administration +------------------------------ +M: Anthony Liguori +M: Paul Brook + +Guest CPU cores (TCG): +---------------------- Alpha +M: qemu-devel@nongnu.org +S: Orphan +F: target-alpha/ + +ARM +M: Paul Brook +S: Maintained +F: target-arm/ + +CRIS +M: Edgar E. Iglesias +S: Maintained +F: target-cris/ + +M68K +M: Paul Brook +S: Maintained +F: target-m68k/ + MicroBlaze - petalogix_s3adsp1800.c Edgar E. Iglesias +M: Edgar E. Iglesias +S: Maintained +F: target-microblaze/ + +MIPS +M: qemu-devel@nongnu.org +S: Orphan +F: target-mips/ + +PowerPC +M: Alexander Graf +S: Maintained +F: target-ppc/ + S390 - s390-*.c Alexander Graf +M: Alexander Graf +S: Maintained +F: target-s390x/ -Generic Subsystems: -------------------- +SH4 +M: qemu-devel@nongnu.org +S: Orphan +F: target-sh4/ -Dynamic translator Fabrice Bellard -Main loop Fabrice Bellard (new maintainer needed) -TCG Fabrice Bellard -IDE device ? -SCSI device Paul Brook -PCI layer Michael S. Tsirkin -USB layer ? -Block layer ? -Graphic layer ? -Audio device layer Vassili Karpov (malc) -Character device layer ? -Network device layer ? -GDB stub ? -Linux user ? -Darwin user ? -SLIRP ? +SPARC +M: Blue Swirl +S: Maintained +F: target-sparc/ + +X86 +M: qemu-devel@nongnu.org +S: Odd Fixes +F: target-i386/ + +Guest CPU Cores (KVM): +---------------------- + +Overall +M: Avi Kivity +M: Marcelo Tosatti +L: kvm@vger.kernel.org +S: Supported +F: kvm-* +F: */kvm.* + +PPC +M: Alexander Graf +S: Maintained +F: target-ppc/kvm.c + +S390 +M: Alexander Graf +S: Maintained +F: target-s390x/kvm.c + +X86 +M: Avi Kivity +M: Marcelo Tosatti +L: kvm@vger.kernel.org +S: Supported +F: target-i386/kvm.c + +ARM Machines +------------ +Gumstix +M: qemu-devel@nongnu.org +S: Orphan +F: hw/gumstix.c + +Integrator CP +M: Paul Brook +S: Maintained +F: hw/integratorcp.c + +Mainstone +M: qemu-devel@nongnu.org +S: Orphan +F: hw/mainstone.c + +Musicpal +M: Jan Kiszka +S: Maintained +F: hw/musicpal.c + +nSeries +M: Andrzej Zaborowski +S: Maintained +F: hw/nseries.c + +Palm +M: Andrzej Zaborowski +S: Maintained +F: hw/palm.c + +Real View +M: Paul Brook +S: Maintained +F: hw/realview* + +Spitz +M: Andrzej Zaborowski +S: Maintained +F: hw/spitz.c + +Stellaris +M: Paul Brook +S: Maintained +F: hw/stellaris.c + +Versatile PB +M: Paul Brook +S: Maintained +F: hw/versatilepb.c + +CRIS Machines +------------- +Axis Dev88 +M: Edgar E. Iglesias +S: Maintained +F: hw/axis_dev88.c + +etraxfs +M: Edgar E. Iglesias +S: Maintained +F: hw/etraxfs.c + +M86K Machines +------------- +an5206 +M: Paul Brook +S: Maintained +F: hw/an5206.c + +dummy_m68k +M: Paul Brook +S: Maintained +F: hw/dummy_m68k.c + +mcf5208 +M: Paul Brook +S: Maintained +F: hw/mcf5208.c + +MicroBlaze Machines +------------------- +petalogix_s3adsp1800 +M: Edgar E. Iglesias +S: Maintained +F: hw/petalogix_s3adsp1800.c + +MIPS Machines +------------- +Jazz +M: Hervé Poussineau +S: Maintained +F: hw/mips_jazz.c + +Malta +M: Aurelien Jarno +S: Maintained +F: hw/mips_malta.c + +Mipssim +M: qemu-devel@nongnu.org +S: Orphan +F: hw/mips_mipssim.c + +R4000 +M: Aurelien Jarno +S: Maintained +F: hw/mips_r4k.c + +PowerPC Machines +---------------- +405 +M: Alexander Graf +S: Maintained +F: hw/ppc405_boards.c + +New World +M: Alexander Graf +S: Maintained +F: hw/ppc_newworld.c + +Old World +M: Alexander Graf +S: Maintained +F: hw/ppc_oldworld.c + +Prep +M: qemu-devel@nongnu.org +S: Orphan +F: hw/ppc_prep.c + +SH4 Machines +------------ +R2D +M: Magnus Damm +S: Maintained +F: hw/r2d.c + +Shix +M: Magnus Damm +S: Oprhan +F: hw/shix.c + +SPARC Machines +-------------- +Sun4m +M: Blue Swirl +S: Maintained +F: hw/sun4m.c + +Sun4u +M: Blue Swirl +S: Maintained +F: hw/sun4u.c + +S390 Machines +------------- +S390 Virtio +M: Alexander Graf +S: Maintained +F: hw/s390-*.c + +X86 Machines +------------ +PC +M: Anthony Liguori +S: Supported +F: hw/pc.[ch] hw/pc_piix.c + +Devices +------- +IDE +M: Kevin Wolf +S: Odd Fixes +F: hw/ide/ + +PCI +M: Michael S. Tsirkin +S: Supported +F: hw/pci* +F: hw/piix* + +SCSI +M: Paul Brook +M: Kevin Wolf +S: Odd Fixes +F: hw/lsi53c895a.c +F: hw/scsi* + +USB +M: qemu-devel@nongnu.org +S: Odd Fixes +F: hw/usb* + +vhost +M: Michael S. Tsirkin +S: Supported +F: hw/vhost* + +virtio +M: Anthony Liguori +S: Supported +F: hw/virtio* + +virtio-9p +M: Venkateswararao Jujjuri (JV) +S: Supported +F: hw/virtio-9p* + +virtio-blk +M: Kevin Wolf +S: Supported +F: hw/virtio-blk* + +virtio-serial +M: Amit Shah +S: Supported +F: hw/virtio-serial* +F: hw/virtio-console* + +Subsystems +---------- +Audio +M: Vassili Karpov (malc) +S: Maintained +F: audio/ + +Block +M: Kevin Wolf +S: Supported +F: block* +F: block/ + +Character Devices +M: Anthony Liguori +S: Maintained +F: qemu-char.c + +GDB stub +M: qemu-devel@nongnu.org +S: Odd Fixes +F: gdbstub* +F: gdb-xml/ + +Graphics +M: Anthony Liguori +S: Maintained +F: ui/ + +Main loop +M: Anthony Liguori +S: Supported +F: vl.c + +Monitor (QMP/HMP) +M: Luiz Capitulino +M: Markus Armbruster +S: Supported +F: monitor.c + +Network device layer +M: Anthony Liguori +M: Mark McLoughlin +S: Maintained +F: net/ + +SLIRP +M: qemu-devel@nongnu.org +S: Orphan +F: slirp/ + +Usermode Emulation +------------------ +BSD user +M: Blue Swirl +S: Maintained +F: bsd-user/ + +Darwin user +M: qemu-devel@nongnu.org +S: Orphan +F: darwin-user/ + +Linux user +M: Riku Voipio +S: Maintained +F: linux-user/