diff options
author | 2010-02-25 23:34:00 -0300 | |
---|---|---|
committer | 2010-02-25 23:34:00 -0300 | |
commit | 69a5ecafa27daeb943dc2ee65b1470844f23f934 (patch) | |
tree | 13a30a888ad68d5fb63746ad921bf1afc75c82d2 | |
parent | Do not allow vcpu stop with in progress PIO (diff) | |
parent | Merge commit '6173d56bdcb53389c54e803873e6bf8f87836a4f' into stable-0.12-merge (diff) | |
download | qemu-kvm-69a5ecafa27daeb943dc2ee65b1470844f23f934.tar.gz qemu-kvm-69a5ecafa27daeb943dc2ee65b1470844f23f934.tar.bz2 qemu-kvm-69a5ecafa27daeb943dc2ee65b1470844f23f934.zip |
Merge branch 'stable-0.12-merge' into stable-0.12
* stable-0.12-merge: (52 commits)
Update version and change for 0.12.3 release
qcow2: Fix access after end of array
ide save/restore pio/atapi cmd transfer fields and io buffer
net: Monitor command set_link finds only VLAN clients, fix
net: info network shows only VLAN clients, fix
net: net_check_clients() checks only VLAN clients, fix
net: Fix bogus "Warning: vlan 0 with no nics" with -device
net: net_check_clients() runs too early to see -device, fix
net: Remove unused net_client_uninit()
don't dereference NULL after failed strdup
virtio-net: fix network stall under load
json: fix PRId64 on Win32
fix inet_parse typo
iothread: fix vcpu stop with smp tcg
segfault due to buffer overrun in usb-serial
qcow2: Fix signedness bugs
Do not ignore error, if open file failed (-serial /dev/tty)
pc-bios: update to newer version of (stable) seabios
kvm: Fix eflags corruption in kvm mode
target-mips: fix ROTR and DROTR by zero
...
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r-- | Changelog | 52 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | block.c | 36 | ||||
-rw-r--r-- | block/curl.c | 2 | ||||
-rw-r--r-- | block/qcow2-cluster.c | 107 | ||||
-rw-r--r-- | block/qcow2-refcount.c | 84 | ||||
-rw-r--r-- | block/qcow2-snapshot.c | 11 | ||||
-rw-r--r-- | block/qcow2.c | 41 | ||||
-rw-r--r-- | block/qcow2.h | 10 | ||||
-rw-r--r-- | block/raw-posix.c | 2 | ||||
-rw-r--r-- | block/vvfat.c | 10 | ||||
-rw-r--r-- | cpu-exec.c | 12 | ||||
-rw-r--r-- | exec.c | 2 | ||||
-rw-r--r-- | hw/cirrus_vga.c | 6 | ||||
-rw-r--r-- | hw/ide/core.c | 78 | ||||
-rw-r--r-- | hw/ide/internal.h | 9 | ||||
-rw-r--r-- | hw/ide/qdev.c | 3 | ||||
-rw-r--r-- | hw/mc146818rtc.c | 2 | ||||
-rw-r--r-- | hw/musicpal.c | 9 | ||||
-rw-r--r-- | hw/pc.c | 16 | ||||
-rw-r--r-- | hw/scsi-disk.c | 7 | ||||
-rw-r--r-- | hw/usb-net.c | 2 | ||||
-rw-r--r-- | hw/usb-serial.c | 32 | ||||
-rw-r--r-- | hw/virtio-blk.c | 93 | ||||
-rw-r--r-- | hw/virtio-net.c | 10 | ||||
-rw-r--r-- | json-lexer.c | 16 | ||||
-rw-r--r-- | json-parser.c | 3 | ||||
-rw-r--r-- | monitor.c | 11 | ||||
-rw-r--r-- | net.c | 64 | ||||
-rw-r--r-- | net.h | 3 | ||||
-rw-r--r-- | net/slirp.c | 4 | ||||
-rw-r--r-- | net/socket.c | 4 | ||||
-rw-r--r-- | net/tap-win32.c | 4 | ||||
-rw-r--r-- | net/tap.c | 4 | ||||
-rw-r--r-- | net/vde.c | 4 | ||||
-rw-r--r-- | pc-bios/bios.bin | bin | 131072 -> 131072 bytes | |||
-rw-r--r-- | qemu-char.c | 3 | ||||
-rw-r--r-- | qemu-common.h | 3 | ||||
-rw-r--r-- | qemu-nbd.c | 2 | ||||
-rw-r--r-- | qemu-options.hx | 25 | ||||
-rw-r--r-- | qemu-sockets.c | 8 | ||||
m--------- | roms/seabios | 0 | ||||
-rw-r--r-- | savevm.c | 2 | ||||
-rw-r--r-- | sdl.c | 1 | ||||
-rw-r--r-- | slirp/misc.c | 2 | ||||
-rw-r--r-- | target-mips/cpu.h | 4 | ||||
-rw-r--r-- | target-mips/helper.c | 8 | ||||
-rw-r--r-- | target-mips/op_helper.c | 18 | ||||
-rw-r--r-- | target-mips/translate.c | 6 | ||||
-rw-r--r-- | tcg/mips/tcg-target.c | 4 | ||||
-rw-r--r-- | usb-linux.c | 2 | ||||
-rw-r--r-- | vl.c | 7 | ||||
-rw-r--r-- | vnc.c | 6 |
53 files changed, 594 insertions, 262 deletions
@@ -1,3 +1,55 @@ +version 0.12.3 + - kvm: Fix eflags corruption in kvm mode (Jan Kiszka) + - qcow2: Fix access after end of array (Kevin Wolf) + - ide save/restore pio/atapi cmd transfer fields and io buffer (Marcelo Tosatti) + - net: Monitor command set_link finds only VLAN clients, fix (Markus Armbruster) + - net: info network shows only VLAN clients, fix (Markus Armbruster) + - net: net_check_clients() checks only VLAN clients, fix (Markus Armbruster) + - net: Fix bogus "Warning: vlan 0 with no nics" with -device (Markus Armbruster) + - net: net_check_clients() runs too early to see -device, fix (Markus Armbruster) + - net: Remove unused net_client_uninit() (Markus Armbruster) + - don't dereference NULL after failed strdup (Jim Meyering) + - virtio-net: fix network stall under load (Tom Lendacky) + - json: fix PRId64 on Win32 (Roy Tam) + - fix inet_parse typo (Marcelo Tosatti) + - iothread: fix vcpu stop with smp tcg (Marcelo Tosatti) + - segfault due to buffer overrun in usb-serial (David S. Ahern) + - qcow2: Fix signedness bugs (Kevin Wolf) + - Do not ignore error, if open file failed (-serial /dev/tty) (Evgeniy Dushistov) + - pc-bios: update to newer version of (stable) seabios (Anthony Liguori) + - target-mips: fix ROTR and DROTR by zero (Aurelien Jarno) + - target-mips: fix CpU exception for coprocessor 0 (Nathan Froyd) + - tcg/mips: fix crash in tcg_out_qemu_ld() (Aurelien Jarno) + - target-mips: don't call cpu_loop_exit() from helper.c (Aurelien Jarno) + - virtio-blk: Fix error cases which ignored rerror/werror (Kevin Wolf) + - virtio-blk: Fix restart after read error (Kevin Wolf) + - virtio_blk: Factor virtio_blk_handle_request out (Kevin Wolf) + - cirrus: Properly re-register cirrus_linear_io_addr on vram unmap (Jan Kiszka) + - qcow2: Don't ignore qcow2_alloc_clusters return value (Kevin Wolf) + - qcow2: Don't ignore update_refcount return value (Kevin Wolf) + - qcow2: Allow updating no refcounts (Kevin Wolf) + - qcow2: Improve error handling in update_refcount (Kevin Wolf) + - qcow2: Fix error handling in grow_refcount_table (Kevin Wolf) + - block: Return original error codes in bdrv_pread/write (Kevin Wolf) + - qcow2: Return 0/-errno in qcow2_alloc_cluster_offset (Kevin Wolf) + - qcow2: Return 0/-errno in get_cluster_table (Kevin Wolf) + - qcow2: Fix error handling in qcow_save_vmstate (Kevin Wolf) + - qcow2: Fix error handling in qcow2_grow_l1_table (Kevin Wolf) + - win32/sdl: Fix toggle full screen (Herve Poussineau) + - win32: pair qemu_memalign() with qemu_vfree() (Herve Poussineau) + - vnc_refresh: calling vnc_update_client might free vs (Stefano Stabellini) + - Musicpal: Fix descriptor walk in eth_send (Jan Kiszka) + - Musicpal: Fix wm8750 I2C address (Jan Kiszka) + - fix savevm command without id or tag (Marcelo Tosatti) + - reduce number of reinjects on ACK (Gleb Natapov) + - QMP: Fix asynchronous events delivery (Luiz Capitulino) + - Documentation: Add missing documentation for qdev related command line options (Stefan Weil) + - pc: add driver version compat properties (Gerd Hoffmann) + - scsi: device version property (Gerd Hoffmann) + - ide: device version property (Gerd Hoffmann) + - QMP: Emit asynchronous events on all QMP monitors (Adam Litke) + - Fix QEMU_WARN_UNUSED_RESULT (Kevin Wolf) + version 0.12.2: - Qemu's internal TFTP server breaks lock-step-iness of TFTP (Milan Plzik) - osdep.c: Fix accept4 fallback (Kevin Wolf) @@ -1 +1 @@ -0.12.2 +0.12.3 @@ -691,6 +691,7 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset, uint8_t tmp_buf[BDRV_SECTOR_SIZE]; int len, nb_sectors, count; int64_t sector_num; + int ret; count = count1; /* first read to align to sector start */ @@ -699,8 +700,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset, len = count; sector_num = offset >> BDRV_SECTOR_BITS; if (len > 0) { - if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0) - return -EIO; + if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0) + return ret; memcpy(buf, tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), len); count -= len; if (count == 0) @@ -712,8 +713,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset, /* read the sectors "in place" */ nb_sectors = count >> BDRV_SECTOR_BITS; if (nb_sectors > 0) { - if (bdrv_read(bs, sector_num, buf, nb_sectors) < 0) - return -EIO; + if ((ret = bdrv_read(bs, sector_num, buf, nb_sectors)) < 0) + return ret; sector_num += nb_sectors; len = nb_sectors << BDRV_SECTOR_BITS; buf += len; @@ -722,8 +723,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset, /* add data from the last sector */ if (count > 0) { - if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0) - return -EIO; + if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0) + return ret; memcpy(buf, tmp_buf, count); } return count1; @@ -735,6 +736,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, uint8_t tmp_buf[BDRV_SECTOR_SIZE]; int len, nb_sectors, count; int64_t sector_num; + int ret; count = count1; /* first write to align to sector start */ @@ -743,11 +745,11 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, len = count; sector_num = offset >> BDRV_SECTOR_BITS; if (len > 0) { - if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0) - return -EIO; + if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0) + return ret; memcpy(tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), buf, len); - if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0) - return -EIO; + if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0) + return ret; count -= len; if (count == 0) return count1; @@ -758,8 +760,8 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, /* write the sectors "in place" */ nb_sectors = count >> BDRV_SECTOR_BITS; if (nb_sectors > 0) { - if (bdrv_write(bs, sector_num, buf, nb_sectors) < 0) - return -EIO; + if ((ret = bdrv_write(bs, sector_num, buf, nb_sectors)) < 0) + return ret; sector_num += nb_sectors; len = nb_sectors << BDRV_SECTOR_BITS; buf += len; @@ -768,11 +770,11 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, /* add data from the last sector */ if (count > 0) { - if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0) - return -EIO; + if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0) + return ret; memcpy(tmp_buf, buf, count); - if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0) - return -EIO; + if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0) + return ret; } return count1; } @@ -1607,7 +1609,7 @@ static void multiwrite_user_cb(MultiwriteCB *mcb) for (i = 0; i < mcb->num_callbacks; i++) { mcb->callbacks[i].cb(mcb->callbacks[i].opaque, mcb->error); qemu_free(mcb->callbacks[i].free_qiov); - qemu_free(mcb->callbacks[i].free_buf); + qemu_vfree(mcb->callbacks[i].free_buf); } } diff --git a/block/curl.c b/block/curl.c index 5223ce879..c9c457486 100644 --- a/block/curl.c +++ b/block/curl.c @@ -309,7 +309,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags) static int inited = 0; - file = strdup(filename); + file = qemu_strdup(filename); s->readahead_size = READ_AHEAD_SIZE; /* Parse a trailing ":readahead=#:" param, if present. */ diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index f88118cdc..b13b6935f 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -33,7 +33,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size) BDRVQcowState *s = bs->opaque; int new_l1_size, new_l1_size2, ret, i; uint64_t *new_l1_table; - uint64_t new_l1_table_offset; + int64_t new_l1_table_offset; uint8_t data[12]; new_l1_size = s->l1_size; @@ -55,6 +55,10 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size) /* write new table (align to cluster) */ new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2); + if (new_l1_table_offset < 0) { + qemu_free(new_l1_table); + return new_l1_table_offset; + } for(i = 0; i < s->l1_size; i++) new_l1_table[i] = cpu_to_be64(new_l1_table[i]); @@ -67,9 +71,10 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size) /* set new table */ cpu_to_be32w((uint32_t*)data, new_l1_size); cpu_to_be64w((uint64_t*)(data + 4), new_l1_table_offset); - if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size), data, - sizeof(data)) != sizeof(data)) + ret = bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size), data,sizeof(data)); + if (ret != sizeof(data)) { goto fail; + } qemu_free(s->l1_table); qcow2_free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t)); s->l1_table_offset = new_l1_table_offset; @@ -77,8 +82,9 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size) s->l1_size = new_l1_size; return 0; fail: - qemu_free(s->l1_table); - return -EIO; + qemu_free(new_l1_table); + qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2); + return ret < 0 ? ret : -EIO; } void qcow2_l2_cache_reset(BlockDriverState *bs) @@ -213,13 +219,17 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index) BDRVQcowState *s = bs->opaque; int min_index; uint64_t old_l2_offset; - uint64_t *l2_table, l2_offset; + uint64_t *l2_table; + int64_t l2_offset; old_l2_offset = s->l1_table[l1_index]; /* allocate a new l2 entry */ l2_offset = qcow2_alloc_clusters(bs, s->l2_size * sizeof(uint64_t)); + if (l2_offset < 0) { + return NULL; + } /* update the L1 entry */ @@ -479,8 +489,8 @@ out: * the l2 table offset in the qcow2 file and the cluster index * in the l2 table are given to the caller. * + * Returns 0 on success, -errno in failure case */ - static int get_cluster_table(BlockDriverState *bs, uint64_t offset, uint64_t **new_l2_table, uint64_t *new_l2_offset, @@ -496,8 +506,9 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset, l1_index = offset >> (s->l2_bits + s->cluster_bits); if (l1_index >= s->l1_size) { ret = qcow2_grow_l1_table(bs, l1_index + 1); - if (ret < 0) - return 0; + if (ret < 0) { + return ret; + } } l2_offset = s->l1_table[l1_index]; @@ -507,14 +518,16 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset, /* load the l2 table in memory */ l2_offset &= ~QCOW_OFLAG_COPIED; l2_table = l2_load(bs, l2_offset); - if (l2_table == NULL) - return 0; + if (l2_table == NULL) { + return -EIO; + } } else { if (l2_offset) qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t)); l2_table = l2_allocate(bs, l1_index); - if (l2_table == NULL) - return 0; + if (l2_table == NULL) { + return -EIO; + } l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED; } @@ -526,7 +539,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset, *new_l2_offset = l2_offset; *new_l2_index = l2_index; - return 1; + return 0; } /* @@ -548,12 +561,14 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, { BDRVQcowState *s = bs->opaque; int l2_index, ret; - uint64_t l2_offset, *l2_table, cluster_offset; + uint64_t l2_offset, *l2_table; + int64_t cluster_offset; int nb_csectors; ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index); - if (ret == 0) + if (ret < 0) { return 0; + } cluster_offset = be64_to_cpu(l2_table[l2_index]); if (cluster_offset & QCOW_OFLAG_COPIED) @@ -563,6 +578,10 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, qcow2_free_any_clusters(bs, cluster_offset, 1); cluster_offset = qcow2_alloc_bytes(bs, compressed_size); + if (cluster_offset < 0) { + return 0; + } + nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - (cluster_offset >> 9); @@ -605,12 +624,12 @@ static int write_l2_entries(BDRVQcowState *s, uint64_t *l2_table, return 0; } -int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset, - QCowL2Meta *m) +int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m) { BDRVQcowState *s = bs->opaque; int i, j = 0, l2_index, ret; uint64_t *old_cluster, start_sect, l2_offset, *l2_table; + uint64_t cluster_offset = m->cluster_offset; if (m->nb_clusters == 0) return 0; @@ -633,10 +652,11 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset, goto err; } - ret = -EIO; /* update L2 table */ - if (!get_cluster_table(bs, m->offset, &l2_table, &l2_offset, &l2_index)) + ret = get_cluster_table(bs, m->offset, &l2_table, &l2_offset, &l2_index); + if (ret < 0) { goto err; + } for (i = 0; i < m->nb_clusters; i++) { /* if two concurrent writes happen to the same unallocated cluster @@ -670,30 +690,36 @@ err: /* * alloc_cluster_offset * - * For a given offset of the disk image, return cluster offset in - * qcow2 file. - * + * For a given offset of the disk image, return cluster offset in qcow2 file. * If the offset is not found, allocate a new cluster. * - * Return the cluster offset if successful, - * Return 0, otherwise. + * If the cluster was already allocated, m->nb_clusters is set to 0, + * m->depends_on is set to NULL and the other fields in m are meaningless. * + * If the cluster is newly allocated, m->nb_clusters is set to the number of + * contiguous clusters that have been allocated. This may be 0 if the request + * conflict with another write request in flight; in this case, m->depends_on + * is set and the remaining fields of m are meaningless. + * + * If m->nb_clusters is non-zero, the other fields of m are valid and contain + * information about the first allocated cluster. + * + * Return 0 on success and -errno in error cases */ - -uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs, - uint64_t offset, - int n_start, int n_end, - int *num, QCowL2Meta *m) +int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, + int n_start, int n_end, int *num, QCowL2Meta *m) { BDRVQcowState *s = bs->opaque; int l2_index, ret; - uint64_t l2_offset, *l2_table, cluster_offset; + uint64_t l2_offset, *l2_table; + int64_t cluster_offset; unsigned int nb_clusters, i = 0; QCowL2Meta *old_alloc; ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index); - if (ret == 0) - return 0; + if (ret < 0) { + return ret; + } nb_clusters = size_to_clusters(s, n_end << 9); @@ -709,6 +735,7 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs, cluster_offset &= ~QCOW_OFLAG_COPIED; m->nb_clusters = 0; + m->depends_on = NULL; goto out; } @@ -723,12 +750,15 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs, while (i < nb_clusters) { i += count_contiguous_clusters(nb_clusters - i, s->cluster_size, &l2_table[l2_index], i, 0); - - if(be64_to_cpu(l2_table[l2_index + i])) + if ((i >= nb_clusters) || be64_to_cpu(l2_table[l2_index + i])) { break; + } i += count_contiguous_free_clusters(nb_clusters - i, &l2_table[l2_index + i]); + if (i >= nb_clusters) { + break; + } cluster_offset = be64_to_cpu(l2_table[l2_index + i]); @@ -736,6 +766,7 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs, (cluster_offset & QCOW_OFLAG_COMPRESSED)) break; } + assert(i <= nb_clusters); nb_clusters = i; /* @@ -779,6 +810,9 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs, /* allocate a new cluster */ cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size); + if (cluster_offset < 0) { + return cluster_offset; + } /* save info needed for meta data update */ m->offset = offset; @@ -787,10 +821,11 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs, out: m->nb_available = MIN(nb_clusters << (s->cluster_bits - 9), n_end); + m->cluster_offset = cluster_offset; *num = m->nb_available - n_start; - return cluster_offset; + return 0; } static int decompress_buffer(uint8_t *out_buf, int out_buf_size, diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 54b19f86d..c2a5c0471 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -168,9 +168,12 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size) cpu_to_be64w((uint64_t*)data, table_offset); cpu_to_be32w((uint32_t*)(data + 8), refcount_table_clusters); - if (bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset), - data, sizeof(data)) != sizeof(data)) + ret = bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset), + data, sizeof(data)); + if (ret != sizeof(data)) { goto fail; + } + qemu_free(s->refcount_table); old_table_offset = s->refcount_table_offset; old_table_size = s->refcount_table_size; @@ -183,7 +186,7 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size) return 0; fail: qemu_free(new_table); - return -EIO; + return ret < 0 ? ret : -EIO; } @@ -266,22 +269,26 @@ static int write_refcount_block_entries(BDRVQcowState *s, } /* XXX: cache several refcount block clusters ? */ -static int update_refcount(BlockDriverState *bs, - int64_t offset, int64_t length, - int addend) +static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, + int64_t offset, int64_t length, int addend) { BDRVQcowState *s = bs->opaque; int64_t start, last, cluster_offset; int64_t refcount_block_offset = 0; int64_t table_index = -1, old_table_index; int first_index = -1, last_index = -1; + int ret; #ifdef DEBUG_ALLOC2 printf("update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n", offset, length, addend); #endif - if (length <= 0) + if (length < 0) { return -EINVAL; + } else if (length == 0) { + return 0; + } + start = offset & ~(s->cluster_size - 1); last = (offset + length - 1) & ~(s->cluster_size - 1); for(cluster_offset = start; cluster_offset <= last; @@ -289,6 +296,7 @@ static int update_refcount(BlockDriverState *bs, { int block_index, refcount; int64_t cluster_index = cluster_offset >> s->cluster_bits; + int64_t new_block; /* Only write refcount block to disk when we are done with it */ old_table_index = table_index; @@ -306,10 +314,12 @@ static int update_refcount(BlockDriverState *bs, } /* Load the refcount block and allocate it if needed */ - refcount_block_offset = alloc_refcount_block(bs, cluster_index); - if (refcount_block_offset < 0) { - return refcount_block_offset; + new_block = alloc_refcount_block(bs, cluster_index); + if (new_block < 0) { + ret = new_block; + goto fail; } + refcount_block_offset = new_block; /* we can update the count and save it */ block_index = cluster_index & @@ -323,24 +333,38 @@ static int update_refcount(BlockDriverState *bs, refcount = be16_to_cpu(s->refcount_block_cache[block_index]); refcount += addend; - if (refcount < 0 || refcount > 0xffff) - return -EINVAL; + if (refcount < 0 || refcount > 0xffff) { + ret = -EINVAL; + goto fail; + } if (refcount == 0 && cluster_index < s->free_cluster_index) { s->free_cluster_index = cluster_index; } s->refcount_block_cache[block_index] = cpu_to_be16(refcount); } + ret = 0; +fail: + /* Write last changed block to disk */ if (refcount_block_offset != 0) { if (write_refcount_block_entries(s, refcount_block_offset, first_index, last_index) < 0) { - return -EIO; + return ret < 0 ? ret : -EIO; } } - return 0; + /* + * Try do undo any updates if an error is returned (This may succeed in + * some cases like ENOSPC for allocating a new refcount block) + */ + if (ret < 0) { + int dummy; + dummy = update_refcount(bs, offset, cluster_offset - offset, -addend); + } + + return ret; } /* addend must be 1 or -1 */ @@ -390,9 +414,13 @@ retry: int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size) { int64_t offset; + int ret; offset = alloc_clusters_noref(bs, size); - update_refcount(bs, offset, size, 1); + ret = update_refcount(bs, offset, size, 1); + if (ret < 0) { + return ret; + } return offset; } @@ -407,6 +435,9 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size) assert(size > 0 && size <= s->cluster_size); if (s->free_byte_offset == 0) { s->free_byte_offset = qcow2_alloc_clusters(bs, s->cluster_size); + if (s->free_byte_offset < 0) { + return s->free_byte_offset; + } } redo: free_in_cluster = s->cluster_size - @@ -422,6 +453,9 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size) update_cluster_refcount(bs, offset >> s->cluster_bits, 1); } else { offset = qcow2_alloc_clusters(bs, s->cluster_size); + if (offset < 0) { + return offset; + } cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1); if ((cluster_offset + s->cluster_size) == offset) { /* we are lucky: contiguous data */ @@ -439,7 +473,13 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size) void qcow2_free_clusters(BlockDriverState *bs, int64_t offset, int64_t size) { - update_refcount(bs, offset, size, -1); + int ret; + + ret = update_refcount(bs, offset, size, -1); + if (ret < 0) { + fprintf(stderr, "qcow2_free_clusters failed: %s\n", strerror(-ret)); + abort(); + } } /* @@ -549,9 +589,15 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, if (offset & QCOW_OFLAG_COMPRESSED) { nb_csectors = ((offset >> s->csize_shift) & s->csize_mask) + 1; - if (addend != 0) - update_refcount(bs, (offset & s->cluster_offset_mask) & ~511, - nb_csectors * 512, addend); + if (addend != 0) { + int ret; + ret = update_refcount(bs, + (offset & s->cluster_offset_mask) & ~511, + nb_csectors * 512, addend); + if (ret < 0) { + goto fail; + } + } /* compressed clusters are never modified */ refcount = 2; } else { diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index d63c7e17d..8ddaea23b 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -139,6 +139,9 @@ static int qcow_write_snapshots(BlockDriverState *bs) snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size); offset = snapshots_offset; + if (offset < 0) { + return offset; + } for(i = 0; i < s->nb_snapshots; i++) { sn = s->snapshots + i; @@ -235,6 +238,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) QCowSnapshot *snapshots1, sn1, *sn = &sn1; int i, ret; uint64_t *l1_table = NULL; + int64_t l1_table_offset; memset(sn, 0, sizeof(*sn)); @@ -263,7 +267,12 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) goto fail; /* create the L1 table of the snapshot */ - sn->l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t)); + l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t)); + if (l1_table_offset < 0) { + goto fail; + } + + sn->l1_table_offset = l1_table_offset; sn->l1_size = s->l1_size; if (s->l1_size != 0) { diff --git a/block/qcow2.c b/block/qcow2.c index 984264b3e..4ae8f193d 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -561,7 +561,7 @@ static void qcow_aio_write_cb(void *opaque, int ret) acb->hd_aiocb = NULL; if (ret >= 0) { - ret = qcow2_alloc_cluster_link_l2(bs, acb->cluster_offset, &acb->l2meta); + ret = qcow2_alloc_cluster_link_l2(bs, &acb->l2meta); } run_dependent_requests(&acb->l2meta); @@ -585,21 +585,23 @@ static void qcow_aio_write_cb(void *opaque, int ret) n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors) n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors; - acb->cluster_offset = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9, - index_in_cluster, - n_end, &acb->n, &acb->l2meta); + ret = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9, + index_in_cluster, n_end, &acb->n, &acb->l2meta); + if (ret < 0) { + goto done; + } + + acb->cluster_offset = acb->l2meta.cluster_offset; /* Need to wait for another request? If so, we are done for now. */ - if (!acb->cluster_offset && acb->l2meta.depends_on != NULL) { + if (acb->l2meta.nb_clusters == 0 && acb->l2meta.depends_on != NULL) { QLIST_INSERT_HEAD(&acb->l2meta.depends_on->dependent_requests, acb, next_depend); return; } - if (!acb->cluster_offset || (acb->cluster_offset & 511) != 0) { - ret = -EIO; - goto done; - } + assert((acb->cluster_offset & 511) == 0); + if (s->crypt_method) { if (!acb->cluster_data) { acb->cluster_data = qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS * @@ -683,27 +685,27 @@ static int get_bits_from_size(size_t size) static int preallocate(BlockDriverState *bs) { BDRVQcowState *s = bs->opaque; - uint64_t cluster_offset = 0; uint64_t nb_sectors; uint64_t offset; int num; + int ret; QCowL2Meta meta; nb_sectors = bdrv_getlength(bs) >> 9; offset = 0; QLIST_INIT(&meta.dependent_requests); + meta.cluster_offset = 0; while (nb_sectors) { num = MIN(nb_sectors, INT_MAX >> 9); - cluster_offset = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num, - &meta); + ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num, &meta); - if (cluster_offset == 0) { + if (ret < 0) { return -1; } - if (qcow2_alloc_cluster_link_l2(bs, cluster_offset, &meta) < 0) { - qcow2_free_any_clusters(bs, cluster_offset, meta.nb_clusters); + if (qcow2_alloc_cluster_link_l2(bs, &meta) < 0) { + qcow2_free_any_clusters(bs, meta.cluster_offset, meta.nb_clusters); return -1; } @@ -722,10 +724,10 @@ static int preallocate(BlockDriverState *bs) * all of the allocated clusters (otherwise we get failing reads after * EOF). Extend the image to the last allocated sector. */ - if (cluster_offset != 0) { + if (meta.cluster_offset != 0) { uint8_t buf[512]; memset(buf, 0, 512); - bdrv_write(s->hd, (cluster_offset >> 9) + num - 1, buf, 1); + bdrv_write(s->hd, (meta.cluster_offset >> 9) + num - 1, buf, 1); } return 0; @@ -1056,12 +1058,13 @@ static int qcow_save_vmstate(BlockDriverState *bs, const uint8_t *buf, { BDRVQcowState *s = bs->opaque; int growable = bs->growable; + int ret; bs->growable = 1; - bdrv_pwrite(bs, qcow_vm_state_offset(s) + pos, buf, size); + ret = bdrv_pwrite(bs, qcow_vm_state_offset(s) + pos, buf, size); bs->growable = growable; - return size; + return ret; } static int qcow_load_vmstate(BlockDriverState *bs, uint8_t *buf, diff --git a/block/qcow2.h b/block/qcow2.h index 26ab5d952..de9397a3d 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -135,6 +135,7 @@ struct QCowAIOCB; typedef struct QCowL2Meta { uint64_t offset; + uint64_t cluster_offset; int n_start; int nb_available; int nb_clusters; @@ -191,16 +192,13 @@ void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num, uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, int *num); -uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs, - uint64_t offset, - int n_start, int n_end, - int *num, QCowL2Meta *m); +int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, + int n_start, int n_end, int *num, QCowL2Meta *m); uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, uint64_t offset, int compressed_size); -int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset, - QCowL2Meta *m); +int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m); /* qcow2-snapshot.c functions */ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info); diff --git a/block/raw-posix.c b/block/raw-posix.c index 6dcc65189..c204cf94e 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -597,7 +597,7 @@ static void raw_close(BlockDriverState *bs) close(s->fd); s->fd = -1; if (s->aligned_buf != NULL) - qemu_free(s->aligned_buf); + qemu_vfree(s->aligned_buf); } } diff --git a/block/vvfat.c b/block/vvfat.c index 063f7318c..c1acb3586 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -882,7 +882,7 @@ static int init_directories(BDRVVVFATState* s, mapping->dir_index = 0; mapping->info.dir.parent_mapping_index = -1; mapping->first_mapping_index = -1; - mapping->path = strdup(dirname); + mapping->path = qemu_strdup(dirname); i = strlen(mapping->path); if (i > 0 && mapping->path[i - 1] == '/') mapping->path[i - 1] = '\0'; @@ -1632,10 +1632,10 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s, /* rename */ if (strcmp(basename, basename2)) - schedule_rename(s, cluster_num, strdup(path)); + schedule_rename(s, cluster_num, qemu_strdup(path)); } else if (is_file(direntry)) /* new file */ - schedule_new_file(s, strdup(path), cluster_num); + schedule_new_file(s, qemu_strdup(path), cluster_num); else { assert(0); return 0; @@ -1752,10 +1752,10 @@ static int check_directory_consistency(BDRVVVFATState *s, mapping->mode &= ~MODE_DELETED; if (strcmp(basename, basename2)) - schedule_rename(s, cluster_num, strdup(path)); + schedule_rename(s, cluster_num, qemu_strdup(path)); } else /* new directory */ - schedule_mkdir(s, cluster_num, strdup(path)); + schedule_mkdir(s, cluster_num, qemu_strdup(path)); lfn_init(&lfn); do { diff --git a/cpu-exec.c b/cpu-exec.c index 0f085eab3..040d4741b 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -236,11 +236,13 @@ int cpu_exec(CPUState *env1) env_to_regs(); #if defined(TARGET_I386) - /* put eflags in CPU temporary format */ - CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - DF = 1 - (2 * ((env->eflags >> 10) & 1)); - CC_OP = CC_OP_EFLAGS; - env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + if (!kvm_enabled()) { + /* put eflags in CPU temporary format */ + CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((env->eflags >> 10) & 1)); + CC_OP = CC_OP_EFLAGS; + env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + } #elif defined(TARGET_SPARC) #elif defined(TARGET_M68K) env->cc_op = CC_OP_FLAGS; @@ -3455,7 +3455,7 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, if (is_write) { cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len); } - qemu_free(bounce.buffer); + qemu_vfree(bounce.buffer); bounce.buffer = NULL; cpu_notify_map_clients(); } diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 25c68b1d9..571044f64 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -2595,9 +2595,11 @@ static void map_linear_vram(CirrusVGAState *s) static void unmap_linear_vram(CirrusVGAState *s) { vga_dirty_log_stop(&s->vga); - if (s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) + if (s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) { s->vga.map_addr = s->vga.map_end = 0; - + cpu_register_physical_memory(s->vga.lfb_addr, s->vga.vram_size, + s->cirrus_linear_io_addr); + } cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000, s->vga.vga_io_memory); diff --git a/hw/ide/core.c b/hw/ide/core.c index 76c382080..64aebc276 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -115,7 +115,7 @@ static void ide_identify(IDEState *s) put_le16(p + 20, 3); /* XXX: retired, remove ? */ put_le16(p + 21, 512); /* cache size in sectors */ put_le16(p + 22, 4); /* ecc bytes */ - padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */ + padstr((char *)(p + 23), s->version, 8); /* firmware version */ padstr((char *)(p + 27), "QEMU HARDDISK", 40); /* model */ #if MAX_MULT_SECTORS > 1 put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS); @@ -186,7 +186,7 @@ static void ide_atapi_identify(IDEState *s) put_le16(p + 20, 3); /* buffer type */ put_le16(p + 21, 512); /* cache size in sectors */ put_le16(p + 22, 4); /* ecc bytes */ - padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */ + padstr((char *)(p + 23), s->version, 8); /* firmware version */ padstr((char *)(p + 27), "QEMU DVD-ROM", 40); /* model */ put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ #ifdef USE_DMA_CDROM @@ -238,7 +238,7 @@ static void ide_cfata_identify(IDEState *s) put_le16(p + 8, s->nb_sectors); /* Sectors per card */ padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */ put_le16(p + 22, 0x0004); /* ECC bytes */ - padstr((char *) (p + 23), QEMU_VERSION, 8); /* Firmware Revision */ + padstr((char *) (p + 23), s->version, 8); /* Firmware Revision */ padstr((char *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */ #if MAX_MULT_SECTORS > 1 put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS); @@ -1591,7 +1591,7 @@ static void ide_atapi_cmd(IDEState *s) buf[7] = 0; /* reserved */ padstr8(buf + 8, 8, "QEMU"); padstr8(buf + 16, 16, "QEMU DVD-ROM"); - padstr8(buf + 32, 4, QEMU_VERSION); + padstr8(buf + 32, 4, s->version); ide_atapi_cmd_reply(s, 36, max_len); break; case GPCMD_GET_CONFIGURATION: @@ -2590,7 +2590,7 @@ void ide_bus_reset(IDEBus *bus) ide_clear_hob(bus); } -void ide_init_drive(IDEState *s, DriveInfo *dinfo) +void ide_init_drive(IDEState *s, DriveInfo *dinfo, const char *version) { int cylinders, heads, secs; uint64_t nb_sectors; @@ -2619,6 +2619,11 @@ void ide_init_drive(IDEState *s, DriveInfo *dinfo) if (strlen(s->drive_serial_str) == 0) snprintf(s->drive_serial_str, sizeof(s->drive_serial_str), "QM%05d", s->drive_serial); + if (version) { + pstrcpy(s->version, sizeof(s->version), version); + } else { + pstrcpy(s->version, sizeof(s->version), QEMU_VERSION); + } ide_reset(s); } @@ -2635,13 +2640,14 @@ void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1, s->unit = i; s->drive_serial = drive_serial++; s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4); + s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4; s->smart_selftest_data = qemu_blockalign(s->bs, 512); s->sector_write_timer = qemu_new_timer(vm_clock, ide_sector_write_timer_cb, s); if (i == 0) - ide_init_drive(s, hd0); + ide_init_drive(s, hd0, NULL); if (i == 1) - ide_init_drive(s, hd1); + ide_init_drive(s, hd1, NULL); } bus->irq = irq; } @@ -2669,6 +2675,25 @@ static bool is_identify_set(void *opaque, int version_id) return s->identify_set != 0; } +static EndTransferFunc* transfer_end_table[] = { + ide_sector_read, + ide_sector_write, + ide_transfer_stop, + ide_atapi_cmd_reply_end, + ide_atapi_cmd, +}; + +static int transfer_end_table_idx(EndTransferFunc *fn) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(transfer_end_table); i++) + if (transfer_end_table[i] == fn) + return i; + + return -1; +} + static int ide_drive_post_load(void *opaque, int version_id) { IDEState *s = opaque; @@ -2679,14 +2704,42 @@ static int ide_drive_post_load(void *opaque, int version_id) s->cdrom_changed = 1; } } + + if (s->cur_io_buffer_len) { + s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx]; + s->data_ptr = s->io_buffer + s->cur_io_buffer_offset; + s->data_end = s->data_ptr + s->cur_io_buffer_len; + } + return 0; } +static void ide_drive_pre_save(void *opaque) +{ + IDEState *s = opaque; + + s->cur_io_buffer_len = 0; + + if (!(s->status & DRQ_STAT)) + return; + + s->cur_io_buffer_offset = s->data_ptr - s->io_buffer; + s->cur_io_buffer_len = s->data_end - s->data_ptr; + + s->end_transfer_fn_idx = transfer_end_table_idx(s->end_transfer_func); + if (s->end_transfer_fn_idx == -1) { + fprintf(stderr, "%s: invalid end_transfer_func for DRQ_STAT\n", + __func__); + s->end_transfer_fn_idx = 2; + } +} + const VMStateDescription vmstate_ide_drive = { .name = "ide_drive", - .version_id = 3, + .version_id = 4, .minimum_version_id = 0, .minimum_version_id_old = 0, + .pre_save = ide_drive_pre_save, .post_load = ide_drive_post_load, .fields = (VMStateField []) { VMSTATE_INT32(mult_sectors, IDEState), @@ -2709,7 +2762,14 @@ const VMStateDescription vmstate_ide_drive = { VMSTATE_UINT8(sense_key, IDEState), VMSTATE_UINT8(asc, IDEState), VMSTATE_UINT8_V(cdrom_changed, IDEState, 3), - /* XXX: if a transfer is pending, we do not save it yet */ + VMSTATE_INT32_V(req_nb_sectors, IDEState, 4), + VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 4, + vmstate_info_uint8, uint8_t), + VMSTATE_INT32_V(cur_io_buffer_offset, IDEState, 4), + VMSTATE_INT32_V(cur_io_buffer_len, IDEState, 4), + VMSTATE_UINT8_V(end_transfer_fn_idx, IDEState, 4), + VMSTATE_INT32_V(elementary_transfer_size, IDEState, 4), + VMSTATE_INT32_V(packet_transfer_size, IDEState, 4), VMSTATE_END_OF_LIST() } }; diff --git a/hw/ide/internal.h b/hw/ide/internal.h index f937daacf..8869a0834 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -397,6 +397,7 @@ struct IDEState { /* set for lba48 access */ uint8_t lba48; BlockDriverState *bs; + char version[9]; /* ATAPI specific */ uint8_t sense_key; uint8_t asc; @@ -416,6 +417,11 @@ struct IDEState { uint8_t *data_ptr; uint8_t *data_end; uint8_t *io_buffer; + /* PIO save/restore */ + int32_t io_buffer_total_len; + int cur_io_buffer_offset; + int cur_io_buffer_len; + uint8_t end_transfer_fn_idx; QEMUTimer *sector_write_timer; /* only used for win2k install hack */ uint32_t irq_count; /* counts IRQs when using win2k install hack */ /* CF-ATA extended error */ @@ -449,6 +455,7 @@ struct IDEDevice { DeviceState qdev; uint32_t unit; DriveInfo *dinfo; + char *version; }; typedef int (*ide_qdev_initfn)(IDEDevice *dev); @@ -548,7 +555,7 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr); void ide_data_writel(void *opaque, uint32_t addr, uint32_t val); uint32_t ide_data_readl(void *opaque, uint32_t addr); -void ide_init_drive(IDEState *s, DriveInfo *dinfo); +void ide_init_drive(IDEState *s, DriveInfo *dinfo, const char *version); void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1, qemu_irq irq); void ide_init_ioport(IDEBus *bus, int iobase, int iobase2); diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 81e79950d..0b84a4f1d 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -99,7 +99,7 @@ typedef struct IDEDrive { static int ide_drive_initfn(IDEDevice *dev) { IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus); - ide_init_drive(bus->ifs + dev->unit, dev->dinfo); + ide_init_drive(bus->ifs + dev->unit, dev->dinfo, dev->version); return 0; } @@ -110,6 +110,7 @@ static IDEDeviceInfo ide_drive_info = { .qdev.props = (Property[]) { DEFINE_PROP_UINT32("unit", IDEDrive, dev.unit, -1), DEFINE_PROP_DRIVE("drive", IDEDrive, dev.dinfo), + DEFINE_PROP_STRING("ver", IDEDrive, dev.version), DEFINE_PROP_END_OF_LIST(), } }; diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index e4d55c7c7..2616d0d7e 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -30,7 +30,7 @@ //#define DEBUG_CMOS -#define RTC_REINJECT_ON_ACK_COUNT 1000 +#define RTC_REINJECT_ON_ACK_COUNT 20 #define RTC_SECONDS 0 #define RTC_SECONDS_ALARM 1 diff --git a/hw/musicpal.c b/hw/musicpal.c index 4a33e28bc..b8af15ed5 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -67,7 +67,7 @@ #define MP_AUDIO_IRQ 30 /* Wolfson 8750 I2C address */ -#define MP_WM_ADDR 0x34 +#define MP_WM_ADDR 0x1A /* Ethernet register offsets */ #define MP_ETH_SMIR 0x010 @@ -238,14 +238,13 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index) { uint32_t desc_addr = s->tx_queue[queue_index]; mv88w8618_tx_desc desc; + uint32_t next_desc; uint8_t buf[2048]; int len; - if (!desc_addr) { - return; - } do { eth_tx_desc_get(desc_addr, &desc); + next_desc = desc.next; if (desc.cmdstat & MP_ETH_TX_OWN) { len = desc.bytes; if (len < 2048) { @@ -256,7 +255,7 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index) s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index); eth_tx_desc_put(desc_addr, &desc); } - desc_addr = desc.next; + desc_addr = next_desc; } while (desc_addr != s->tx_queue[queue_index]); } @@ -1354,6 +1354,14 @@ static QEMUMachine pc_machine_v0_11 = { .property = "vectors", .value = stringify(0), },{ + .driver = "ide-drive", + .property = "ver", + .value = "0.11", + },{ + .driver = "scsi-disk", + .property = "ver", + .value = "0.11", + },{ .driver = "PCI", .property = "rombar", .value = stringify(0), @@ -1385,6 +1393,14 @@ static QEMUMachine pc_machine_v0_10 = { .property = "vectors", .value = stringify(0), },{ + .driver = "ide-drive", + .property = "ver", + .value = "0.10", + },{ + .driver = "scsi-disk", + .property = "ver", + .value = "0.10", + },{ .driver = "PCI", .property = "rombar", .value = stringify(0), diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index eb5b5a847..b34fbaa67 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -65,6 +65,7 @@ struct SCSIDiskState int cluster_size; uint64_t max_lba; QEMUBH *bh; + char *version; }; static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun) @@ -80,7 +81,7 @@ static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun) static void scsi_remove_request(SCSIDiskReq *r) { - qemu_free(r->iov.iov_base); + qemu_vfree(r->iov.iov_base); scsi_req_free(&r->req); } @@ -315,6 +316,7 @@ static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) { BlockDriverState *bdrv = req->dev->dinfo->bdrv; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); int buflen = 0; if (req->cmd.buf[1] & 0x2) { @@ -432,7 +434,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) memcpy(&outbuf[16], "QEMU HARDDISK ", 16); } memcpy(&outbuf[8], "QEMU ", 8); - memcpy(&outbuf[32], QEMU_VERSION, 4); + memcpy(&outbuf[32], s->version ? s->version : QEMU_VERSION, 4); /* Identify device as SCSI-3 rev 1. Some later commands are also implemented. */ outbuf[2] = 3; @@ -1029,6 +1031,7 @@ static SCSIDeviceInfo scsi_disk_info = { .get_buf = scsi_get_buf, .qdev.props = (Property[]) { DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.dinfo), + DEFINE_PROP_STRING("ver", SCSIDiskState, version), DEFINE_PROP_END_OF_LIST(), }, }; diff --git a/hw/usb-net.c b/hw/usb-net.c index 9744dfa5d..cfd2f62e0 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1492,7 +1492,7 @@ static USBDevice *usb_net_init(const char *cmdline) dev = usb_create(NULL /* FIXME */, "usb-net"); qdev_set_nic_properties(&dev->qdev, &nd_table[idx]); - qdev_init(&dev->qdev); + qdev_init_nofail(&dev->qdev); return dev; } diff --git a/hw/usb-serial.c b/hw/usb-serial.c index 2775cf0f0..c3f340137 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -497,12 +497,28 @@ static int usb_serial_can_read(void *opaque) static void usb_serial_read(void *opaque, const uint8_t *buf, int size) { USBSerialState *s = opaque; - int first_size = RECV_BUF - s->recv_ptr; - if (first_size > size) - first_size = size; - memcpy(s->recv_buf + s->recv_ptr + s->recv_used, buf, first_size); - if (size > first_size) - memcpy(s->recv_buf, buf + first_size, size - first_size); + int first_size, start; + + /* room in the buffer? */ + if (size > (RECV_BUF - s->recv_used)) + size = RECV_BUF - s->recv_used; + + start = s->recv_ptr + s->recv_used; + if (start < RECV_BUF) { + /* copy data to end of buffer */ + first_size = RECV_BUF - start; + if (first_size > size) + first_size = size; + + memcpy(s->recv_buf + start, buf, first_size); + + /* wrap around to front if needed */ + if (size > first_size) + memcpy(s->recv_buf, buf + first_size, size - first_size); + } else { + start -= RECV_BUF; + memcpy(s->recv_buf + start, buf, size); + } s->recv_used += size; } @@ -583,7 +599,7 @@ static USBDevice *usb_serial_init(const char *filename) qdev_prop_set_uint16(&dev->qdev, "vendorid", vendorid); if (productid) qdev_prop_set_uint16(&dev->qdev, "productid", productid); - qdev_init(&dev->qdev); + qdev_init_nofail(&dev->qdev); return dev; } @@ -599,7 +615,7 @@ static USBDevice *usb_braille_init(const char *unused) dev = usb_create(NULL /* FIXME */, "usb-braille"); qdev_prop_set_chr(&dev->qdev, "chardev", cdrv); - qdev_init(&dev->qdev); + qdev_init_nofail(&dev->qdev); return dev; } diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index a2f063974..2fd9b3fba 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -272,7 +272,7 @@ static void do_multiwrite(BlockDriverState *bs, BlockRequest *blkreq, if (ret != 0) { for (i = 0; i < num_writes; i++) { if (blkreq[i].error) { - virtio_blk_req_complete(blkreq[i].opaque, VIRTIO_BLK_S_IOERR); + virtio_blk_rw_complete(blkreq[i].opaque, -EIO); } } } @@ -316,7 +316,46 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req) acb = bdrv_aio_readv(req->dev->bs, req->out->sector, &req->qiov, req->qiov.size / 512, virtio_blk_rw_complete, req); if (!acb) { - virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR); + virtio_blk_rw_complete(req, -EIO); + } +} + +typedef struct MultiReqBuffer { + BlockRequest blkreq[32]; + int num_writes; + BlockDriverState *old_bs; +} MultiReqBuffer; + +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"); + 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"); + exit(1); + } + + req->out = (void *)req->elem.out_sg[0].iov_base; + req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base; + + if (req->out->type & VIRTIO_BLK_T_FLUSH) { + virtio_blk_handle_flush(req); + } else if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) { + virtio_blk_handle_scsi(req); + } else if (req->out->type & VIRTIO_BLK_T_OUT) { + qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1], + req->elem.out_num - 1); + virtio_blk_handle_write(mrb->blkreq, &mrb->num_writes, + req, &mrb->old_bs); + } else { + qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0], + req->elem.in_num - 1); + virtio_blk_handle_read(req); } } @@ -324,42 +363,17 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) { VirtIOBlock *s = to_virtio_blk(vdev); VirtIOBlockReq *req; - BlockRequest blkreq[32]; - int num_writes = 0; - BlockDriverState *old_bs = NULL; + MultiReqBuffer mrb = { + .num_writes = 0, + .old_bs = NULL, + }; while ((req = virtio_blk_get_request(s))) { - if (req->elem.out_num < 1 || req->elem.in_num < 1) { - fprintf(stderr, "virtio-blk missing headers\n"); - 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"); - exit(1); - } - - req->out = (void *)req->elem.out_sg[0].iov_base; - req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base; - - if (req->out->type & VIRTIO_BLK_T_FLUSH) { - virtio_blk_handle_flush(req); - } else if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) { - virtio_blk_handle_scsi(req); - } else if (req->out->type & VIRTIO_BLK_T_OUT) { - qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1], - req->elem.out_num - 1); - virtio_blk_handle_write(blkreq, &num_writes, req, &old_bs); - } else { - qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0], - req->elem.in_num - 1); - virtio_blk_handle_read(req); - } + virtio_blk_handle_request(req, &mrb); } - if (num_writes > 0) { - do_multiwrite(old_bs, blkreq, num_writes); + if (mrb.num_writes > 0) { + do_multiwrite(mrb.old_bs, mrb.blkreq, mrb.num_writes); } /* @@ -373,6 +387,10 @@ static void virtio_blk_dma_restart_bh(void *opaque) { VirtIOBlock *s = opaque; VirtIOBlockReq *req = s->rq; + MultiReqBuffer mrb = { + .num_writes = 0, + .old_bs = NULL, + }; qemu_bh_delete(s->bh); s->bh = NULL; @@ -380,10 +398,13 @@ static void virtio_blk_dma_restart_bh(void *opaque) s->rq = NULL; while (req) { - bdrv_aio_writev(req->dev->bs, req->out->sector, &req->qiov, - req->qiov.size / 512, virtio_blk_rw_complete, req); + virtio_blk_handle_request(req, &mrb); req = req->next; } + + if (mrb.num_writes > 0) { + do_multiwrite(mrb.old_bs, mrb.blkreq, mrb.num_writes); + } } static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 2f201ffc7..d8a1629dc 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -384,7 +384,15 @@ static int virtio_net_has_buffers(VirtIONet *n, int bufsize) (n->mergeable_rx_bufs && !virtqueue_avail_bytes(n->rx_vq, bufsize, 0))) { virtio_queue_set_notification(n->rx_vq, 1); - return 0; + + /* To avoid a race condition where the guest has made some buffers + * available after the above check but before notification was + * enabled, check for available buffers again. + */ + if (virtio_queue_empty(n->rx_vq) || + (n->mergeable_rx_bufs && + !virtqueue_avail_bytes(n->rx_vq, bufsize, 0))) + return 0; } virtio_queue_set_notification(n->rx_vq, 0); diff --git a/json-lexer.c b/json-lexer.c index 53697c5ff..9d649205a 100644 --- a/json-lexer.c +++ b/json-lexer.c @@ -54,6 +54,9 @@ enum json_lexer_state { IN_ESCAPE, IN_ESCAPE_L, IN_ESCAPE_LL, + IN_ESCAPE_I, + IN_ESCAPE_I6, + IN_ESCAPE_I64, IN_ESCAPE_DONE, IN_WHITESPACE, IN_OPERATOR_DONE, @@ -223,6 +226,18 @@ static const uint8_t json_lexer[][256] = { ['l'] = IN_ESCAPE_LL, }, + [IN_ESCAPE_I64] = { + ['d'] = IN_ESCAPE_DONE, + }, + + [IN_ESCAPE_I6] = { + ['4'] = IN_ESCAPE_I64, + }, + + [IN_ESCAPE_I] = { + ['6'] = IN_ESCAPE_I6, + }, + [IN_ESCAPE] = { ['d'] = IN_ESCAPE_DONE, ['i'] = IN_ESCAPE_DONE, @@ -230,6 +245,7 @@ static const uint8_t json_lexer[][256] = { ['s'] = IN_ESCAPE_DONE, ['f'] = IN_ESCAPE_DONE, ['l'] = IN_ESCAPE_L, + ['I'] = IN_ESCAPE_I, }, /* top level rule */ diff --git a/json-parser.c b/json-parser.c index 7624c0f9b..2ab6f6c11 100644 --- a/json-parser.c +++ b/json-parser.c @@ -476,7 +476,8 @@ static QObject *parse_escape(JSONParserContext *ctxt, QList **tokens, va_list *a obj = QOBJECT(qint_from_int(va_arg(*ap, int))); } else if (token_is_escape(token, "%ld")) { obj = QOBJECT(qint_from_int(va_arg(*ap, long))); - } else if (token_is_escape(token, "%lld")) { + } else if (token_is_escape(token, "%lld") || + token_is_escape(token, "%I64d")) { obj = QOBJECT(qint_from_int(va_arg(*ap, long long))); } else if (token_is_escape(token, "%s")) { obj = QOBJECT(qstring_from_str(va_arg(*ap, const char *))); @@ -337,13 +337,10 @@ void monitor_protocol_event(MonitorEvent event, QObject *data) { QDict *qmp; const char *event_name; - Monitor *mon = cur_mon; + Monitor *mon; assert(event < QEVENT_MAX); - if (!monitor_ctrl_mode(mon)) - return; - switch (event) { case QEVENT_DEBUG: event_name = "DEBUG"; @@ -373,7 +370,11 @@ void monitor_protocol_event(MonitorEvent event, QObject *data) qdict_put_obj(qmp, "data", data); } - monitor_json_emitter(mon, QOBJECT(qmp)); + QLIST_FOREACH(mon, &mon_list, entry) { + if (monitor_ctrl_mode(mon)) { + monitor_json_emitter(mon, QOBJECT(qmp)); + } + } QDECREF(qmp); } @@ -96,7 +96,7 @@ int parse_host_src_port(struct sockaddr_in *haddr, struct sockaddr_in *saddr, const char *input_str) { - char *str = strdup(input_str); + char *str = qemu_strdup(input_str); char *host_str = str; char *src_str; const char *src_str2; @@ -812,9 +812,6 @@ static int net_init_nic(QemuOpts *opts, } nd->used = 1; - if (vlan) { - nd->vlan->nb_guest_devs++; - } nb_nics++; return idx; @@ -1128,20 +1125,6 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev) return -1; } -void net_client_uninit(NICInfo *nd) -{ - if (nd->vlan) { - nd->vlan->nb_guest_devs--; - } - nb_nics--; - - qemu_free(nd->model); - qemu_free(nd->name); - qemu_free(nd->devaddr); - - nd->used = 0; -} - static int net_host_check_device(const char *device) { int i; @@ -1227,16 +1210,23 @@ void net_set_boot_mask(int net_boot_mask) void do_info_network(Monitor *mon) { VLANState *vlan; + VLANClientState *vc; QTAILQ_FOREACH(vlan, &vlans, next) { - VLANClientState *vc; - monitor_printf(mon, "VLAN %d devices:\n", vlan->id); QTAILQ_FOREACH(vc, &vlan->clients, next) { monitor_printf(mon, " %s: %s\n", vc->name, vc->info_str); } } + monitor_printf(mon, "Devices not on any VLAN:\n"); + QTAILQ_FOREACH(vc, &non_vlan_clients, next) { + monitor_printf(mon, " %s: %s", vc->name, vc->info_str); + if (vc->peer) { + monitor_printf(mon, " peer=%s", vc->peer->name); + } + monitor_printf(mon, "\n"); + } } void do_set_link(Monitor *mon, const QDict *qdict) @@ -1253,6 +1243,7 @@ void do_set_link(Monitor *mon, const QDict *qdict) } } } + vc = qemu_find_netdev(name); done: if (!vc) { @@ -1289,20 +1280,41 @@ void net_cleanup(void) } } -static void net_check_clients(void) +void net_check_clients(void) { VLANState *vlan; + VLANClientState *vc; + int has_nic, has_host_dev; QTAILQ_FOREACH(vlan, &vlans, next) { - if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0) - continue; - if (vlan->nb_guest_devs == 0) + QTAILQ_FOREACH(vc, &vlan->clients, next) { + switch (vc->info->type) { + case NET_CLIENT_TYPE_NIC: + has_nic = 1; + break; + case NET_CLIENT_TYPE_SLIRP: + case NET_CLIENT_TYPE_TAP: + case NET_CLIENT_TYPE_SOCKET: + case NET_CLIENT_TYPE_VDE: + has_host_dev = 1; + break; + default: ; + } + } + if (has_host_dev && !has_nic) fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id); - if (vlan->nb_host_devs == 0) + if (has_nic && !has_host_dev) fprintf(stderr, "Warning: vlan %d is not connected to host network\n", vlan->id); } + QTAILQ_FOREACH(vc, &non_vlan_clients, next) { + if (!vc->peer) { + fprintf(stderr, "Warning: %s %s has no peer\n", + vc->info->type == NET_CLIENT_TYPE_NIC ? "nic" : "netdev", + vc->name); + } + } } static int net_init_client(QemuOpts *opts, void *dummy) @@ -1337,8 +1349,6 @@ int net_init_clients(void) return -1; } - net_check_clients(); - return 0; } @@ -76,7 +76,6 @@ struct VLANState { int id; QTAILQ_HEAD(, VLANClientState) clients; QTAILQ_ENTRY(VLANState) next; - unsigned int nb_guest_devs, nb_host_devs; NetQueue *send_queue; }; @@ -160,9 +159,9 @@ extern const char *legacy_tftp_prefix; extern const char *legacy_bootp_filename; int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev); -void net_client_uninit(NICInfo *nd); int net_client_parse(QemuOptsList *opts_list, const char *str); int net_init_clients(void); +void net_check_clients(void); void net_cleanup(void); void net_set_boot_mask(int boot_mask); void net_host_device_add(Monitor *mon, const QDict *qdict); diff --git a/net/slirp.c b/net/slirp.c index 3f91c4bb3..50ac0b9bb 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -728,10 +728,6 @@ int net_init_slirp(QemuOpts *opts, qemu_free(config); } - if (ret != -1 && vlan) { - vlan->nb_host_devs++; - } - qemu_free(vnet); return ret; diff --git a/net/socket.c b/net/socket.c index 5533737e4..442a9c790 100644 --- a/net/socket.c +++ b/net/socket.c @@ -569,9 +569,5 @@ int net_init_socket(QemuOpts *opts, return -1; } - if (vlan) { - vlan->nb_host_devs++; - } - return 0; } diff --git a/net/tap-win32.c b/net/tap-win32.c index b717c1724..8370c803b 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -714,10 +714,6 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan return -1; } - if (vlan) { - vlan->nb_host_devs++; - } - return 0; } @@ -441,9 +441,5 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan } } - if (vlan) { - vlan->nb_host_devs++; - } - return 0; } @@ -127,9 +127,5 @@ int net_init_vde(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan return -1; } - if (vlan) { - vlan->nb_host_devs++; - } - return 0; } diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin Binary files differindex 1741eeced..855f46834 100644 --- a/pc-bios/bios.bin +++ b/pc-bios/bios.bin diff --git a/qemu-char.c b/qemu-char.c index b13f8d4cf..5a1b535bd 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1180,6 +1180,9 @@ static CharDriverState *qemu_chr_open_tty(QemuOpts *opts) int fd; TFR(fd = open(filename, O_RDWR | O_NONBLOCK)); + if (fd < 0) { + return NULL; + } tty_serial_init(fd, 115200, 'N', 8, 1); chr = qemu_chr_open_fd(fd, fd); if (!chr) { diff --git a/qemu-common.h b/qemu-common.h index 5fbe0f9db..1c5c0b222 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -2,6 +2,8 @@ #ifndef QEMU_COMMON_H #define QEMU_COMMON_H +#include "config-host.h" + #define QEMU_NORETURN __attribute__ ((__noreturn__)) #ifdef CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT #define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) @@ -29,7 +31,6 @@ #include <fcntl.h> #include <sys/stat.h> #include <assert.h> -#include "config-host.h" #ifndef O_LARGEFILE #define O_LARGEFILE 0 diff --git a/qemu-nbd.c b/qemu-nbd.c index 6cdb83473..4ea8c9e45 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -467,7 +467,7 @@ int main(int argc, char **argv) } } } while (persistent || nb_fds > 1); - qemu_free(data); + qemu_vfree(data); close(sharing_fds[0]); bdrv_close(bs); diff --git a/qemu-options.hx b/qemu-options.hx index ca73ba5db..e2fbebd9b 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -405,6 +405,12 @@ ETEXI DEF("device", HAS_ARG, QEMU_OPTION_device, "-device driver[,options] add device\n") +STEXI +@item -device @var{driver}[,@var{option}[,...]] +Add device @var{driver}. Depending on the device type, +@var{option} (typically @var{key}=@var{value}) may be useful. +ETEXI + DEF("name", HAS_ARG, QEMU_OPTION_name, "-name string1[,process=string2] set the name of the guest\n" " string1 sets the window title and string2 the process name (on Linux)\n") @@ -1894,6 +1900,8 @@ ETEXI DEF("nodefaults", 0, QEMU_OPTION_nodefaults, \ "-nodefaults don't create default devices.\n") STEXI +@item -nodefaults +Don't create default devices. ETEXI #ifndef _WIN32 @@ -1916,10 +1924,6 @@ Immediately before starting guest execution, drop root privileges, switching to the specified user. ETEXI -STEXI -@end table -ETEXI - #if defined(TARGET_SPARC) || defined(TARGET_PPC) DEF("prom-env", HAS_ARG, QEMU_OPTION_prom_env, "-prom-env variable=value\n" @@ -1935,9 +1939,17 @@ DEF("old-param", 0, QEMU_OPTION_old_param, #endif DEF("readconfig", HAS_ARG, QEMU_OPTION_readconfig, "-readconfig <file>\n") +STEXI +@item -readconfig @var{file} +Read device configuration from @var{file}. +ETEXI DEF("writeconfig", HAS_ARG, QEMU_OPTION_writeconfig, "-writeconfig <file>\n" " read/write config file\n") +STEXI +@item -writeconfig @var{file} +Write device configuration to @var{file}. +ETEXI DEF("no-kvm", 0, QEMU_OPTION_no_kvm, "-no-kvm disable KVM hardware virtualization\n") @@ -1969,3 +1981,8 @@ DEF("mem-path", HAS_ARG, QEMU_OPTION_mempath, DEF("mem-prealloc", 0, QEMU_OPTION_mem_prealloc, "-mem-prealloc preallocate guest memory (use with -mempath)\n") #endif + +HXCOMM This is the last statement. Insert new options before this line! +STEXI +@end table +ETEXI diff --git a/qemu-sockets.c b/qemu-sockets.c index 8850516f2..a88b2a77f 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -424,7 +424,7 @@ static int inet_parse(QemuOpts *opts, const char *str) __FUNCTION__, str); return -1; } - qemu_opt_set(opts, "ipv6", "yes"); + qemu_opt_set(opts, "ipv6", "on"); } else if (qemu_isdigit(str[0])) { /* IPv4 addr */ if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { @@ -432,7 +432,7 @@ static int inet_parse(QemuOpts *opts, const char *str) __FUNCTION__, str); return -1; } - qemu_opt_set(opts, "ipv4", "yes"); + qemu_opt_set(opts, "ipv4", "on"); } else { /* hostname */ if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { @@ -450,9 +450,9 @@ static int inet_parse(QemuOpts *opts, const char *str) if (h) qemu_opt_set(opts, "to", h+4); if (strstr(optstr, ",ipv4")) - qemu_opt_set(opts, "ipv4", "yes"); + qemu_opt_set(opts, "ipv4", "on"); if (strstr(optstr, ",ipv6")) - qemu_opt_set(opts, "ipv6", "yes"); + qemu_opt_set(opts, "ipv6", "on"); return 0; } diff --git a/roms/seabios b/roms/seabios -Subproject 5da68339ecf44677b8f4f115cdf3cb1da46a9f6 +Subproject 9fb3f4d950744e97cc655b7d7b523d8bf101e4a @@ -1719,7 +1719,7 @@ void do_savevm(Monitor *mon, const QDict *qdict) sn->vm_clock_nsec = qemu_get_clock(vm_clock); /* Delete old snapshots of the same name */ - if (del_existing_snapshots(mon, name) < 0) { + if (name && del_existing_snapshots(mon, name) < 0) { goto the_end; } @@ -525,6 +525,7 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state static void toggle_full_screen(DisplayState *ds) { gui_fullscreen = !gui_fullscreen; + do_sdl_resize(real_screen->w, real_screen->h, real_screen->format->BitsPerPixel); if (gui_fullscreen) { scaling_active = 0; gui_saved_grab = gui_grab; diff --git a/slirp/misc.c b/slirp/misc.c index c76ad8fef..b68af6d7a 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -179,7 +179,7 @@ fork_exec(struct socket *so, const char *ex, int do_pty) close(s); i = 0; - bptr = strdup(ex); /* No need to free() this */ + bptr = qemu_strdup(ex); /* No need to free() this */ if (do_pty == 1) { /* Setup "slirp.telnetd -x" */ argv[i++] = "slirp.telnetd"; diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 97e106f47..89c28f1bf 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -590,8 +590,8 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, #define cpu_handle_mmu_fault cpu_mips_handle_mmu_fault void do_interrupt (CPUState *env); void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra); -target_phys_addr_t do_translate_address (CPUState *env, target_ulong address, - int rw); +target_phys_addr_t cpu_mips_translate_address (CPUState *env, target_ulong address, + int rw); static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) { diff --git a/target-mips/helper.c b/target-mips/helper.c index 1e7e01608..ec8711498 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -311,7 +311,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw, } #if !defined(CONFIG_USER_ONLY) -target_phys_addr_t do_translate_address(CPUState *env, target_ulong address, int rw) +target_phys_addr_t cpu_mips_translate_address(CPUState *env, target_ulong address, int rw) { target_phys_addr_t physical; int prot; @@ -326,10 +326,10 @@ target_phys_addr_t do_translate_address(CPUState *env, target_ulong address, int address, rw, access_type); if (ret != TLBRET_MATCH) { raise_mmu_exception(env, address, rw, ret); - cpu_loop_exit(); + return -1LL; + } else { + return physical; } - - return physical; } #endif diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index be75af5e6..dda9e825e 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -276,10 +276,24 @@ void helper_dmultu (target_ulong arg1, target_ulong arg2) #endif #ifndef CONFIG_USER_ONLY + +static inline target_phys_addr_t do_translate_address(target_ulong address, int rw) +{ + target_phys_addr_t lladdr; + + lladdr = cpu_mips_translate_address(env, address, rw); + + if (lladdr == -1LL) { + cpu_loop_exit(); + } else { + return lladdr; + } +} + #define HELPER_LD_ATOMIC(name, insn) \ target_ulong helper_##name(target_ulong arg, int mem_idx) \ { \ - env->lladdr = do_translate_address(env, arg, 0); \ + env->lladdr = do_translate_address(arg, 0); \ env->llval = do_##insn(arg, mem_idx); \ return env->llval; \ } @@ -298,7 +312,7 @@ target_ulong helper_##name(target_ulong arg1, target_ulong arg2, int mem_idx) \ env->CP0_BadVAddr = arg2; \ helper_raise_exception(EXCP_AdES); \ } \ - if (do_translate_address(env, arg2, 1) == env->lladdr) { \ + if (do_translate_address(arg2, 1) == env->lladdr) { \ tmp = do_##ld_insn(arg2, mem_idx); \ if (tmp == env->llval) { \ do_##st_insn(arg2, arg1, mem_idx); \ diff --git a/target-mips/translate.c b/target-mips/translate.c index f756ab9db..f811f50c7 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -821,7 +821,7 @@ static inline void gen_op_addr_add (DisasContext *ctx, TCGv ret, TCGv arg0, TCGv static inline void check_cp0_enabled(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0))) - generate_exception_err(ctx, EXCP_CpU, 1); + generate_exception_err(ctx, EXCP_CpU, 0); } static inline void check_cp1_enabled(DisasContext *ctx) @@ -1451,6 +1451,8 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc, tcg_gen_rotri_i32(t1, t1, uimm); tcg_gen_ext_i32_tl(cpu_gpr[rt], t1); tcg_temp_free_i32(t1); + } else { + tcg_gen_ext32s_tl(cpu_gpr[rt], t0); } opn = "rotr"; } else { @@ -1489,6 +1491,8 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc, if (env->insn_flags & ISA_MIPS32R2) { if (uimm != 0) { tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm); + } else { + tcg_gen_mov_tl(cpu_gpr[rt], t0); } opn = "drotr"; } else { diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index 8fcb5c99c..807b8fdfa 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -731,9 +731,9 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, /* label1: fast path */ reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr); - tcg_out_opc_imm(s, OPC_LW, TCG_REG_V0, TCG_REG_A0, + tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, offsetof(CPUState, tlb_table[mem_index][0].addend) + addr_meml); - tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_V0, addr_regl); + tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_A0, addr_regl); addr_reg1 = TCG_REG_V0; #endif diff --git a/usb-linux.c b/usb-linux.c index 88728e927..5619b3060 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -1036,7 +1036,7 @@ USBDevice *usb_host_device_open(const char *devname) qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr); qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id); qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id); - qdev_init(&dev->qdev); + qdev_init_nofail(&dev->qdev); return dev; fail: @@ -4094,14 +4094,15 @@ static void tcg_cpu_exec(void) for (; next_cpu != NULL; next_cpu = next_cpu->next_cpu) { CPUState *env = cur_cpu = next_cpu; - if (!vm_running) - break; if (timer_alarm_pending) { timer_alarm_pending = 0; break; } if (cpu_can_run(env)) ret = qemu_cpu_exec(env); + else if (env->stop) + break; + if (ret == EXCP_DEBUG) { gdb_set_stop_cpu(env); debug_requested = 1; @@ -6081,6 +6082,8 @@ int main(int argc, char **argv, char **envp) if (qemu_opts_foreach(&qemu_device_opts, device_init_func, NULL, 1) != 0) exit(1); + net_check_clients(); + if (!display_state) dumb_display_init(); /* just use the first displaystate for the moment */ @@ -2293,7 +2293,7 @@ static int vnc_refresh_server_surface(VncDisplay *vd) static void vnc_refresh(void *opaque) { VncDisplay *vd = opaque; - VncState *vs = NULL; + VncState *vs = NULL, *vn = NULL; int has_dirty = 0, rects = 0; vga_hw_update(); @@ -2302,8 +2302,10 @@ static void vnc_refresh(void *opaque) vs = vd->clients; while (vs != NULL) { + vn = vs->next; rects += vnc_update_client(vs, has_dirty); - vs = vs->next; + /* vs might be free()ed here */ + vs = vn; } /* vd->timer could be NULL now if the last client disconnected, * in this case don't update the timer */ |