diff options
author | Avi Kivity <avi@redhat.com> | 2009-06-17 09:39:04 +0300 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-06-17 09:39:04 +0300 |
commit | 1407fe807a5d5bbbdaafd4a48cb406a9d78aa18a (patch) | |
tree | 21d4c06538a193bf0503aea7cb0e5eb0ec932165 | |
parent | a5b526135da17b56a7be85fd51a76a1d5a917617 (diff) | |
parent | cfde4bd93100c58c0bfaed76deefb144caac488f (diff) |
Merge branch 'master' of git://git.sv.gnu.org/qemukvm-87rc1
* 'master' of git://git.sv.gnu.org/qemu: (58 commits)
exec.c: remove unnecessary #if NB_MMU_MODES
Fix vga_screen_dump_blank() PPM generation
Prevent CD-ROM media eject while device is locked
set migration max downtime
add non-arbitrary migration stop condition
kvm: Fix IRQ injection into full queue
Call qemu_bh_delete at bdrv_aio_bh_cb.
Remove dead code
QEMU KVM: i386: Fix the cpu reset state
allow CPUID vendor override
Fix help message for new configure option --enable-debug.
provide cpu_index to env mapping
pci: add define for communication class devices
vnc: improve numpad support for qemu console.
virtio blk: fix warning.
lsi53c895a: Implement write access to DMA Byte Counter
lsi53c895a: Implement read and write access to DMA Next Address
lsi53c895a: Implement Scratch Byte Register
Rename pci_register_io_region() to pci_register_bar()
Rearrange io_mem_init()
...
Conflicts:
configure
Signed-off-by: Avi Kivity <avi@redhat.com>
197 files changed, 5938 insertions, 2840 deletions
@@ -80,7 +80,9 @@ recurse-all: $(SUBDIR_RULES) BLOCK_OBJS=cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o BLOCK_OBJS+=block/cow.o block/qcow.o aes.o block/vmdk.o block/cloop.o BLOCK_OBJS+=block/dmg.o block/bochs.o block/vpc.o block/vvfat.o -BLOCK_OBJS+=block/qcow2.o block/parallels.o block/nbd.o +BLOCK_OBJS+=block/qcow2.o block/qcow2-refcount.o block/qcow2-cluster.o +BLOCK_OBJS+=block/qcow2-snapshot.o +BLOCK_OBJS+=block/parallels.o block/nbd.o BLOCK_OBJS+=nbd.o block.o aio.o ifdef CONFIG_WIN32 @@ -224,7 +226,7 @@ keymaps.o: keymaps.c keymaps.h sdl.o: sdl.c keymaps.h sdl_keysym.h -sdl.o audio/sdlaudio.o: CFLAGS += $(SDL_CFLAGS) +sdl.o audio/sdlaudio.o baum.o: CFLAGS += $(SDL_CFLAGS) acl.o: acl.h acl.c diff --git a/Makefile.target b/Makefile.target index ca8d54df7..6637d9bac 100644 --- a/Makefile.target +++ b/Makefile.target @@ -804,6 +804,8 @@ firmware.o: firmware.c $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< endif +vl.o: CFLAGS+=$(SDL_CFLAGS) + vl.o: qemu-options.h monitor.o: qemu-monitor.h @@ -1373,7 +1373,7 @@ typedef struct BlockDriverAIOCBSync { static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb) { BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb; - qemu_bh_cancel(acb->bh); + qemu_bh_delete(acb->bh); qemu_aio_release(acb); } @@ -1390,7 +1390,7 @@ static void bdrv_aio_bh_cb(void *opaque) qemu_iovec_from_buffer(acb->qiov, acb->bounce, acb->qiov->size); qemu_vfree(acb->bounce); acb->common.cb(acb->common.opaque, acb->ret); - + qemu_bh_delete(acb->bh); qemu_aio_release(acb); } @@ -1566,11 +1566,15 @@ int bdrv_media_changed(BlockDriverState *bs) /** * If eject_flag is TRUE, eject the media. Otherwise, close the tray */ -void bdrv_eject(BlockDriverState *bs, int eject_flag) +int bdrv_eject(BlockDriverState *bs, int eject_flag) { BlockDriver *drv = bs->drv; int ret; + if (bs->locked) { + return -EBUSY; + } + if (!drv || !drv->bdrv_eject) { ret = -ENOTSUP; } else { @@ -1579,7 +1583,10 @@ void bdrv_eject(BlockDriverState *bs, int eject_flag) if (ret == -ENOTSUP) { if (eject_flag) bdrv_close(bs); + ret = 0; } + + return ret; } int bdrv_is_locked(BlockDriverState *bs) @@ -124,7 +124,7 @@ int bdrv_is_inserted(BlockDriverState *bs); int bdrv_media_changed(BlockDriverState *bs); int bdrv_is_locked(BlockDriverState *bs); void bdrv_set_locked(BlockDriverState *bs, int locked); -void bdrv_eject(BlockDriverState *bs, int eject_flag); +int bdrv_eject(BlockDriverState *bs, int eject_flag); void bdrv_set_change_cb(BlockDriverState *bs, void (*change_cb)(void *opaque), void *opaque); void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size); diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c new file mode 100644 index 000000000..d349655d0 --- /dev/null +++ b/block/qcow2-cluster.c @@ -0,0 +1,800 @@ +/* + * Block driver for the QCOW version 2 format + * + * Copyright (c) 2004-2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <zlib.h> + +#include "qemu-common.h" +#include "block_int.h" +#include "block/qcow2.h" + +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; + uint8_t data[12]; + + new_l1_size = s->l1_size; + if (min_size <= new_l1_size) + return 0; + while (min_size > new_l1_size) { + new_l1_size = (new_l1_size * 3 + 1) / 2; + } +#ifdef DEBUG_ALLOC2 + printf("grow l1_table from %d to %d\n", s->l1_size, new_l1_size); +#endif + + new_l1_size2 = sizeof(uint64_t) * new_l1_size; + new_l1_table = qemu_mallocz(new_l1_size2); + memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t)); + + /* write new table (align to cluster) */ + new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2); + + for(i = 0; i < s->l1_size; i++) + new_l1_table[i] = cpu_to_be64(new_l1_table[i]); + ret = bdrv_pwrite(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2); + if (ret != new_l1_size2) + goto fail; + for(i = 0; i < s->l1_size; i++) + new_l1_table[i] = be64_to_cpu(new_l1_table[i]); + + /* 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)) + 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; + s->l1_table = new_l1_table; + s->l1_size = new_l1_size; + return 0; + fail: + qemu_free(s->l1_table); + return -EIO; +} + +void qcow2_l2_cache_reset(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + + memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t)); + memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t)); + memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t)); +} + +static inline int l2_cache_new_entry(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + uint32_t min_count; + int min_index, i; + + /* find a new entry in the least used one */ + min_index = 0; + min_count = 0xffffffff; + for(i = 0; i < L2_CACHE_SIZE; i++) { + if (s->l2_cache_counts[i] < min_count) { + min_count = s->l2_cache_counts[i]; + min_index = i; + } + } + return min_index; +} + +/* + * seek_l2_table + * + * seek l2_offset in the l2_cache table + * if not found, return NULL, + * if found, + * increments the l2 cache hit count of the entry, + * if counter overflow, divide by two all counters + * return the pointer to the l2 cache entry + * + */ + +static uint64_t *seek_l2_table(BDRVQcowState *s, uint64_t l2_offset) +{ + int i, j; + + for(i = 0; i < L2_CACHE_SIZE; i++) { + if (l2_offset == s->l2_cache_offsets[i]) { + /* increment the hit count */ + if (++s->l2_cache_counts[i] == 0xffffffff) { + for(j = 0; j < L2_CACHE_SIZE; j++) { + s->l2_cache_counts[j] >>= 1; + } + } + return s->l2_cache + (i << s->l2_bits); + } + } + return NULL; +} + +/* + * l2_load + * + * Loads a L2 table into memory. If the table is in the cache, the cache + * is used; otherwise the L2 table is loaded from the image file. + * + * Returns a pointer to the L2 table on success, or NULL if the read from + * the image file failed. + */ + +static uint64_t *l2_load(BlockDriverState *bs, uint64_t l2_offset) +{ + BDRVQcowState *s = bs->opaque; + int min_index; + uint64_t *l2_table; + + /* seek if the table for the given offset is in the cache */ + + l2_table = seek_l2_table(s, l2_offset); + if (l2_table != NULL) + return l2_table; + + /* not found: load a new entry in the least used one */ + + min_index = l2_cache_new_entry(bs); + l2_table = s->l2_cache + (min_index << s->l2_bits); + if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != + s->l2_size * sizeof(uint64_t)) + return NULL; + s->l2_cache_offsets[min_index] = l2_offset; + s->l2_cache_counts[min_index] = 1; + + return l2_table; +} + +/* + * Writes one sector of the L1 table to the disk (can't update single entries + * and we really don't want bdrv_pread to perform a read-modify-write) + */ +#define L1_ENTRIES_PER_SECTOR (512 / 8) +static int write_l1_entry(BDRVQcowState *s, int l1_index) +{ + uint64_t buf[L1_ENTRIES_PER_SECTOR]; + int l1_start_index; + int i; + + l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1); + for (i = 0; i < L1_ENTRIES_PER_SECTOR; i++) { + buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]); + } + + if (bdrv_pwrite(s->hd, s->l1_table_offset + 8 * l1_start_index, + buf, sizeof(buf)) != sizeof(buf)) + { + return -1; + } + + return 0; +} + +/* + * l2_allocate + * + * Allocate a new l2 entry in the file. If l1_index points to an already + * used entry in the L2 table (i.e. we are doing a copy on write for the L2 + * table) copy the contents of the old L2 table into the newly allocated one. + * Otherwise the new table is initialized with zeros. + * + */ + +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; + + 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)); + + /* update the L1 entry */ + + s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED; + if (write_l1_entry(s, l1_index) < 0) { + return NULL; + } + + /* allocate a new entry in the l2 cache */ + + min_index = l2_cache_new_entry(bs); + l2_table = s->l2_cache + (min_index << s->l2_bits); + + if (old_l2_offset == 0) { + /* if there was no old l2 table, clear the new table */ + memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); + } else { + /* if there was an old l2 table, read it from the disk */ + if (bdrv_pread(s->hd, old_l2_offset, + l2_table, s->l2_size * sizeof(uint64_t)) != + s->l2_size * sizeof(uint64_t)) + return NULL; + } + /* write the l2 table to the file */ + if (bdrv_pwrite(s->hd, l2_offset, + l2_table, s->l2_size * sizeof(uint64_t)) != + s->l2_size * sizeof(uint64_t)) + return NULL; + + /* update the l2 cache entry */ + + s->l2_cache_offsets[min_index] = l2_offset; + s->l2_cache_counts[min_index] = 1; + + return l2_table; +} + +static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size, + uint64_t *l2_table, uint64_t start, uint64_t mask) +{ + int i; + uint64_t offset = be64_to_cpu(l2_table[0]) & ~mask; + + if (!offset) + return 0; + + for (i = start; i < start + nb_clusters; i++) + if (offset + i * cluster_size != (be64_to_cpu(l2_table[i]) & ~mask)) + break; + + return (i - start); +} + +static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table) +{ + int i = 0; + + while(nb_clusters-- && l2_table[i] == 0) + i++; + + return i; +} + +/* The crypt function is compatible with the linux cryptoloop + algorithm for < 4 GB images. NOTE: out_buf == in_buf is + supported */ +void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num, + uint8_t *out_buf, const uint8_t *in_buf, + int nb_sectors, int enc, + const AES_KEY *key) +{ + union { + uint64_t ll[2]; + uint8_t b[16]; + } ivec; + int i; + + for(i = 0; i < nb_sectors; i++) { + ivec.ll[0] = cpu_to_le64(sector_num); + ivec.ll[1] = 0; + AES_cbc_encrypt(in_buf, out_buf, 512, key, + ivec.b, enc); + sector_num++; + in_buf += 512; + out_buf += 512; + } +} + + +static int qcow_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + BDRVQcowState *s = bs->opaque; + int ret, index_in_cluster, n, n1; + uint64_t cluster_offset; + + while (nb_sectors > 0) { + n = nb_sectors; + cluster_offset = qcow2_get_cluster_offset(bs, sector_num << 9, &n); + index_in_cluster = sector_num & (s->cluster_sectors - 1); + if (!cluster_offset) { + if (bs->backing_hd) { + /* read from the base image */ + n1 = qcow2_backing_read1(bs->backing_hd, sector_num, buf, n); + if (n1 > 0) { + ret = bdrv_read(bs->backing_hd, sector_num, buf, n1); + if (ret < 0) + return -1; + } + } else { + memset(buf, 0, 512 * n); + } + } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) { + if (qcow2_decompress_cluster(s, cluster_offset) < 0) + return -1; + memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n); + } else { + ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512); + if (ret != n * 512) + return -1; + if (s->crypt_method) { + qcow2_encrypt_sectors(s, sector_num, buf, buf, n, 0, + &s->aes_decrypt_key); + } + } + nb_sectors -= n; + sector_num += n; + buf += n * 512; + } + return 0; +} + +static int copy_sectors(BlockDriverState *bs, uint64_t start_sect, + uint64_t cluster_offset, int n_start, int n_end) +{ + BDRVQcowState *s = bs->opaque; + int n, ret; + + n = n_end - n_start; + if (n <= 0) + return 0; + ret = qcow_read(bs, start_sect + n_start, s->cluster_data, n); + if (ret < 0) + return ret; + if (s->crypt_method) { + qcow2_encrypt_sectors(s, start_sect + n_start, + s->cluster_data, + s->cluster_data, n, 1, + &s->aes_encrypt_key); + } + ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start, + s->cluster_data, n); + if (ret < 0) + return ret; + return 0; +} + + +/* + * get_cluster_offset + * + * For a given offset of the disk image, return cluster offset in + * qcow2 file. + * + * on entry, *num is the number of contiguous clusters we'd like to + * access following offset. + * + * on exit, *num is the number of contiguous clusters we can read. + * + * Return 1, if the offset is found + * Return 0, otherwise. + * + */ + +uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, + int *num) +{ + BDRVQcowState *s = bs->opaque; + int l1_index, l2_index; + uint64_t l2_offset, *l2_table, cluster_offset; + int l1_bits, c; + int index_in_cluster, nb_available, nb_needed, nb_clusters; + + index_in_cluster = (offset >> 9) & (s->cluster_sectors - 1); + nb_needed = *num + index_in_cluster; + + l1_bits = s->l2_bits + s->cluster_bits; + + /* compute how many bytes there are between the offset and + * the end of the l1 entry + */ + + nb_available = (1 << l1_bits) - (offset & ((1 << l1_bits) - 1)); + + /* compute the number of available sectors */ + + nb_available = (nb_available >> 9) + index_in_cluster; + + if (nb_needed > nb_available) { + nb_needed = nb_available; + } + + cluster_offset = 0; + + /* seek the the l2 offset in the l1 table */ + + l1_index = offset >> l1_bits; + if (l1_index >= s->l1_size) + goto out; + + l2_offset = s->l1_table[l1_index]; + + /* seek the l2 table of the given l2 offset */ + + if (!l2_offset) + goto out; + + /* load the l2 table in memory */ + + l2_offset &= ~QCOW_OFLAG_COPIED; + l2_table = l2_load(bs, l2_offset); + if (l2_table == NULL) + return 0; + + /* find the cluster offset for the given disk offset */ + + l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); + cluster_offset = be64_to_cpu(l2_table[l2_index]); + nb_clusters = size_to_clusters(s, nb_needed << 9); + + if (!cluster_offset) { + /* how many empty clusters ? */ + c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]); + } else { + /* how many allocated clusters ? */ + c = count_contiguous_clusters(nb_clusters, s->cluster_size, + &l2_table[l2_index], 0, QCOW_OFLAG_COPIED); + } + + nb_available = (c * s->cluster_sectors); +out: + if (nb_available > nb_needed) + nb_available = nb_needed; + + *num = nb_available - index_in_cluster; + + return cluster_offset & ~QCOW_OFLAG_COPIED; +} + +/* + * get_cluster_table + * + * for a given disk offset, load (and allocate if needed) + * the l2 table. + * + * the l2 table offset in the qcow2 file and the cluster index + * in the l2 table are given to the caller. + * + */ + +static int get_cluster_table(BlockDriverState *bs, uint64_t offset, + uint64_t **new_l2_table, + uint64_t *new_l2_offset, + int *new_l2_index) +{ + BDRVQcowState *s = bs->opaque; + int l1_index, l2_index, ret; + uint64_t l2_offset, *l2_table; + + /* seek the the l2 offset in the l1 table */ + + 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; + } + l2_offset = s->l1_table[l1_index]; + + /* seek the l2 table of the given l2 offset */ + + if (l2_offset & QCOW_OFLAG_COPIED) { + /* load the l2 table in memory */ + l2_offset &= ~QCOW_OFLAG_COPIED; + l2_table = l2_load(bs, l2_offset); + if (l2_table == NULL) + return 0; + } 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; + l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED; + } + + /* find the cluster offset for the given disk offset */ + + l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); + + *new_l2_table = l2_table; + *new_l2_offset = l2_offset; + *new_l2_index = l2_index; + + return 1; +} + +/* + * alloc_compressed_cluster_offset + * + * For a given offset of the disk image, return cluster offset in + * qcow2 file. + * + * If the offset is not found, allocate a new compressed cluster. + * + * Return the cluster offset if successful, + * Return 0, otherwise. + * + */ + +uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, + uint64_t offset, + int compressed_size) +{ + BDRVQcowState *s = bs->opaque; + int l2_index, ret; + uint64_t l2_offset, *l2_table, cluster_offset; + int nb_csectors; + + ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index); + if (ret == 0) + return 0; + + cluster_offset = be64_to_cpu(l2_table[l2_index]); + if (cluster_offset & QCOW_OFLAG_COPIED) + return cluster_offset & ~QCOW_OFLAG_COPIED; + + if (cluster_offset) + qcow2_free_any_clusters(bs, cluster_offset, 1); + + cluster_offset = qcow2_alloc_bytes(bs, compressed_size); + nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - + (cluster_offset >> 9); + + cluster_offset |= QCOW_OFLAG_COMPRESSED | + ((uint64_t)nb_csectors << s->csize_shift); + + /* update L2 table */ + + /* compressed clusters never have the copied flag */ + + l2_table[l2_index] = cpu_to_be64(cluster_offset); + if (bdrv_pwrite(s->hd, + l2_offset + l2_index * sizeof(uint64_t), + l2_table + l2_index, + sizeof(uint64_t)) != sizeof(uint64_t)) + return 0; + + return cluster_offset; +} + +/* + * Write L2 table updates to disk, writing whole sectors to avoid a + * read-modify-write in bdrv_pwrite + */ +#define L2_ENTRIES_PER_SECTOR (512 / 8) +static int write_l2_entries(BDRVQcowState *s, uint64_t *l2_table, + uint64_t l2_offset, int l2_index, int num) +{ + int l2_start_index = l2_index & ~(L1_ENTRIES_PER_SECTOR - 1); + int start_offset = (8 * l2_index) & ~511; + int end_offset = (8 * (l2_index + num) + 511) & ~511; + size_t len = end_offset - start_offset; + + if (bdrv_pwrite(s->hd, l2_offset + start_offset, &l2_table[l2_start_index], + len) != len) + { + return -1; + } + + return 0; +} + +int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset, + QCowL2Meta *m) +{ + BDRVQcowState *s = bs->opaque; + int i, j = 0, l2_index, ret; + uint64_t *old_cluster, start_sect, l2_offset, *l2_table; + + if (m->nb_clusters == 0) + return 0; + + old_cluster = qemu_malloc(m->nb_clusters * sizeof(uint64_t)); + + /* copy content of unmodified sectors */ + start_sect = (m->offset & ~(s->cluster_size - 1)) >> 9; + if (m->n_start) { + ret = copy_sectors(bs, start_sect, cluster_offset, 0, m->n_start); + if (ret < 0) + goto err; + } + + if (m->nb_available & (s->cluster_sectors - 1)) { + uint64_t end = m->nb_available & ~(uint64_t)(s->cluster_sectors - 1); + ret = copy_sectors(bs, start_sect + end, cluster_offset + (end << 9), + m->nb_available - end, s->cluster_sectors); + if (ret < 0) + goto err; + } + + ret = -EIO; + /* update L2 table */ + if (!get_cluster_table(bs, m->offset, &l2_table, &l2_offset, &l2_index)) + goto err; + + for (i = 0; i < m->nb_clusters; i++) { + /* if two concurrent writes happen to the same unallocated cluster + * each write allocates separate cluster and writes data concurrently. + * The first one to complete updates l2 table with pointer to its + * cluster the second one has to do RMW (which is done above by + * copy_sectors()), update l2 table with its cluster pointer and free + * old cluster. This is what this loop does */ + if(l2_table[l2_index + i] != 0) + old_cluster[j++] = l2_table[l2_index + i]; + + l2_table[l2_index + i] = cpu_to_be64((cluster_offset + + (i << s->cluster_bits)) | QCOW_OFLAG_COPIED); + } + + if (write_l2_entries(s, l2_table, l2_offset, l2_index, m->nb_clusters) < 0) { + ret = -1; + goto err; + } + + for (i = 0; i < j; i++) + qcow2_free_any_clusters(bs, + be64_to_cpu(old_cluster[i]) & ~QCOW_OFLAG_COPIED, 1); + + ret = 0; +err: + qemu_free(old_cluster); + return ret; + } + +/* + * alloc_cluster_offset + * + * 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. + * + */ + +uint64_t 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; + int nb_clusters, i = 0; + + ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index); + if (ret == 0) + return 0; + + nb_clusters = size_to_clusters(s, n_end << 9); + + nb_clusters = MIN(nb_clusters, s->l2_size - l2_index); + + cluster_offset = be64_to_cpu(l2_table[l2_index]); + + /* We keep all QCOW_OFLAG_COPIED clusters */ + + if (cluster_offset & QCOW_OFLAG_COPIED) { + nb_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size, + &l2_table[l2_index], 0, 0); + + cluster_offset &= ~QCOW_OFLAG_COPIED; + m->nb_clusters = 0; + + goto out; + } + + /* for the moment, multiple compressed clusters are not managed */ + + if (cluster_offset & QCOW_OFLAG_COMPRESSED) + nb_clusters = 1; + + /* how many available clusters ? */ + + 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])) + break; + + i += count_contiguous_free_clusters(nb_clusters - i, + &l2_table[l2_index + i]); + + cluster_offset = be64_to_cpu(l2_table[l2_index + i]); + + if ((cluster_offset & QCOW_OFLAG_COPIED) || + (cluster_offset & QCOW_OFLAG_COMPRESSED)) + break; + } + nb_clusters = i; + + /* allocate a new cluster */ + + cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size); + + /* save info needed for meta data update */ + m->offset = offset; + m->n_start = n_start; + m->nb_clusters = nb_clusters; + +out: + m->nb_available = MIN(nb_clusters << (s->cluster_bits - 9), n_end); + + *num = m->nb_available - n_start; + + return cluster_offset; +} + +static int decompress_buffer(uint8_t *out_buf, int out_buf_size, + const uint8_t *buf, int buf_size) +{ + z_stream strm1, *strm = &strm1; + int ret, out_len; + + memset(strm, 0, sizeof(*strm)); + + strm->next_in = (uint8_t *)buf; + strm->avail_in = buf_size; + strm->next_out = out_buf; + strm->avail_out = out_buf_size; + + ret = inflateInit2(strm, -12); + if (ret != Z_OK) + return -1; + ret = inflate(strm, Z_FINISH); + out_len = strm->next_out - out_buf; + if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) || + out_len != out_buf_size) { + inflateEnd(strm); + return -1; + } + inflateEnd(strm); + return 0; +} + +int qcow2_decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) +{ + int ret, csize, nb_csectors, sector_offset; + uint64_t coffset; + + coffset = cluster_offset & s->cluster_offset_mask; + if (s->cluster_cache_offset != coffset) { + nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1; + sector_offset = coffset & 511; + csize = nb_csectors * 512 - sector_offset; + ret = bdrv_read(s->hd, coffset >> 9, s->cluster_data, nb_csectors); + if (ret < 0) { + return -1; + } + if (decompress_buffer(s->cluster_cache, s->cluster_size, + s->cluster_data + sector_offset, csize) < 0) { + return -1; + } + s->cluster_cache_offset = coffset; + } + return 0; +} diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c new file mode 100644 index 000000000..dd6e293d0 --- /dev/null +++ b/block/qcow2-refcount.c @@ -0,0 +1,854 @@ +/* + * Block driver for the QCOW version 2 format + * + * Copyright (c) 2004-2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu-common.h" +#include "block_int.h" +#include "block/qcow2.h" + +static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size); +static int update_refcount(BlockDriverState *bs, + int64_t offset, int64_t length, + int addend); + +/*********************************************************/ +/* refcount handling */ + +int qcow2_refcount_init(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + int ret, refcount_table_size2, i; + + s->refcount_block_cache = qemu_malloc(s->cluster_size); + refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t); + s->refcount_table = qemu_malloc(refcount_table_size2); + if (s->refcount_table_size > 0) { + ret = bdrv_pread(s->hd, s->refcount_table_offset, + s->refcount_table, refcount_table_size2); + if (ret != refcount_table_size2) + goto fail; + for(i = 0; i < s->refcount_table_size; i++) + be64_to_cpus(&s->refcount_table[i]); + } + return 0; + fail: + return -ENOMEM; +} + +void qcow2_refcount_close(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + qemu_free(s->refcount_block_cache); + qemu_free(s->refcount_table); +} + + +static int load_refcount_block(BlockDriverState *bs, + int64_t refcount_block_offset) +{ + BDRVQcowState *s = bs->opaque; + int ret; + ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache, + s->cluster_size); + if (ret != s->cluster_size) + return -EIO; + s->refcount_block_cache_offset = refcount_block_offset; + return 0; +} + +static int get_refcount(BlockDriverState *bs, int64_t cluster_index) +{ + BDRVQcowState *s = bs->opaque; + int refcount_table_index, block_index; + int64_t refcount_block_offset; + + refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); + if (refcount_table_index >= s->refcount_table_size) + return 0; + refcount_block_offset = s->refcount_table[refcount_table_index]; + if (!refcount_block_offset) + return 0; + if (refcount_block_offset != s->refcount_block_cache_offset) { + /* better than nothing: return allocated if read error */ + if (load_refcount_block(bs, refcount_block_offset) < 0) + return 1; + } + block_index = cluster_index & + ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1); + return be16_to_cpu(s->refcount_block_cache[block_index]); +} + +static int grow_refcount_table(BlockDriverState *bs, int min_size) +{ + BDRVQcowState *s = bs->opaque; + int new_table_size, new_table_size2, refcount_table_clusters, i, ret; + uint64_t *new_table; + int64_t table_offset; + uint8_t data[12]; + int old_table_size; + int64_t old_table_offset; + + if (min_size <= s->refcount_table_size) + return 0; + /* compute new table size */ + refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3); + for(;;) { + if (refcount_table_clusters == 0) { + refcount_table_clusters = 1; + } else { + refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2; + } + new_table_size = refcount_table_clusters << (s->cluster_bits - 3); + if (min_size <= new_table_size) + break; + } +#ifdef DEBUG_ALLOC2 + printf("grow_refcount_table from %d to %d\n", + s->refcount_table_size, + new_table_size); +#endif + new_table_size2 = new_table_size * sizeof(uint64_t); + new_table = qemu_mallocz(new_table_size2); + memcpy(new_table, s->refcount_table, + s->refcount_table_size * sizeof(uint64_t)); + for(i = 0; i < s->refcount_table_size; i++) + cpu_to_be64s(&new_table[i]); + /* Note: we cannot update the refcount now to avoid recursion */ + table_offset = alloc_clusters_noref(bs, new_table_size2); + ret = bdrv_pwrite(s->hd, table_offset, new_table, new_table_size2); + if (ret != new_table_size2) + goto fail; + for(i = 0; i < s->refcount_table_size; i++) + be64_to_cpus(&new_table[i]); + + 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)) + goto fail; + qemu_free(s->refcount_table); + old_table_offset = s->refcount_table_offset; + old_table_size = s->refcount_table_size; + s->refcount_table = new_table; + s->refcount_table_size = new_table_size; + s->refcount_table_offset = table_offset; + + update_refcount(bs, table_offset, new_table_size2, 1); + qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t)); + return 0; + fail: + qcow2_free_clusters(bs, table_offset, new_table_size2); + qemu_free(new_table); + return -EIO; +} + + +static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) +{ + BDRVQcowState *s = bs->opaque; + int64_t offset, refcount_block_offset; + int ret, refcount_table_index; + uint64_t data64; + + /* Find L1 index and grow refcount table if needed */ + refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); + if (refcount_table_index >= s->refcount_table_size) { + ret = grow_refcount_table(bs, refcount_table_index + 1); + if (ret < 0) + return ret; + } + + /* Load or allocate the refcount block */ + refcount_block_offset = s->refcount_table[refcount_table_index]; + if (!refcount_block_offset) { + /* create a new refcount block */ + /* Note: we cannot update the refcount now to avoid recursion */ + offset = alloc_clusters_noref(bs, s->cluster_size); + memset(s->refcount_block_cache, 0, s->cluster_size); + ret = bdrv_pwrite(s->hd, offset, s->refcount_block_cache, s->cluster_size); + if (ret != s->cluster_size) + return -EINVAL; + s->refcount_table[refcount_table_index] = offset; + data64 = cpu_to_be64(offset); + ret = bdrv_pwrite(s->hd, s->refcount_table_offset + + refcount_table_index * sizeof(uint64_t), + &data64, sizeof(data64)); + if (ret != sizeof(data64)) + return -EINVAL; + + refcount_block_offset = offset; + s->refcount_block_cache_offset = offset; + update_refcount(bs, offset, s->cluster_size, 1); + } else { + if (refcount_block_offset != s->refcount_block_cache_offset) { + if (load_refcount_block(bs, refcount_block_offset) < 0) + return -EIO; + } + } + + return refcount_block_offset; +} + +#define REFCOUNTS_PER_SECTOR (512 >> REFCOUNT_SHIFT) +static int write_refcount_block_entries(BDRVQcowState *s, + int64_t refcount_block_offset, int first_index, int last_index) +{ + size_t size; + + first_index &= ~(REFCOUNTS_PER_SECTOR - 1); + last_index = (last_index + REFCOUNTS_PER_SECTOR) + & ~(REFCOUNTS_PER_SECTOR - 1); + + size = (last_index - first_index) << REFCOUNT_SHIFT; + if (bdrv_pwrite(s->hd, + refcount_block_offset + (first_index << REFCOUNT_SHIFT), + &s->refcount_block_cache[first_index], size) != size) + { + return -EIO; + } + + return 0; +} + +/* XXX: cache several refcount block clusters ? */ +static int 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; + +#ifdef DEBUG_ALLOC2 + printf("update_refcount: offset=%lld size=%lld addend=%d\n", + offset, length, addend); +#endif + if (length <= 0) + return -EINVAL; + start = offset & ~(s->cluster_size - 1); + last = (offset + length - 1) & ~(s->cluster_size - 1); + for(cluster_offset = start; cluster_offset <= last; + cluster_offset += s->cluster_size) + { + int block_index, refcount; + int64_t cluster_index = cluster_offset >> s->cluster_bits; + + /* Only write refcount block to disk when we are done with it */ + old_table_index = table_index; + table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); + if ((old_table_index >= 0) && (table_index != old_table_index)) { + + if (write_refcount_block_entries(s, refcount_block_offset, + first_index, last_index) < 0) + { + return -EIO; + } + + first_index = -1; + last_index = -1; + } + + /* 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; + } + + /* we can update the count and save it */ + block_index = cluster_index & + ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1); + if (first_index == -1 || block_index < first_index) { + first_index = block_index; + } + if (block_index > last_index) { + last_index = block_index; + } + + refcount = be16_to_cpu(s->refcount_block_cache[block_index]); + refcount += addend; + if (refcount < 0 || refcount > 0xffff) + return -EINVAL; + 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); + } + + /* 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 0; +} + +/* addend must be 1 or -1 */ +static int update_cluster_refcount(BlockDriverState *bs, + int64_t cluster_index, + int addend) +{ + BDRVQcowState *s = bs->opaque; + int ret; + + ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend); + if (ret < 0) { + return ret; + } + + return get_refcount(bs, cluster_index); +} + + + +/*********************************************************/ +/* cluster allocation functions */ + + + +/* return < 0 if error */ +static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size) +{ + BDRVQcowState *s = bs->opaque; + int i, nb_clusters; + + nb_clusters = size_to_clusters(s, size); +retry: + for(i = 0; i < nb_clusters; i++) { + int64_t i = s->free_cluster_index++; + if (get_refcount(bs, i) != 0) + goto retry; + } +#ifdef DEBUG_ALLOC2 + printf("alloc_clusters: size=%lld -> %lld\n", + size, + (s->free_cluster_index - nb_clusters) << s->cluster_bits); +#endif + return (s->free_cluster_index - nb_clusters) << s->cluster_bits; +} + +int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size) +{ + int64_t offset; + + offset = alloc_clusters_noref(bs, size); + update_refcount(bs, offset, size, 1); + return offset; +} + +/* only used to allocate compressed sectors. We try to allocate + contiguous sectors. size must be <= cluster_size */ +int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size) +{ + BDRVQcowState *s = bs->opaque; + int64_t offset, cluster_offset; + int free_in_cluster; + + assert(size > 0 && size <= s->cluster_size); + if (s->free_byte_offset == 0) { + s->free_byte_offset = qcow2_alloc_clusters(bs, s->cluster_size); + } + redo: + free_in_cluster = s->cluster_size - + (s->free_byte_offset & (s->cluster_size - 1)); + if (size <= free_in_cluster) { + /* enough space in current cluster */ + offset = s->free_byte_offset; + s->free_byte_offset += size; + free_in_cluster -= size; + if (free_in_cluster == 0) + s->free_byte_offset = 0; + if ((offset & (s->cluster_size - 1)) != 0) + update_cluster_refcount(bs, offset >> s->cluster_bits, 1); + } else { + offset = qcow2_alloc_clusters(bs, s->cluster_size); + cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1); + if ((cluster_offset + s->cluster_size) == offset) { + /* we are lucky: contiguous data */ + offset = s->free_byte_offset; + update_cluster_refcount(bs, offset >> s->cluster_bits, 1); + s->free_byte_offset += size; + } else { + s->free_byte_offset = offset; + goto redo; + } + } + return offset; +} + +void qcow2_free_clusters(BlockDriverState *bs, + int64_t offset, int64_t size) +{ + update_refcount(bs, offset, size, -1); +} + +/* + * free_any_clusters + * + * free clusters according to its type: compressed or not + * + */ + +void qcow2_free_any_clusters(BlockDriverState *bs, + uint64_t cluster_offset, int nb_clusters) +{ + BDRVQcowState *s = bs->opaque; + + /* free the cluster */ + + if (cluster_offset & QCOW_OFLAG_COMPRESSED) { + int nb_csectors; + nb_csectors = ((cluster_offset >> s->csize_shift) & + s->csize_mask) + 1; + qcow2_free_clusters(bs, + (cluster_offset & s->cluster_offset_mask) & ~511, + nb_csectors * 512); + return; + } + + qcow2_free_clusters(bs, cluster_offset, nb_clusters << s->cluster_bits); + + return; +} + + + +/*********************************************************/ +/* snapshots and image creation */ + + + +void qcow2_create_refcount_update(QCowCreateState *s, int64_t offset, + int64_t size) +{ + int refcount; + int64_t start, last, cluster_offset; + uint16_t *p; + + start = offset & ~(s->cluster_size - 1); + last = (offset + size - 1) & ~(s->cluster_size - 1); + for(cluster_offset = start; cluster_offset <= last; + cluster_offset += s->cluster_size) { + p = &s->refcount_block[cluster_offset >> s->cluster_bits]; + refcount = be16_to_cpu(*p); + refcount++; + *p = cpu_to_be16(refcount); + } +} + +/* update the refcounts of snapshots and the copied flag */ +int qcow2_update_snapshot_refcount(BlockDriverState *bs, + int64_t l1_table_offset, int l1_size, int addend) +{ + BDRVQcowState *s = bs->opaque; + uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated; + int64_t old_offset, old_l2_offset; + int l2_size, i, j, l1_modified, l2_modified, nb_csectors, refcount; + + qcow2_l2_cache_reset(bs); + + l2_table = NULL; + l1_table = NULL; + l1_size2 = l1_size * sizeof(uint64_t); + l1_allocated = 0; + if (l1_table_offset != s->l1_table_offset) { + l1_table = qemu_malloc(l1_size2); + l1_allocated = 1; + if (bdrv_pread(s->hd, l1_table_offset, + l1_table, l1_size2) != l1_size2) + goto fail; + for(i = 0;i < l1_size; i++) + be64_to_cpus(&l1_table[i]); + } else { + assert(l1_size == s->l1_size); + l1_table = s->l1_table; + l1_allocated = 0; + } + + l2_size = s->l2_size * sizeof(uint64_t); + l2_table = qemu_malloc(l2_size); + l1_modified = 0; + for(i = 0; i < l1_size; i++) { + l2_offset = l1_table[i]; + if (l2_offset) { + old_l2_offset = l2_offset; + l2_offset &= ~QCOW_OFLAG_COPIED; + l2_modified = 0; + if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size) + goto fail; + for(j = 0; j < s->l2_size; j++) { + offset = be64_to_cpu(l2_table[j]); + if (offset != 0) { + old_offset = offset; + offset &= ~QCOW_OFLAG_COPIED; + 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); + /* compressed clusters are never modified */ + refcount = 2; + } else { + if (addend != 0) { + refcount = update_cluster_refcount(bs, offset >> s->cluster_bits, addend); + } else { + refcount = get_refcount(bs, offset >> s->cluster_bits); + } + } + + if (refcount == 1) { + offset |= QCOW_OFLAG_COPIED; + } + if (offset != old_offset) { + l2_table[j] = cpu_to_be64(offset); + l2_modified = 1; + } + } + } + if (l2_modified) { + if (bdrv_pwrite(s->hd, + l2_offset, l2_table, l2_size) != l2_size) + goto fail; + } + + if (addend != 0) { + refcount = update_cluster_refcount(bs, l2_offset >> s->cluster_bits, addend); + } else { + refcount = get_refcount(bs, l2_offset >> s->cluster_bits); + } + if (refcount == 1) { + l2_offset |= QCOW_OFLAG_COPIED; + } + if (l2_offset != old_l2_offset) { + l1_table[i] = l2_offset; + l1_modified = 1; + } + } + } + if (l1_modified) { + for(i = 0; i < l1_size; i++) + cpu_to_be64s(&l1_table[i]); + if (bdrv_pwrite(s->hd, l1_table_offset, l1_table, + l1_size2) != l1_size2) + goto fail; + for(i = 0; i < l1_size; i++) + be64_to_cpus(&l1_table[i]); + } + if (l1_allocated) + qemu_free(l1_table); + qemu_free(l2_table); + return 0; + fail: + if (l1_allocated) + qemu_free(l1_table); + qemu_free(l2_table); + return -EIO; +} + + + + +/*********************************************************/ +/* refcount checking functions */ + + + +/* + * Increases the refcount for a range of clusters in a given refcount table. + * This is used to construct a temporary refcount table out of L1 and L2 tables + * which can be compared the the refcount table saved in the image. + * + * Returns the number of errors in the image that were found + */ +static int inc_refcounts(BlockDriverState *bs, + uint16_t *refcount_table, + int refcount_table_size, + int64_t offset, int64_t size) +{ + BDRVQcowState *s = bs->opaque; + int64_t start, last, cluster_offset; + int k; + int errors = 0; + + if (size <= 0) + return 0; + + start = offset & ~(s->cluster_size - 1); + last = (offset + size - 1) & ~(s->cluster_size - 1); + for(cluster_offset = start; cluster_offset <= last; + cluster_offset += s->cluster_size) { + k = cluster_offset >> s->cluster_bits; + if (k < 0 || k >= refcount_table_size) { + fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n", + cluster_offset); + errors++; + } else { + if (++refcount_table[k] == 0) { + fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64 + "\n", cluster_offset); + errors++; + } + } + } + + return errors; +} + +/* + * Increases the refcount in the given refcount table for the all clusters + * referenced in the L2 table. While doing so, performs some checks on L2 + * entries. + * + * Returns the number of errors found by the checks or -errno if an internal + * error occurred. + */ +static int check_refcounts_l2(BlockDriverState *bs, + uint16_t *refcount_table, int refcount_table_size, int64_t l2_offset, + int check_copied) +{ + BDRVQcowState *s = bs->opaque; + uint64_t *l2_table, offset; + int i, l2_size, nb_csectors, refcount; + int errors = 0; + + /* Read L2 table from disk */ + l2_size = s->l2_size * sizeof(uint64_t); + l2_table = qemu_malloc(l2_size); + + if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size) + goto fail; + + /* Do the actual checks */ + for(i = 0; i < s->l2_size; i++) { + offset = be64_to_cpu(l2_table[i]); + if (offset != 0) { + if (offset & QCOW_OFLAG_COMPRESSED) { + /* Compressed clusters don't have QCOW_OFLAG_COPIED */ + if (offset & QCOW_OFLAG_COPIED) { + fprintf(stderr, "ERROR: cluster %" PRId64 ": " + "copied flag must never be set for compressed " + "clusters\n", offset >> s->cluster_bits); + offset &= ~QCOW_OFLAG_COPIED; + errors++; + } + + /* Mark cluster as used */ + nb_csectors = ((offset >> s->csize_shift) & + s->csize_mask) + 1; + offset &= s->cluster_offset_mask; + errors += inc_refcounts(bs, refcount_table, + refcount_table_size, + offset & ~511, nb_csectors * 512); + } else { + /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */ + if (check_copied) { + uint64_t entry = offset; + offset &= ~QCOW_OFLAG_COPIED; + refcount = get_refcount(bs, offset >> s->cluster_bits); + if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) { + fprintf(stderr, "ERROR OFLAG_COPIED: offset=%" + PRIx64 " refcount=%d\n", entry, refcount); + errors++; + } + } + + /* Mark cluster as used */ + offset &= ~QCOW_OFLAG_COPIED; + errors += inc_refcounts(bs, refcount_table, + refcount_table_size, + offset, s->cluster_size); + + /* Correct offsets are cluster aligned */ + if (offset & (s->cluster_size - 1)) { + fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not " + "properly aligned; L2 entry corrupted.\n", offset); + errors++; + } + } + } + } + + qemu_free(l2_table); + return errors; + +fail: + fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n"); + qemu_free(l2_table); + return -EIO; +} + +/* + * Increases the refcount for the L1 table, its L2 tables and all referenced + * clusters in the given refcount table. While doing so, performs some checks + * on L1 and L2 entries. + * + * Returns the number of errors found by the checks or -errno if an internal + * error occurred. + */ +static int check_refcounts_l1(BlockDriverState *bs, + uint16_t *refcount_table, + int refcount_table_size, + int64_t l1_table_offset, int l1_size, + int check_copied) +{ + BDRVQcowState *s = bs->opaque; + uint64_t *l1_table, l2_offset, l1_size2; + int i, refcount, ret; + int errors = 0; + + l1_size2 = l1_size * sizeof(uint64_t); + + /* Mark L1 table as used */ + errors += inc_refcounts(bs, refcount_table, refcount_table_size, + l1_table_offset, l1_size2); + + /* Read L1 table entries from disk */ + l1_table = qemu_malloc(l1_size2); + if (bdrv_pread(s->hd, l1_table_offset, + l1_table, l1_size2) != l1_size2) + goto fail; + for(i = 0;i < l1_size; i++) + be64_to_cpus(&l1_table[i]); + + /* Do the actual checks */ + for(i = 0; i < l1_size; i++) { + l2_offset = l1_table[i]; + if (l2_offset) { + /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */ + if (check_copied) { + refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED) + >> s->cluster_bits); + if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) { + fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64 + " refcount=%d\n", l2_offset, refcount); + errors++; + } + } + + /* Mark L2 table as used */ + l2_offset &= ~QCOW_OFLAG_COPIED; + errors += inc_refcounts(bs, refcount_table, + refcount_table_size, + l2_offset, + s->cluster_size); + + /* L2 tables are cluster aligned */ + if (l2_offset & (s->cluster_size - 1)) { + fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not " + "cluster aligned; L1 entry corrupted\n", l2_offset); + errors++; + } + + /* Process and check L2 entries */ + ret = check_refcounts_l2(bs, refcount_table, refcount_table_size, + l2_offset, check_copied); + if (ret < 0) { + goto fail; + } + errors += ret; + } + } + qemu_free(l1_table); + return errors; + +fail: + fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n"); + qemu_free(l1_table); + return -EIO; +} + +/* + * Checks an image for refcount consistency. + * + * Returns 0 if no errors are found, the number of errors in case the image is + * detected as corrupted, and -errno when an internal error occured. + */ +int qcow2_check_refcounts(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + int64_t size; + int nb_clusters, refcount1, refcount2, i; + QCowSnapshot *sn; + uint16_t *refcount_table; + int ret, errors = 0; + + size = bdrv_getlength(s->hd); + nb_clusters = size_to_clusters(s, size); + refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t)); + + /* header */ + errors += inc_refcounts(bs, refcount_table, nb_clusters, + 0, s->cluster_size); + + /* current L1 table */ + ret = check_refcounts_l1(bs, refcount_table, nb_clusters, + s->l1_table_offset, s->l1_size, 1); + if (ret < 0) { + return ret; + } + errors += ret; + + /* snapshots */ + for(i = 0; i < s->nb_snapshots; i++) { + sn = s->snapshots + i; + check_refcounts_l1(bs, refcount_table, nb_clusters, + sn->l1_table_offset, sn->l1_size, 0); + } + errors += inc_refcounts(bs, refcount_table, nb_clusters, + s->snapshots_offset, s->snapshots_size); + + /* refcount data */ + errors += inc_refcounts(bs, refcount_table, nb_clusters, + s->refcount_table_offset, + s->refcount_table_size * sizeof(uint64_t)); + for(i = 0; i < s->refcount_table_size; i++) { + int64_t offset; + offset = s->refcount_table[i]; + if (offset != 0) { + errors += inc_refcounts(bs, refcount_table, nb_clusters, + offset, s->cluster_size); + } + } + + /* compare ref counts */ + for(i = 0; i < nb_clusters; i++) { + refcount1 = get_refcount(bs, i); + refcount2 = refcount_table[i]; + if (refcount1 != refcount2) { + fprintf(stderr, "ERROR cluster %d refcount=%d reference=%d\n", + i, refcount1, refcount2); + errors++; + } + } + + qemu_free(refcount_table); + + return errors; +} + diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c new file mode 100644 index 000000000..e1e4d8973 --- /dev/null +++ b/block/qcow2-snapshot.c @@ -0,0 +1,405 @@ +/* + * Block driver for the QCOW version 2 format + * + * Copyright (c) 2004-2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu-common.h" +#include "block_int.h" +#include "block/qcow2.h" + +typedef struct __attribute__((packed)) QCowSnapshotHeader { + /* header is 8 byte aligned */ + uint64_t l1_table_offset; + + uint32_t l1_size; + uint16_t id_str_size; + uint16_t name_size; + + uint32_t date_sec; + uint32_t date_nsec; + + uint64_t vm_clock_nsec; + + uint32_t vm_state_size; + uint32_t extra_data_size; /* for extension */ + /* extra data follows */ + /* id_str follows */ + /* name follows */ +} QCowSnapshotHeader; + +void qcow2_free_snapshots(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + int i; + + for(i = 0; i < s->nb_snapshots; i++) { + qemu_free(s->snapshots[i].name); + qemu_free(s->snapshots[i].id_str); + } + qemu_free(s->snapshots); + s->snapshots = NULL; + s->nb_snapshots = 0; +} + +int qcow2_read_snapshots(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + QCowSnapshotHeader h; + QCowSnapshot *sn; + int i, id_str_size, name_size; + int64_t offset; + uint32_t extra_data_size; + + if (!s->nb_snapshots) { + s->snapshots = NULL; + s->snapshots_size = 0; + return 0; + } + + offset = s->snapshots_offset; + s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot)); + for(i = 0; i < s->nb_snapshots; i++) { + offset = align_offset(offset, 8); + if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h)) + goto fail; + offset += sizeof(h); + sn = s->snapshots + i; + sn->l1_table_offset = be64_to_cpu(h.l1_table_offset); + sn->l1_size = be32_to_cpu(h.l1_size); + sn->vm_state_size = be32_to_cpu(h.vm_state_size); + sn->date_sec = be32_to_cpu(h.date_sec); + sn->date_nsec = be32_to_cpu(h.date_nsec); + sn->vm_clock_nsec = be64_to_cpu(h.vm_clock_nsec); + extra_data_size = be32_to_cpu(h.extra_data_size); + + id_str_size = be16_to_cpu(h.id_str_size); + name_size = be16_to_cpu(h.name_size); + + offset += extra_data_size; + + sn->id_str = qemu_malloc(id_str_size + 1); + if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size) + goto fail; + offset += id_str_size; + sn->id_str[id_str_size] = '\0'; + + sn->name = qemu_malloc(name_size + 1); + if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size) + goto fail; + offset += name_size; + sn->name[name_size] = '\0'; + } + s->snapshots_size = offset - s->snapshots_offset; + return 0; + fail: + qcow2_free_snapshots(bs); + return -1; +} + +/* add at the end of the file a new list of snapshots */ +static int qcow_write_snapshots(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + QCowSnapshot *sn; + QCowSnapshotHeader h; + int i, name_size, id_str_size, snapshots_size; + uint64_t data64; + uint32_t data32; + int64_t offset, snapshots_offset; + + /* compute the size of the snapshots */ + offset = 0; + for(i = 0; i < s->nb_snapshots; i++) { + sn = s->snapshots + i; + offset = align_offset(offset, 8); + offset += sizeof(h); + offset += strlen(sn->id_str); + offset += strlen(sn->name); + } + snapshots_size = offset; + + snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size); + offset = snapshots_offset; + + for(i = 0; i < s->nb_snapshots; i++) { + sn = s->snapshots + i; + memset(&h, 0, sizeof(h)); + h.l1_table_offset = cpu_to_be64(sn->l1_table_offset); + h.l1_size = cpu_to_be32(sn->l1_size); + h.vm_state_size = cpu_to_be32(sn->vm_state_size); + h.date_sec = cpu_to_be32(sn->date_sec); + h.date_nsec = cpu_to_be32(sn->date_nsec); + h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec); + + id_str_size = strlen(sn->id_str); + name_size = strlen(sn->name); + h.id_str_size = cpu_to_be16(id_str_size); + h.name_size = cpu_to_be16(name_size); + offset = align_offset(offset, 8); + if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h)) + goto fail; + offset += sizeof(h); + if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size) + goto fail; + offset += id_str_size; + if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size) + goto fail; + offset += name_size; + } + + /* update the various header fields */ + data64 = cpu_to_be64(snapshots_offset); + if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset), + &data64, sizeof(data64)) != sizeof(data64)) + goto fail; + data32 = cpu_to_be32(s->nb_snapshots); + if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots), + &data32, sizeof(data32)) != sizeof(data32)) + goto fail; + + /* free the old snapshot table */ + qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size); + s->snapshots_offset = snapshots_offset; + s->snapshots_size = snapshots_size; + return 0; + fail: + return -1; +} + +static void find_new_snapshot_id(BlockDriverState *bs, + char *id_str, int id_str_size) +{ + BDRVQcowState *s = bs->opaque; + QCowSnapshot *sn; + int i, id, id_max = 0; + + for(i = 0; i < s->nb_snapshots; i++) { + sn = s->snapshots + i; + id = strtoul(sn->id_str, NULL, 10); + if (id > id_max) + id_max = id; + } + snprintf(id_str, id_str_size, "%d", id_max + 1); +} + +static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str) +{ + BDRVQcowState *s = bs->opaque; + int i; + + for(i = 0; i < s->nb_snapshots; i++) { + if (!strcmp(s->snapshots[i].id_str, id_str)) + return i; + } + return -1; +} + +static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name) +{ + BDRVQcowState *s = bs->opaque; + int i, ret; + + ret = find_snapshot_by_id(bs, name); + if (ret >= 0) + return ret; + for(i = 0; i < s->nb_snapshots; i++) { + if (!strcmp(s->snapshots[i].name, name)) + return i; + } + return -1; +} + +/* if no id is provided, a new one is constructed */ +int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) +{ + BDRVQcowState *s = bs->opaque; + QCowSnapshot *snapshots1, sn1, *sn = &sn1; + int i, ret; + uint64_t *l1_table = NULL; + + memset(sn, 0, sizeof(*sn)); + + if (sn_info->id_str[0] == '\0') { + /* compute a new id */ + find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str)); + } + + /* check that the ID is unique */ + if (find_snapshot_by_id(bs, sn_info->id_str) >= 0) + return -ENOENT; + + sn->id_str = qemu_strdup(sn_info->id_str); + if (!sn->id_str) + goto fail; + sn->name = qemu_strdup(sn_info->name); + if (!sn->name) + goto fail; + sn->vm_state_size = sn_info->vm_state_size; + sn->date_sec = sn_info->date_sec; + sn->date_nsec = sn_info->date_nsec; + sn->vm_clock_nsec = sn_info->vm_clock_nsec; + + ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1); + if (ret < 0) + goto fail; + + /* create the L1 table of the snapshot */ + sn->l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t)); + sn->l1_size = s->l1_size; + + l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t)); + for(i = 0; i < s->l1_size; i++) { + l1_table[i] = cpu_to_be64(s->l1_table[i]); + } + if (bdrv_pwrite(s->hd, sn->l1_table_offset, + l1_table, s->l1_size * sizeof(uint64_t)) != + (s->l1_size * sizeof(uint64_t))) + goto fail; + qemu_free(l1_table); + l1_table = NULL; + + snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot)); + if (s->snapshots) { + memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot)); + qemu_free(s->snapshots); + } + s->snapshots = snapshots1; + s->snapshots[s->nb_snapshots++] = *sn; + + if (qcow_write_snapshots(bs) < 0) + goto fail; +#ifdef DEBUG_ALLOC + check_refcounts(bs); +#endif + return 0; + fail: + qemu_free(sn->name); + qemu_free(l1_table); + return -1; +} + +/* copy the snapshot 'snapshot_name' into the current disk image */ +int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) +{ + BDRVQcowState *s = bs->opaque; + QCowSnapshot *sn; + int i, snapshot_index, l1_size2; + + snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id); + if (snapshot_index < 0) + return -ENOENT; + sn = &s->snapshots[snapshot_index]; + + if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0) + goto fail; + + if (qcow2_grow_l1_table(bs, sn->l1_size) < 0) + goto fail; + + s->l1_size = sn->l1_size; + l1_size2 = s->l1_size * sizeof(uint64_t); + /* copy the snapshot l1 table to the current l1 table */ + if (bdrv_pread(s->hd, sn->l1_table_offset, + s->l1_table, l1_size2) != l1_size2) + goto fail; + if (bdrv_pwrite(s->hd, s->l1_table_offset, + s->l1_table, l1_size2) != l1_size2) + goto fail; + for(i = 0;i < s->l1_size; i++) { + be64_to_cpus(&s->l1_table[i]); + } + + if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0) + goto fail; + +#ifdef DEBUG_ALLOC + check_refcounts(bs); +#endif + return 0; + fail: + return -EIO; +} + +int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id) +{ + BDRVQcowState *s = bs->opaque; + QCowSnapshot *sn; + int snapshot_index, ret; + + snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id); + if (snapshot_index < 0) + return -ENOENT; + sn = &s->snapshots[snapshot_index]; + + ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1); + if (ret < 0) + return ret; + /* must update the copied flag on the current cluster offsets */ + ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0); + if (ret < 0) + return ret; + qcow2_free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t)); + + qemu_free(sn->id_str); + qemu_free(sn->name); + memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn)); + s->nb_snapshots--; + ret = qcow_write_snapshots(bs); + if (ret < 0) { + /* XXX: restore snapshot if error ? */ + return ret; + } +#ifdef DEBUG_ALLOC + check_refcounts(bs); +#endif + return 0; +} + +int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) +{ + BDRVQcowState *s = bs->opaque; + QEMUSnapshotInfo *sn_tab, *sn_info; + QCowSnapshot *sn; + int i; + + if (!s->nb_snapshots) { + *psn_tab = NULL; + return s->nb_snapshots; + } + + sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo)); + for(i = 0; i < s->nb_snapshots; i++) { + sn_info = sn_tab + i; + sn = s->snapshots + i; + pstrcpy(sn_info->id_str, sizeof(sn_info->id_str), + sn->id_str); + pstrcpy(sn_info->name, sizeof(sn_info->name), + sn->name); + sn_info->vm_state_size = sn->vm_state_size; + sn_info->date_sec = sn->date_sec; + sn_info->date_nsec = sn->date_nsec; + sn_info->vm_clock_nsec = sn->vm_clock_nsec; + } + *psn_tab = sn_tab; + return s->nb_snapshots; +} + diff --git a/block/qcow2.c b/block/qcow2.c index c2be42ed3..9acbddf94 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -26,6 +26,7 @@ #include "module.h" #include <zlib.h> #include "aes.h" +#include "block/qcow2.h" /* Differences with QCOW: @@ -47,40 +48,6 @@ //#define DEBUG_ALLOC2 //#define DEBUG_EXT -#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb) -#define QCOW_VERSION 2 - -#define QCOW_CRYPT_NONE 0 -#define QCOW_CRYPT_AES 1 - -#define QCOW_MAX_CRYPT_CLUSTERS 32 - -/* indicate that the refcount of the referenced cluster is exactly one. */ -#define QCOW_OFLAG_COPIED (1LL << 63) -/* indicate that the cluster is compressed (they never have the copied flag) */ -#define QCOW_OFLAG_COMPRESSED (1LL << 62) - -#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */ - -#define MIN_CLUSTER_BITS 9 -#define MAX_CLUSTER_BITS 16 - -typedef struct QCowHeader { - uint32_t magic; - uint32_t version; - uint64_t backing_file_offset; - uint32_t backing_file_size; - uint32_t cluster_bits; - uint64_t size; /* in bytes */ - uint32_t crypt_method; - uint32_t l1_size; /* XXX: save number of clusters instead ? */ - uint64_t l1_table_offset; - uint64_t refcount_table_offset; - uint32_t refcount_table_clusters; - uint32_t nb_snapshots; - uint64_t snapshots_offset; -} QCowHeader; - typedef struct { uint32_t magic; @@ -90,97 +57,6 @@ typedef struct { #define QCOW_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA -typedef struct __attribute__((packed)) QCowSnapshotHeader { - /* header is 8 byte aligned */ - uint64_t l1_table_offset; - - uint32_t l1_size; - uint16_t id_str_size; - uint16_t name_size; - - uint32_t date_sec; - uint32_t date_nsec; - - uint64_t vm_clock_nsec; - - uint32_t vm_state_size; - uint32_t extra_data_size; /* for extension */ - /* extra data follows */ - /* id_str follows */ - /* name follows */ -} QCowSnapshotHeader; - -#define L2_CACHE_SIZE 16 - -typedef struct QCowSnapshot { - uint64_t l1_table_offset; - uint32_t l1_size; - char *id_str; - char *name; - uint32_t vm_state_size; - uint32_t date_sec; - uint32_t date_nsec; - uint64_t vm_clock_nsec; -} QCowSnapshot; - -typedef struct BDRVQcowState { - BlockDriverState *hd; - int cluster_bits; - int cluster_size; - int cluster_sectors; - int l2_bits; - int l2_size; - int l1_size; - int l1_vm_state_index; - int csize_shift; - int csize_mask; - uint64_t cluster_offset_mask; - uint64_t l1_table_offset; - uint64_t *l1_table; - uint64_t *l2_cache; - uint64_t l2_cache_offsets[L2_CACHE_SIZE]; - uint32_t l2_cache_counts[L2_CACHE_SIZE]; - uint8_t *cluster_cache; - uint8_t *cluster_data; - uint64_t cluster_cache_offset; - - uint64_t *refcount_table; - uint64_t refcount_table_offset; - uint32_t refcount_table_size; - uint64_t refcount_block_cache_offset; - uint16_t *refcount_block_cache; - int64_t free_cluster_index; - int64_t free_byte_offset; - - uint32_t crypt_method; /* current crypt method, 0 if no key yet */ - uint32_t crypt_method_header; - AES_KEY aes_encrypt_key; - AES_KEY aes_decrypt_key; - uint64_t snapshots_offset; - int snapshots_size; - int nb_snapshots; - QCowSnapshot *snapshots; -} BDRVQcowState; - -static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset); -static int qcow_read(BlockDriverState *bs, int64_t sector_num, - uint8_t *buf, int nb_sectors); -static int qcow_read_snapshots(BlockDriverState *bs); -static void qcow_free_snapshots(BlockDriverState *bs); -static int refcount_init(BlockDriverState *bs); -static void refcount_close(BlockDriverState *bs); -static int get_refcount(BlockDriverState *bs, int64_t cluster_index); -static int update_cluster_refcount(BlockDriverState *bs, - int64_t cluster_index, - int addend); -static int update_refcount(BlockDriverState *bs, - int64_t offset, int64_t length, - int addend); -static int64_t alloc_clusters(BlockDriverState *bs, int64_t size); -static int64_t alloc_bytes(BlockDriverState *bs, int size); -static void free_clusters(BlockDriverState *bs, - int64_t offset, int64_t size); -static int check_refcounts(BlockDriverState *bs); static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) { @@ -351,7 +227,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) + 512); s->cluster_cache_offset = -1; - if (refcount_init(bs) < 0) + if (qcow2_refcount_init(bs) < 0) goto fail; /* read qcow2 extensions */ @@ -371,7 +247,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) goto fail; bs->backing_file[len] = '\0'; } - if (qcow_read_snapshots(bs) < 0) + if (qcow2_read_snapshots(bs) < 0) goto fail; #ifdef DEBUG_ALLOC @@ -380,8 +256,8 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) return 0; fail: - qcow_free_snapshots(bs); - refcount_close(bs); + qcow2_free_snapshots(bs); + qcow2_refcount_close(bs); qemu_free(s->l1_table); qemu_free(s->l2_cache); qemu_free(s->cluster_cache); @@ -432,748 +308,20 @@ static int qcow_set_key(BlockDriverState *bs, const char *key) return 0; } -/* The crypt function is compatible with the linux cryptoloop - algorithm for < 4 GB images. NOTE: out_buf == in_buf is - supported */ -static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num, - uint8_t *out_buf, const uint8_t *in_buf, - int nb_sectors, int enc, - const AES_KEY *key) -{ - union { - uint64_t ll[2]; - uint8_t b[16]; - } ivec; - int i; - - for(i = 0; i < nb_sectors; i++) { - ivec.ll[0] = cpu_to_le64(sector_num); - ivec.ll[1] = 0; - AES_cbc_encrypt(in_buf, out_buf, 512, key, - ivec.b, enc); - sector_num++; - in_buf += 512; - out_buf += 512; - } -} - -static int copy_sectors(BlockDriverState *bs, uint64_t start_sect, - uint64_t cluster_offset, int n_start, int n_end) -{ - BDRVQcowState *s = bs->opaque; - int n, ret; - - n = n_end - n_start; - if (n <= 0) - return 0; - ret = qcow_read(bs, start_sect + n_start, s->cluster_data, n); - if (ret < 0) - return ret; - if (s->crypt_method) { - encrypt_sectors(s, start_sect + n_start, - s->cluster_data, - s->cluster_data, n, 1, - &s->aes_encrypt_key); - } - ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start, - s->cluster_data, n); - if (ret < 0) - return ret; - return 0; -} - -static void l2_cache_reset(BlockDriverState *bs) -{ - BDRVQcowState *s = bs->opaque; - - memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t)); - memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t)); - memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t)); -} - -static inline int l2_cache_new_entry(BlockDriverState *bs) -{ - BDRVQcowState *s = bs->opaque; - uint32_t min_count; - int min_index, i; - - /* find a new entry in the least used one */ - min_index = 0; - min_count = 0xffffffff; - for(i = 0; i < L2_CACHE_SIZE; i++) { - if (s->l2_cache_counts[i] < min_count) { - min_count = s->l2_cache_counts[i]; - min_index = i; - } - } - return min_index; -} - -static int64_t align_offset(int64_t offset, int n) -{ - offset = (offset + n - 1) & ~(n - 1); - return offset; -} - -static int 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; - uint8_t data[12]; - - new_l1_size = s->l1_size; - if (min_size <= new_l1_size) - return 0; - while (min_size > new_l1_size) { - new_l1_size = (new_l1_size * 3 + 1) / 2; - } -#ifdef DEBUG_ALLOC2 - printf("grow l1_table from %d to %d\n", s->l1_size, new_l1_size); -#endif - - new_l1_size2 = sizeof(uint64_t) * new_l1_size; - new_l1_table = qemu_mallocz(new_l1_size2); - memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t)); - - /* write new table (align to cluster) */ - new_l1_table_offset = alloc_clusters(bs, new_l1_size2); - - for(i = 0; i < s->l1_size; i++) - new_l1_table[i] = cpu_to_be64(new_l1_table[i]); - ret = bdrv_pwrite(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2); - if (ret != new_l1_size2) - goto fail; - for(i = 0; i < s->l1_size; i++) - new_l1_table[i] = be64_to_cpu(new_l1_table[i]); - - /* 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)) - goto fail; - qemu_free(s->l1_table); - free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t)); - s->l1_table_offset = new_l1_table_offset; - s->l1_table = new_l1_table; - s->l1_size = new_l1_size; - return 0; - fail: - qemu_free(s->l1_table); - return -EIO; -} - -/* - * seek_l2_table - * - * seek l2_offset in the l2_cache table - * if not found, return NULL, - * if found, - * increments the l2 cache hit count of the entry, - * if counter overflow, divide by two all counters - * return the pointer to the l2 cache entry - * - */ - -static uint64_t *seek_l2_table(BDRVQcowState *s, uint64_t l2_offset) -{ - int i, j; - - for(i = 0; i < L2_CACHE_SIZE; i++) { - if (l2_offset == s->l2_cache_offsets[i]) { - /* increment the hit count */ - if (++s->l2_cache_counts[i] == 0xffffffff) { - for(j = 0; j < L2_CACHE_SIZE; j++) { - s->l2_cache_counts[j] >>= 1; - } - } - return s->l2_cache + (i << s->l2_bits); - } - } - return NULL; -} - -/* - * l2_load - * - * Loads a L2 table into memory. If the table is in the cache, the cache - * is used; otherwise the L2 table is loaded from the image file. - * - * Returns a pointer to the L2 table on success, or NULL if the read from - * the image file failed. - */ - -static uint64_t *l2_load(BlockDriverState *bs, uint64_t l2_offset) -{ - BDRVQcowState *s = bs->opaque; - int min_index; - uint64_t *l2_table; - - /* seek if the table for the given offset is in the cache */ - - l2_table = seek_l2_table(s, l2_offset); - if (l2_table != NULL) - return l2_table; - - /* not found: load a new entry in the least used one */ - - min_index = l2_cache_new_entry(bs); - l2_table = s->l2_cache + (min_index << s->l2_bits); - if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != - s->l2_size * sizeof(uint64_t)) - return NULL; - s->l2_cache_offsets[min_index] = l2_offset; - s->l2_cache_counts[min_index] = 1; - - return l2_table; -} - -/* - * l2_allocate - * - * Allocate a new l2 entry in the file. If l1_index points to an already - * used entry in the L2 table (i.e. we are doing a copy on write for the L2 - * table) copy the contents of the old L2 table into the newly allocated one. - * Otherwise the new table is initialized with zeros. - * - */ - -static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index) -{ - BDRVQcowState *s = bs->opaque; - int min_index; - uint64_t old_l2_offset, tmp; - uint64_t *l2_table, l2_offset; - - old_l2_offset = s->l1_table[l1_index]; - - /* allocate a new l2 entry */ - - l2_offset = alloc_clusters(bs, s->l2_size * sizeof(uint64_t)); - - /* update the L1 entry */ - - s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED; - - tmp = cpu_to_be64(l2_offset | QCOW_OFLAG_COPIED); - if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), - &tmp, sizeof(tmp)) != sizeof(tmp)) - return NULL; - - /* allocate a new entry in the l2 cache */ - - min_index = l2_cache_new_entry(bs); - l2_table = s->l2_cache + (min_index << s->l2_bits); - - if (old_l2_offset == 0) { - /* if there was no old l2 table, clear the new table */ - memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); - } else { - /* if there was an old l2 table, read it from the disk */ - if (bdrv_pread(s->hd, old_l2_offset, - l2_table, s->l2_size * sizeof(uint64_t)) != - s->l2_size * sizeof(uint64_t)) - return NULL; - } - /* write the l2 table to the file */ - if (bdrv_pwrite(s->hd, l2_offset, - l2_table, s->l2_size * sizeof(uint64_t)) != - s->l2_size * sizeof(uint64_t)) - return NULL; - - /* update the l2 cache entry */ - - s->l2_cache_offsets[min_index] = l2_offset; - s->l2_cache_counts[min_index] = 1; - - return l2_table; -} - -static int size_to_clusters(BDRVQcowState *s, int64_t size) -{ - return (size + (s->cluster_size - 1)) >> s->cluster_bits; -} - -static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size, - uint64_t *l2_table, uint64_t start, uint64_t mask) -{ - int i; - uint64_t offset = be64_to_cpu(l2_table[0]) & ~mask; - - if (!offset) - return 0; - - for (i = start; i < start + nb_clusters; i++) - if (offset + i * cluster_size != (be64_to_cpu(l2_table[i]) & ~mask)) - break; - - return (i - start); -} - -static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table) -{ - int i = 0; - - while(nb_clusters-- && l2_table[i] == 0) - i++; - - return i; -} - -/* - * get_cluster_offset - * - * For a given offset of the disk image, return cluster offset in - * qcow2 file. - * - * on entry, *num is the number of contiguous clusters we'd like to - * access following offset. - * - * on exit, *num is the number of contiguous clusters we can read. - * - * Return 1, if the offset is found - * Return 0, otherwise. - * - */ - -static uint64_t get_cluster_offset(BlockDriverState *bs, - uint64_t offset, int *num) -{ - BDRVQcowState *s = bs->opaque; - int l1_index, l2_index; - uint64_t l2_offset, *l2_table, cluster_offset; - int l1_bits, c; - int index_in_cluster, nb_available, nb_needed, nb_clusters; - - index_in_cluster = (offset >> 9) & (s->cluster_sectors - 1); - nb_needed = *num + index_in_cluster; - - l1_bits = s->l2_bits + s->cluster_bits; - - /* compute how many bytes there are between the offset and - * the end of the l1 entry - */ - - nb_available = (1 << l1_bits) - (offset & ((1 << l1_bits) - 1)); - - /* compute the number of available sectors */ - - nb_available = (nb_available >> 9) + index_in_cluster; - - if (nb_needed > nb_available) { - nb_needed = nb_available; - } - - cluster_offset = 0; - - /* seek the the l2 offset in the l1 table */ - - l1_index = offset >> l1_bits; - if (l1_index >= s->l1_size) - goto out; - - l2_offset = s->l1_table[l1_index]; - - /* seek the l2 table of the given l2 offset */ - - if (!l2_offset) - goto out; - - /* load the l2 table in memory */ - - l2_offset &= ~QCOW_OFLAG_COPIED; - l2_table = l2_load(bs, l2_offset); - if (l2_table == NULL) - return 0; - - /* find the cluster offset for the given disk offset */ - - l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); - cluster_offset = be64_to_cpu(l2_table[l2_index]); - nb_clusters = size_to_clusters(s, nb_needed << 9); - - if (!cluster_offset) { - /* how many empty clusters ? */ - c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]); - } else { - /* how many allocated clusters ? */ - c = count_contiguous_clusters(nb_clusters, s->cluster_size, - &l2_table[l2_index], 0, QCOW_OFLAG_COPIED); - } - - nb_available = (c * s->cluster_sectors); -out: - if (nb_available > nb_needed) - nb_available = nb_needed; - - *num = nb_available - index_in_cluster; - - return cluster_offset & ~QCOW_OFLAG_COPIED; -} - -/* - * free_any_clusters - * - * free clusters according to its type: compressed or not - * - */ - -static void free_any_clusters(BlockDriverState *bs, - uint64_t cluster_offset, int nb_clusters) -{ - BDRVQcowState *s = bs->opaque; - - /* free the cluster */ - - if (cluster_offset & QCOW_OFLAG_COMPRESSED) { - int nb_csectors; - nb_csectors = ((cluster_offset >> s->csize_shift) & - s->csize_mask) + 1; - free_clusters(bs, (cluster_offset & s->cluster_offset_mask) & ~511, - nb_csectors * 512); - return; - } - - free_clusters(bs, cluster_offset, nb_clusters << s->cluster_bits); - - return; -} - -/* - * get_cluster_table - * - * for a given disk offset, load (and allocate if needed) - * the l2 table. - * - * the l2 table offset in the qcow2 file and the cluster index - * in the l2 table are given to the caller. - * - */ - -static int get_cluster_table(BlockDriverState *bs, uint64_t offset, - uint64_t **new_l2_table, - uint64_t *new_l2_offset, - int *new_l2_index) -{ - BDRVQcowState *s = bs->opaque; - int l1_index, l2_index, ret; - uint64_t l2_offset, *l2_table; - - /* seek the the l2 offset in the l1 table */ - - l1_index = offset >> (s->l2_bits + s->cluster_bits); - if (l1_index >= s->l1_size) { - ret = grow_l1_table(bs, l1_index + 1); - if (ret < 0) - return 0; - } - l2_offset = s->l1_table[l1_index]; - - /* seek the l2 table of the given l2 offset */ - - if (l2_offset & QCOW_OFLAG_COPIED) { - /* load the l2 table in memory */ - l2_offset &= ~QCOW_OFLAG_COPIED; - l2_table = l2_load(bs, l2_offset); - if (l2_table == NULL) - return 0; - } else { - if (l2_offset) - free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t)); - l2_table = l2_allocate(bs, l1_index); - if (l2_table == NULL) - return 0; - l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED; - } - - /* find the cluster offset for the given disk offset */ - - l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); - - *new_l2_table = l2_table; - *new_l2_offset = l2_offset; - *new_l2_index = l2_index; - - return 1; -} - -/* - * alloc_compressed_cluster_offset - * - * For a given offset of the disk image, return cluster offset in - * qcow2 file. - * - * If the offset is not found, allocate a new compressed cluster. - * - * Return the cluster offset if successful, - * Return 0, otherwise. - * - */ - -static uint64_t alloc_compressed_cluster_offset(BlockDriverState *bs, - uint64_t offset, - int compressed_size) -{ - BDRVQcowState *s = bs->opaque; - int l2_index, ret; - uint64_t l2_offset, *l2_table, cluster_offset; - int nb_csectors; - - ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index); - if (ret == 0) - return 0; - - cluster_offset = be64_to_cpu(l2_table[l2_index]); - if (cluster_offset & QCOW_OFLAG_COPIED) - return cluster_offset & ~QCOW_OFLAG_COPIED; - - if (cluster_offset) - free_any_clusters(bs, cluster_offset, 1); - - cluster_offset = alloc_bytes(bs, compressed_size); - nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - - (cluster_offset >> 9); - - cluster_offset |= QCOW_OFLAG_COMPRESSED | - ((uint64_t)nb_csectors << s->csize_shift); - - /* update L2 table */ - - /* compressed clusters never have the copied flag */ - - l2_table[l2_index] = cpu_to_be64(cluster_offset); - if (bdrv_pwrite(s->hd, - l2_offset + l2_index * sizeof(uint64_t), - l2_table + l2_index, - sizeof(uint64_t)) != sizeof(uint64_t)) - return 0; - - return cluster_offset; -} - -typedef struct QCowL2Meta -{ - uint64_t offset; - int n_start; - int nb_available; - int nb_clusters; -} QCowL2Meta; - -static int alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset, - QCowL2Meta *m) -{ - BDRVQcowState *s = bs->opaque; - int i, j = 0, l2_index, ret; - uint64_t *old_cluster, start_sect, l2_offset, *l2_table; - - if (m->nb_clusters == 0) - return 0; - - old_cluster = qemu_malloc(m->nb_clusters * sizeof(uint64_t)); - - /* copy content of unmodified sectors */ - start_sect = (m->offset & ~(s->cluster_size - 1)) >> 9; - if (m->n_start) { - ret = copy_sectors(bs, start_sect, cluster_offset, 0, m->n_start); - if (ret < 0) - goto err; - } - - if (m->nb_available & (s->cluster_sectors - 1)) { - uint64_t end = m->nb_available & ~(uint64_t)(s->cluster_sectors - 1); - ret = copy_sectors(bs, start_sect + end, cluster_offset + (end << 9), - m->nb_available - end, s->cluster_sectors); - if (ret < 0) - goto err; - } - - ret = -EIO; - /* update L2 table */ - if (!get_cluster_table(bs, m->offset, &l2_table, &l2_offset, &l2_index)) - goto err; - - for (i = 0; i < m->nb_clusters; i++) { - /* if two concurrent writes happen to the same unallocated cluster - * each write allocates separate cluster and writes data concurrently. - * The first one to complete updates l2 table with pointer to its - * cluster the second one has to do RMW (which is done above by - * copy_sectors()), update l2 table with its cluster pointer and free - * old cluster. This is what this loop does */ - if(l2_table[l2_index + i] != 0) - old_cluster[j++] = l2_table[l2_index + i]; - - l2_table[l2_index + i] = cpu_to_be64((cluster_offset + - (i << s->cluster_bits)) | QCOW_OFLAG_COPIED); - } - - if (bdrv_pwrite(s->hd, l2_offset + l2_index * sizeof(uint64_t), - l2_table + l2_index, m->nb_clusters * sizeof(uint64_t)) != - m->nb_clusters * sizeof(uint64_t)) - goto err; - - for (i = 0; i < j; i++) - free_any_clusters(bs, be64_to_cpu(old_cluster[i]) & ~QCOW_OFLAG_COPIED, - 1); - - ret = 0; -err: - qemu_free(old_cluster); - return ret; - } - -/* - * alloc_cluster_offset - * - * 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. - * - */ - -static uint64_t 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; - int nb_clusters, i = 0; - - ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index); - if (ret == 0) - return 0; - - nb_clusters = size_to_clusters(s, n_end << 9); - - nb_clusters = MIN(nb_clusters, s->l2_size - l2_index); - - cluster_offset = be64_to_cpu(l2_table[l2_index]); - - /* We keep all QCOW_OFLAG_COPIED clusters */ - - if (cluster_offset & QCOW_OFLAG_COPIED) { - nb_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size, - &l2_table[l2_index], 0, 0); - - cluster_offset &= ~QCOW_OFLAG_COPIED; - m->nb_clusters = 0; - - goto out; - } - - /* for the moment, multiple compressed clusters are not managed */ - - if (cluster_offset & QCOW_OFLAG_COMPRESSED) - nb_clusters = 1; - - /* how many available clusters ? */ - - 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])) - break; - - i += count_contiguous_free_clusters(nb_clusters - i, - &l2_table[l2_index + i]); - - cluster_offset = be64_to_cpu(l2_table[l2_index + i]); - - if ((cluster_offset & QCOW_OFLAG_COPIED) || - (cluster_offset & QCOW_OFLAG_COMPRESSED)) - break; - } - nb_clusters = i; - - /* allocate a new cluster */ - - cluster_offset = alloc_clusters(bs, nb_clusters * s->cluster_size); - - /* save info needed for meta data update */ - m->offset = offset; - m->n_start = n_start; - m->nb_clusters = nb_clusters; - -out: - m->nb_available = MIN(nb_clusters << (s->cluster_bits - 9), n_end); - - *num = m->nb_available - n_start; - - return cluster_offset; -} - static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { uint64_t cluster_offset; *pnum = nb_sectors; - cluster_offset = get_cluster_offset(bs, sector_num << 9, pnum); + cluster_offset = qcow2_get_cluster_offset(bs, sector_num << 9, pnum); return (cluster_offset != 0); } -static int decompress_buffer(uint8_t *out_buf, int out_buf_size, - const uint8_t *buf, int buf_size) -{ - z_stream strm1, *strm = &strm1; - int ret, out_len; - - memset(strm, 0, sizeof(*strm)); - - strm->next_in = (uint8_t *)buf; - strm->avail_in = buf_size; - strm->next_out = out_buf; - strm->avail_out = out_buf_size; - - ret = inflateInit2(strm, -12); - if (ret != Z_OK) - return -1; - ret = inflate(strm, Z_FINISH); - out_len = strm->next_out - out_buf; - if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) || - out_len != out_buf_size) { - inflateEnd(strm); - return -1; - } - inflateEnd(strm); - return 0; -} - -static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) -{ - int ret, csize, nb_csectors, sector_offset; - uint64_t coffset; - - coffset = cluster_offset & s->cluster_offset_mask; - if (s->cluster_cache_offset != coffset) { - nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1; - sector_offset = coffset & 511; - csize = nb_csectors * 512 - sector_offset; - ret = bdrv_read(s->hd, coffset >> 9, s->cluster_data, nb_csectors); - if (ret < 0) { - return -1; - } - if (decompress_buffer(s->cluster_cache, s->cluster_size, - s->cluster_data + sector_offset, csize) < 0) { - return -1; - } - s->cluster_cache_offset = coffset; - } - return 0; -} - /* handle reading after the end of the backing file */ -static int backing_read1(BlockDriverState *bs, - int64_t sector_num, uint8_t *buf, int nb_sectors) +int qcow2_backing_read1(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors) { int n1; if ((sector_num + nb_sectors) <= bs->total_sectors) @@ -1186,49 +334,6 @@ static int backing_read1(BlockDriverState *bs, return n1; } -static int qcow_read(BlockDriverState *bs, int64_t sector_num, - uint8_t *buf, int nb_sectors) -{ - BDRVQcowState *s = bs->opaque; - int ret, index_in_cluster, n, n1; - uint64_t cluster_offset; - - while (nb_sectors > 0) { - n = nb_sectors; - cluster_offset = get_cluster_offset(bs, sector_num << 9, &n); - index_in_cluster = sector_num & (s->cluster_sectors - 1); - if (!cluster_offset) { - if (bs->backing_hd) { - /* read from the base image */ - n1 = backing_read1(bs->backing_hd, sector_num, buf, n); - if (n1 > 0) { - ret = bdrv_read(bs->backing_hd, sector_num, buf, n1); - if (ret < 0) - return -1; - } - } else { - memset(buf, 0, 512 * n); - } - } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) { - if (decompress_cluster(s, cluster_offset) < 0) - return -1; - memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n); - } else { - ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512); - if (ret != n * 512) - return -1; - if (s->crypt_method) { - encrypt_sectors(s, sector_num, buf, buf, n, 0, - &s->aes_decrypt_key); - } - } - nb_sectors -= n; - sector_num += n; - buf += n * 512; - } - return 0; -} - typedef struct QCowAIOCB { BlockDriverAIOCB common; int64_t sector_num; @@ -1300,7 +405,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) /* nothing to do */ } else { if (s->crypt_method) { - encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, + qcow2_encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, acb->n, 0, &s->aes_decrypt_key); } @@ -1318,13 +423,14 @@ static void qcow_aio_read_cb(void *opaque, int ret) /* prepare next AIO request */ acb->n = acb->nb_sectors; - acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, &acb->n); + acb->cluster_offset = + qcow2_get_cluster_offset(bs, acb->sector_num << 9, &acb->n); index_in_cluster = acb->sector_num & (s->cluster_sectors - 1); if (!acb->cluster_offset) { if (bs->backing_hd) { /* read from the base image */ - n1 = backing_read1(bs->backing_hd, acb->sector_num, + n1 = qcow2_backing_read1(bs->backing_hd, acb->sector_num, acb->buf, acb->n); if (n1 > 0) { acb->hd_iov.iov_base = (void *)acb->buf; @@ -1349,7 +455,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) } } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) { /* add AIO support for compressed blocks ? */ - if (decompress_cluster(s, acb->cluster_offset) < 0) + if (qcow2_decompress_cluster(s, acb->cluster_offset) < 0) goto done; memcpy(acb->buf, s->cluster_cache + index_in_cluster * 512, 512 * acb->n); @@ -1436,8 +542,8 @@ static void qcow_aio_write_cb(void *opaque, int ret) if (ret < 0) goto done; - if (alloc_cluster_link_l2(bs, acb->cluster_offset, &acb->l2meta) < 0) { - free_any_clusters(bs, acb->cluster_offset, acb->l2meta.nb_clusters); + if (qcow2_alloc_cluster_link_l2(bs, acb->cluster_offset, &acb->l2meta) < 0) { + qcow2_free_any_clusters(bs, acb->cluster_offset, acb->l2meta.nb_clusters); goto done; } @@ -1457,7 +563,7 @@ 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 = alloc_cluster_offset(bs, acb->sector_num << 9, + acb->cluster_offset = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9, index_in_cluster, n_end, &acb->n, &acb->l2meta); if (!acb->cluster_offset || (acb->cluster_offset & 511) != 0) { @@ -1469,7 +575,7 @@ static void qcow_aio_write_cb(void *opaque, int ret) acb->cluster_data = qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); } - encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf, + qcow2_encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf, acb->n, 1, &s->aes_encrypt_key); src_buf = acb->cluster_data; } else { @@ -1518,39 +624,10 @@ static void qcow_close(BlockDriverState *bs) qemu_free(s->l2_cache); qemu_free(s->cluster_cache); qemu_free(s->cluster_data); - refcount_close(bs); + qcow2_refcount_close(bs); bdrv_delete(s->hd); } -/* XXX: use std qcow open function ? */ -typedef struct QCowCreateState { - int cluster_size; - int cluster_bits; - uint16_t *refcount_block; - uint64_t *refcount_table; - int64_t l1_table_offset; - int64_t refcount_table_offset; - int64_t refcount_block_offset; -} QCowCreateState; - -static void create_refcount_update(QCowCreateState *s, - int64_t offset, int64_t size) -{ - int refcount; - int64_t start, last, cluster_offset; - uint16_t *p; - - start = offset & ~(s->cluster_size - 1); - last = (offset + size - 1) & ~(s->cluster_size - 1); - for(cluster_offset = start; cluster_offset <= last; - cluster_offset += s->cluster_size) { - p = &s->refcount_block[cluster_offset >> s->cluster_bits]; - refcount = be16_to_cpu(*p); - refcount++; - *p = cpu_to_be16(refcount); - } -} - static int get_bits_from_size(size_t size) { int res = 0; @@ -1657,10 +734,12 @@ static int qcow_create2(const char *filename, int64_t total_size, s->refcount_block = qemu_mallocz(ref_clusters * s->cluster_size); /* update refcounts */ - create_refcount_update(s, 0, header_size); - create_refcount_update(s, s->l1_table_offset, l1_size * sizeof(uint64_t)); - create_refcount_update(s, s->refcount_table_offset, s->cluster_size); - create_refcount_update(s, s->refcount_block_offset, ref_clusters * s->cluster_size); + qcow2_create_refcount_update(s, 0, header_size); + qcow2_create_refcount_update(s, s->l1_table_offset, + l1_size * sizeof(uint64_t)); + qcow2_create_refcount_update(s, s->refcount_table_offset, s->cluster_size); + qcow2_create_refcount_update(s, s->refcount_block_offset, + ref_clusters * s->cluster_size); /* write all the data */ write(fd, &header, sizeof(header)); @@ -1703,7 +782,7 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options) const char *backing_fmt = NULL; uint64_t sectors = 0; int flags = 0; - size_t cluster_size = 4096; + size_t cluster_size = 65536; /* Read out options */ while (options && options->name) { @@ -1801,8 +880,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, /* could not compress: write normal cluster */ bdrv_write(bs, sector_num, buf, s->cluster_sectors); } else { - cluster_offset = alloc_compressed_cluster_offset(bs, sector_num << 9, - out_len); + cluster_offset = qcow2_alloc_compressed_cluster_offset(bs, + sector_num << 9, out_len); if (!cluster_offset) return -1; cluster_offset &= s->cluster_offset_mask; @@ -1831,1108 +910,10 @@ static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) return 0; } -/*********************************************************/ -/* snapshot support */ - -/* update the refcounts of snapshots and the copied flag */ -static int update_snapshot_refcount(BlockDriverState *bs, - int64_t l1_table_offset, - int l1_size, - int addend) -{ - BDRVQcowState *s = bs->opaque; - uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated; - int64_t old_offset, old_l2_offset; - int l2_size, i, j, l1_modified, l2_modified, nb_csectors, refcount; - - l2_cache_reset(bs); - - l2_table = NULL; - l1_table = NULL; - l1_size2 = l1_size * sizeof(uint64_t); - l1_allocated = 0; - if (l1_table_offset != s->l1_table_offset) { - l1_table = qemu_malloc(l1_size2); - l1_allocated = 1; - if (bdrv_pread(s->hd, l1_table_offset, - l1_table, l1_size2) != l1_size2) - goto fail; - for(i = 0;i < l1_size; i++) - be64_to_cpus(&l1_table[i]); - } else { - assert(l1_size == s->l1_size); - l1_table = s->l1_table; - l1_allocated = 0; - } - - l2_size = s->l2_size * sizeof(uint64_t); - l2_table = qemu_malloc(l2_size); - l1_modified = 0; - for(i = 0; i < l1_size; i++) { - l2_offset = l1_table[i]; - if (l2_offset) { - old_l2_offset = l2_offset; - l2_offset &= ~QCOW_OFLAG_COPIED; - l2_modified = 0; - if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size) - goto fail; - for(j = 0; j < s->l2_size; j++) { - offset = be64_to_cpu(l2_table[j]); - if (offset != 0) { - old_offset = offset; - offset &= ~QCOW_OFLAG_COPIED; - 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); - /* compressed clusters are never modified */ - refcount = 2; - } else { - if (addend != 0) { - refcount = update_cluster_refcount(bs, offset >> s->cluster_bits, addend); - } else { - refcount = get_refcount(bs, offset >> s->cluster_bits); - } - } - - if (refcount == 1) { - offset |= QCOW_OFLAG_COPIED; - } - if (offset != old_offset) { - l2_table[j] = cpu_to_be64(offset); - l2_modified = 1; - } - } - } - if (l2_modified) { - if (bdrv_pwrite(s->hd, - l2_offset, l2_table, l2_size) != l2_size) - goto fail; - } - - if (addend != 0) { - refcount = update_cluster_refcount(bs, l2_offset >> s->cluster_bits, addend); - } else { - refcount = get_refcount(bs, l2_offset >> s->cluster_bits); - } - if (refcount == 1) { - l2_offset |= QCOW_OFLAG_COPIED; - } - if (l2_offset != old_l2_offset) { - l1_table[i] = l2_offset; - l1_modified = 1; - } - } - } - if (l1_modified) { - for(i = 0; i < l1_size; i++) - cpu_to_be64s(&l1_table[i]); - if (bdrv_pwrite(s->hd, l1_table_offset, l1_table, - l1_size2) != l1_size2) - goto fail; - for(i = 0; i < l1_size; i++) - be64_to_cpus(&l1_table[i]); - } - if (l1_allocated) - qemu_free(l1_table); - qemu_free(l2_table); - return 0; - fail: - if (l1_allocated) - qemu_free(l1_table); - qemu_free(l2_table); - return -EIO; -} - -static void qcow_free_snapshots(BlockDriverState *bs) -{ - BDRVQcowState *s = bs->opaque; - int i; - - for(i = 0; i < s->nb_snapshots; i++) { - qemu_free(s->snapshots[i].name); - qemu_free(s->snapshots[i].id_str); - } - qemu_free(s->snapshots); - s->snapshots = NULL; - s->nb_snapshots = 0; -} - -static int qcow_read_snapshots(BlockDriverState *bs) -{ - BDRVQcowState *s = bs->opaque; - QCowSnapshotHeader h; - QCowSnapshot *sn; - int i, id_str_size, name_size; - int64_t offset; - uint32_t extra_data_size; - - if (!s->nb_snapshots) { - s->snapshots = NULL; - s->snapshots_size = 0; - return 0; - } - - offset = s->snapshots_offset; - s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot)); - for(i = 0; i < s->nb_snapshots; i++) { - offset = align_offset(offset, 8); - if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h)) - goto fail; - offset += sizeof(h); - sn = s->snapshots + i; - sn->l1_table_offset = be64_to_cpu(h.l1_table_offset); - sn->l1_size = be32_to_cpu(h.l1_size); - sn->vm_state_size = be32_to_cpu(h.vm_state_size); - sn->date_sec = be32_to_cpu(h.date_sec); - sn->date_nsec = be32_to_cpu(h.date_nsec); - sn->vm_clock_nsec = be64_to_cpu(h.vm_clock_nsec); - extra_data_size = be32_to_cpu(h.extra_data_size); - - id_str_size = be16_to_cpu(h.id_str_size); - name_size = be16_to_cpu(h.name_size); - - offset += extra_data_size; - - sn->id_str = qemu_malloc(id_str_size + 1); - if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size) - goto fail; - offset += id_str_size; - sn->id_str[id_str_size] = '\0'; - - sn->name = qemu_malloc(name_size + 1); - if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size) - goto fail; - offset += name_size; - sn->name[name_size] = '\0'; - } - s->snapshots_size = offset - s->snapshots_offset; - return 0; - fail: - qcow_free_snapshots(bs); - return -1; -} - -/* add at the end of the file a new list of snapshots */ -static int qcow_write_snapshots(BlockDriverState *bs) -{ - BDRVQcowState *s = bs->opaque; - QCowSnapshot *sn; - QCowSnapshotHeader h; - int i, name_size, id_str_size, snapshots_size; - uint64_t data64; - uint32_t data32; - int64_t offset, snapshots_offset; - - /* compute the size of the snapshots */ - offset = 0; - for(i = 0; i < s->nb_snapshots; i++) { - sn = s->snapshots + i; - offset = align_offset(offset, 8); - offset += sizeof(h); - offset += strlen(sn->id_str); - offset += strlen(sn->name); - } - snapshots_size = offset; - - snapshots_offset = alloc_clusters(bs, snapshots_size); - offset = snapshots_offset; - - for(i = 0; i < s->nb_snapshots; i++) { - sn = s->snapshots + i; - memset(&h, 0, sizeof(h)); - h.l1_table_offset = cpu_to_be64(sn->l1_table_offset); - h.l1_size = cpu_to_be32(sn->l1_size); - h.vm_state_size = cpu_to_be32(sn->vm_state_size); - h.date_sec = cpu_to_be32(sn->date_sec); - h.date_nsec = cpu_to_be32(sn->date_nsec); - h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec); - - id_str_size = strlen(sn->id_str); - name_size = strlen(sn->name); - h.id_str_size = cpu_to_be16(id_str_size); - h.name_size = cpu_to_be16(name_size); - offset = align_offset(offset, 8); - if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h)) - goto fail; - offset += sizeof(h); - if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size) - goto fail; - offset += id_str_size; - if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size) - goto fail; - offset += name_size; - } - - /* update the various header fields */ - data64 = cpu_to_be64(snapshots_offset); - if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset), - &data64, sizeof(data64)) != sizeof(data64)) - goto fail; - data32 = cpu_to_be32(s->nb_snapshots); - if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots), - &data32, sizeof(data32)) != sizeof(data32)) - goto fail; - - /* free the old snapshot table */ - free_clusters(bs, s->snapshots_offset, s->snapshots_size); - s->snapshots_offset = snapshots_offset; - s->snapshots_size = snapshots_size; - return 0; - fail: - return -1; -} - -static void find_new_snapshot_id(BlockDriverState *bs, - char *id_str, int id_str_size) -{ - BDRVQcowState *s = bs->opaque; - QCowSnapshot *sn; - int i, id, id_max = 0; - - for(i = 0; i < s->nb_snapshots; i++) { - sn = s->snapshots + i; - id = strtoul(sn->id_str, NULL, 10); - if (id > id_max) - id_max = id; - } - snprintf(id_str, id_str_size, "%d", id_max + 1); -} - -static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str) -{ - BDRVQcowState *s = bs->opaque; - int i; - - for(i = 0; i < s->nb_snapshots; i++) { - if (!strcmp(s->snapshots[i].id_str, id_str)) - return i; - } - return -1; -} - -static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name) -{ - BDRVQcowState *s = bs->opaque; - int i, ret; - - ret = find_snapshot_by_id(bs, name); - if (ret >= 0) - return ret; - for(i = 0; i < s->nb_snapshots; i++) { - if (!strcmp(s->snapshots[i].name, name)) - return i; - } - return -1; -} - -/* if no id is provided, a new one is constructed */ -static int qcow_snapshot_create(BlockDriverState *bs, - QEMUSnapshotInfo *sn_info) -{ - BDRVQcowState *s = bs->opaque; - QCowSnapshot *snapshots1, sn1, *sn = &sn1; - int i, ret; - uint64_t *l1_table = NULL; - - memset(sn, 0, sizeof(*sn)); - - if (sn_info->id_str[0] == '\0') { - /* compute a new id */ - find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str)); - } - - /* check that the ID is unique */ - if (find_snapshot_by_id(bs, sn_info->id_str) >= 0) - return -ENOENT; - - sn->id_str = qemu_strdup(sn_info->id_str); - if (!sn->id_str) - goto fail; - sn->name = qemu_strdup(sn_info->name); - if (!sn->name) - goto fail; - sn->vm_state_size = sn_info->vm_state_size; - sn->date_sec = sn_info->date_sec; - sn->date_nsec = sn_info->date_nsec; - sn->vm_clock_nsec = sn_info->vm_clock_nsec; - - ret = update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1); - if (ret < 0) - goto fail; - - /* create the L1 table of the snapshot */ - sn->l1_table_offset = alloc_clusters(bs, s->l1_size * sizeof(uint64_t)); - sn->l1_size = s->l1_size; - - l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t)); - for(i = 0; i < s->l1_size; i++) { - l1_table[i] = cpu_to_be64(s->l1_table[i]); - } - if (bdrv_pwrite(s->hd, sn->l1_table_offset, - l1_table, s->l1_size * sizeof(uint64_t)) != - (s->l1_size * sizeof(uint64_t))) - goto fail; - qemu_free(l1_table); - l1_table = NULL; - - snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot)); - if (s->snapshots) { - memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot)); - qemu_free(s->snapshots); - } - s->snapshots = snapshots1; - s->snapshots[s->nb_snapshots++] = *sn; - - if (qcow_write_snapshots(bs) < 0) - goto fail; -#ifdef DEBUG_ALLOC - check_refcounts(bs); -#endif - return 0; - fail: - qemu_free(sn->name); - qemu_free(l1_table); - return -1; -} - -/* copy the snapshot 'snapshot_name' into the current disk image */ -static int qcow_snapshot_goto(BlockDriverState *bs, - const char *snapshot_id) -{ - BDRVQcowState *s = bs->opaque; - QCowSnapshot *sn; - int i, snapshot_index, l1_size2; - - snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id); - if (snapshot_index < 0) - return -ENOENT; - sn = &s->snapshots[snapshot_index]; - - if (update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0) - goto fail; - - if (grow_l1_table(bs, sn->l1_size) < 0) - goto fail; - - s->l1_size = sn->l1_size; - l1_size2 = s->l1_size * sizeof(uint64_t); - /* copy the snapshot l1 table to the current l1 table */ - if (bdrv_pread(s->hd, sn->l1_table_offset, - s->l1_table, l1_size2) != l1_size2) - goto fail; - if (bdrv_pwrite(s->hd, s->l1_table_offset, - s->l1_table, l1_size2) != l1_size2) - goto fail; - for(i = 0;i < s->l1_size; i++) { - be64_to_cpus(&s->l1_table[i]); - } - - if (update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0) - goto fail; - -#ifdef DEBUG_ALLOC - check_refcounts(bs); -#endif - return 0; - fail: - return -EIO; -} - -static int qcow_snapshot_delete(BlockDriverState *bs, const char *snapshot_id) -{ - BDRVQcowState *s = bs->opaque; - QCowSnapshot *sn; - int snapshot_index, ret; - - snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id); - if (snapshot_index < 0) - return -ENOENT; - sn = &s->snapshots[snapshot_index]; - - ret = update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1); - if (ret < 0) - return ret; - /* must update the copied flag on the current cluster offsets */ - ret = update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0); - if (ret < 0) - return ret; - free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t)); - - qemu_free(sn->id_str); - qemu_free(sn->name); - memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn)); - s->nb_snapshots--; - ret = qcow_write_snapshots(bs); - if (ret < 0) { - /* XXX: restore snapshot if error ? */ - return ret; - } -#ifdef DEBUG_ALLOC - check_refcounts(bs); -#endif - return 0; -} - -static int qcow_snapshot_list(BlockDriverState *bs, - QEMUSnapshotInfo **psn_tab) -{ - BDRVQcowState *s = bs->opaque; - QEMUSnapshotInfo *sn_tab, *sn_info; - QCowSnapshot *sn; - int i; - - if (!s->nb_snapshots) { - *psn_tab = NULL; - return s->nb_snapshots; - } - - sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo)); - for(i = 0; i < s->nb_snapshots; i++) { - sn_info = sn_tab + i; - sn = s->snapshots + i; - pstrcpy(sn_info->id_str, sizeof(sn_info->id_str), - sn->id_str); - pstrcpy(sn_info->name, sizeof(sn_info->name), - sn->name); - sn_info->vm_state_size = sn->vm_state_size; - sn_info->date_sec = sn->date_sec; - sn_info->date_nsec = sn->date_nsec; - sn_info->vm_clock_nsec = sn->vm_clock_nsec; - } - *psn_tab = sn_tab; - return s->nb_snapshots; -} - -/*********************************************************/ -/* refcount handling */ - -static int refcount_init(BlockDriverState *bs) -{ - BDRVQcowState *s = bs->opaque; - int ret, refcount_table_size2, i; - - s->refcount_block_cache = qemu_malloc(s->cluster_size); - refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t); - s->refcount_table = qemu_malloc(refcount_table_size2); - if (s->refcount_table_size > 0) { - ret = bdrv_pread(s->hd, s->refcount_table_offset, - s->refcount_table, refcount_table_size2); - if (ret != refcount_table_size2) - goto fail; - for(i = 0; i < s->refcount_table_size; i++) - be64_to_cpus(&s->refcount_table[i]); - } - return 0; - fail: - return -ENOMEM; -} - -static void refcount_close(BlockDriverState *bs) -{ - BDRVQcowState *s = bs->opaque; - qemu_free(s->refcount_block_cache); - qemu_free(s->refcount_table); -} - - -static int load_refcount_block(BlockDriverState *bs, - int64_t refcount_block_offset) -{ - BDRVQcowState *s = bs->opaque; - int ret; - ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache, - s->cluster_size); - if (ret != s->cluster_size) - return -EIO; - s->refcount_block_cache_offset = refcount_block_offset; - return 0; -} - -static int get_refcount(BlockDriverState *bs, int64_t cluster_index) -{ - BDRVQcowState *s = bs->opaque; - int refcount_table_index, block_index; - int64_t refcount_block_offset; - - refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); - if (refcount_table_index >= s->refcount_table_size) - return 0; - refcount_block_offset = s->refcount_table[refcount_table_index]; - if (!refcount_block_offset) - return 0; - if (refcount_block_offset != s->refcount_block_cache_offset) { - /* better than nothing: return allocated if read error */ - if (load_refcount_block(bs, refcount_block_offset) < 0) - return 1; - } - block_index = cluster_index & - ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1); - return be16_to_cpu(s->refcount_block_cache[block_index]); -} - -/* return < 0 if error */ -static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size) -{ - BDRVQcowState *s = bs->opaque; - int i, nb_clusters; - - nb_clusters = size_to_clusters(s, size); -retry: - for(i = 0; i < nb_clusters; i++) { - int64_t i = s->free_cluster_index++; - if (get_refcount(bs, i) != 0) - goto retry; - } -#ifdef DEBUG_ALLOC2 - printf("alloc_clusters: size=%lld -> %lld\n", - size, - (s->free_cluster_index - nb_clusters) << s->cluster_bits); -#endif - return (s->free_cluster_index - nb_clusters) << s->cluster_bits; -} - -static int64_t alloc_clusters(BlockDriverState *bs, int64_t size) -{ - int64_t offset; - - offset = alloc_clusters_noref(bs, size); - update_refcount(bs, offset, size, 1); - return offset; -} - -/* only used to allocate compressed sectors. We try to allocate - contiguous sectors. size must be <= cluster_size */ -static int64_t alloc_bytes(BlockDriverState *bs, int size) -{ - BDRVQcowState *s = bs->opaque; - int64_t offset, cluster_offset; - int free_in_cluster; - - assert(size > 0 && size <= s->cluster_size); - if (s->free_byte_offset == 0) { - s->free_byte_offset = alloc_clusters(bs, s->cluster_size); - } - redo: - free_in_cluster = s->cluster_size - - (s->free_byte_offset & (s->cluster_size - 1)); - if (size <= free_in_cluster) { - /* enough space in current cluster */ - offset = s->free_byte_offset; - s->free_byte_offset += size; - free_in_cluster -= size; - if (free_in_cluster == 0) - s->free_byte_offset = 0; - if ((offset & (s->cluster_size - 1)) != 0) - update_cluster_refcount(bs, offset >> s->cluster_bits, 1); - } else { - offset = alloc_clusters(bs, s->cluster_size); - cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1); - if ((cluster_offset + s->cluster_size) == offset) { - /* we are lucky: contiguous data */ - offset = s->free_byte_offset; - update_cluster_refcount(bs, offset >> s->cluster_bits, 1); - s->free_byte_offset += size; - } else { - s->free_byte_offset = offset; - goto redo; - } - } - return offset; -} - -static void free_clusters(BlockDriverState *bs, - int64_t offset, int64_t size) -{ - update_refcount(bs, offset, size, -1); -} - -static int grow_refcount_table(BlockDriverState *bs, int min_size) -{ - BDRVQcowState *s = bs->opaque; - int new_table_size, new_table_size2, refcount_table_clusters, i, ret; - uint64_t *new_table; - int64_t table_offset; - uint8_t data[12]; - int old_table_size; - int64_t old_table_offset; - - if (min_size <= s->refcount_table_size) - return 0; - /* compute new table size */ - refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3); - for(;;) { - if (refcount_table_clusters == 0) { - refcount_table_clusters = 1; - } else { - refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2; - } - new_table_size = refcount_table_clusters << (s->cluster_bits - 3); - if (min_size <= new_table_size) - break; - } -#ifdef DEBUG_ALLOC2 - printf("grow_refcount_table from %d to %d\n", - s->refcount_table_size, - new_table_size); -#endif - new_table_size2 = new_table_size * sizeof(uint64_t); - new_table = qemu_mallocz(new_table_size2); - memcpy(new_table, s->refcount_table, - s->refcount_table_size * sizeof(uint64_t)); - for(i = 0; i < s->refcount_table_size; i++) - cpu_to_be64s(&new_table[i]); - /* Note: we cannot update the refcount now to avoid recursion */ - table_offset = alloc_clusters_noref(bs, new_table_size2); - ret = bdrv_pwrite(s->hd, table_offset, new_table, new_table_size2); - if (ret != new_table_size2) - goto fail; - for(i = 0; i < s->refcount_table_size; i++) - be64_to_cpus(&new_table[i]); - - 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)) - goto fail; - qemu_free(s->refcount_table); - old_table_offset = s->refcount_table_offset; - old_table_size = s->refcount_table_size; - s->refcount_table = new_table; - s->refcount_table_size = new_table_size; - s->refcount_table_offset = table_offset; - - update_refcount(bs, table_offset, new_table_size2, 1); - free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t)); - return 0; - fail: - free_clusters(bs, table_offset, new_table_size2); - qemu_free(new_table); - return -EIO; -} - - -static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) -{ - BDRVQcowState *s = bs->opaque; - int64_t offset, refcount_block_offset; - int ret, refcount_table_index; - uint64_t data64; - - /* Find L1 index and grow refcount table if needed */ - refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); - if (refcount_table_index >= s->refcount_table_size) { - ret = grow_refcount_table(bs, refcount_table_index + 1); - if (ret < 0) - return ret; - } - - /* Load or allocate the refcount block */ - refcount_block_offset = s->refcount_table[refcount_table_index]; - if (!refcount_block_offset) { - /* create a new refcount block */ - /* Note: we cannot update the refcount now to avoid recursion */ - offset = alloc_clusters_noref(bs, s->cluster_size); - memset(s->refcount_block_cache, 0, s->cluster_size); - ret = bdrv_pwrite(s->hd, offset, s->refcount_block_cache, s->cluster_size); - if (ret != s->cluster_size) - return -EINVAL; - s->refcount_table[refcount_table_index] = offset; - data64 = cpu_to_be64(offset); - ret = bdrv_pwrite(s->hd, s->refcount_table_offset + - refcount_table_index * sizeof(uint64_t), - &data64, sizeof(data64)); - if (ret != sizeof(data64)) - return -EINVAL; - - refcount_block_offset = offset; - s->refcount_block_cache_offset = offset; - update_refcount(bs, offset, s->cluster_size, 1); - } else { - if (refcount_block_offset != s->refcount_block_cache_offset) { - if (load_refcount_block(bs, refcount_block_offset) < 0) - return -EIO; - } - } - - return refcount_block_offset; -} - -/* addend must be 1 or -1 */ -static int update_cluster_refcount(BlockDriverState *bs, - int64_t cluster_index, - int addend) -{ - BDRVQcowState *s = bs->opaque; - int ret; - - ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend); - if (ret < 0) { - return ret; - } - - return get_refcount(bs, cluster_index); -} - -/* XXX: cache several refcount block clusters ? */ -static int 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; - -#ifdef DEBUG_ALLOC2 - printf("update_refcount: offset=%lld size=%lld addend=%d\n", - offset, length, addend); -#endif - if (length <= 0) - return -EINVAL; - start = offset & ~(s->cluster_size - 1); - last = (offset + length - 1) & ~(s->cluster_size - 1); - for(cluster_offset = start; cluster_offset <= last; - cluster_offset += s->cluster_size) - { - int block_index, refcount; - int64_t cluster_index = cluster_offset >> s->cluster_bits; - - /* Only write refcount block to disk when we are done with it */ - old_table_index = table_index; - table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); - if ((old_table_index >= 0) && (table_index != old_table_index)) { - size_t size = (last_index - first_index + 1) << REFCOUNT_SHIFT; - if (bdrv_pwrite(s->hd, - refcount_block_offset + (first_index << REFCOUNT_SHIFT), - &s->refcount_block_cache[first_index], size) != size) - { - return -EIO; - } - - first_index = -1; - last_index = -1; - } - - /* 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; - } - - /* we can update the count and save it */ - block_index = cluster_index & - ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1); - if (first_index == -1 || block_index < first_index) { - first_index = block_index; - } - if (block_index > last_index) { - last_index = block_index; - } - - refcount = be16_to_cpu(s->refcount_block_cache[block_index]); - refcount += addend; - if (refcount < 0 || refcount > 0xffff) - return -EINVAL; - 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); - } - - /* Write last changed block to disk */ - if (refcount_block_offset != 0) { - size_t size = (last_index - first_index + 1) << REFCOUNT_SHIFT; - if (bdrv_pwrite(s->hd, - refcount_block_offset + (first_index << REFCOUNT_SHIFT), - &s->refcount_block_cache[first_index], size) != size) - { - return -EIO; - } - } - - return 0; -} - -/* - * Increases the refcount for a range of clusters in a given refcount table. - * This is used to construct a temporary refcount table out of L1 and L2 tables - * which can be compared the the refcount table saved in the image. - * - * Returns the number of errors in the image that were found - */ -static int inc_refcounts(BlockDriverState *bs, - uint16_t *refcount_table, - int refcount_table_size, - int64_t offset, int64_t size) -{ - BDRVQcowState *s = bs->opaque; - int64_t start, last, cluster_offset; - int k; - int errors = 0; - - if (size <= 0) - return 0; - - start = offset & ~(s->cluster_size - 1); - last = (offset + size - 1) & ~(s->cluster_size - 1); - for(cluster_offset = start; cluster_offset <= last; - cluster_offset += s->cluster_size) { - k = cluster_offset >> s->cluster_bits; - if (k < 0 || k >= refcount_table_size) { - fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n", - cluster_offset); - errors++; - } else { - if (++refcount_table[k] == 0) { - fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64 - "\n", cluster_offset); - errors++; - } - } - } - - return errors; -} - -/* - * Increases the refcount in the given refcount table for the all clusters - * referenced in the L2 table. While doing so, performs some checks on L2 - * entries. - * - * Returns the number of errors found by the checks or -errno if an internal - * error occurred. - */ -static int check_refcounts_l2(BlockDriverState *bs, - uint16_t *refcount_table, int refcount_table_size, int64_t l2_offset, - int check_copied) -{ - BDRVQcowState *s = bs->opaque; - uint64_t *l2_table, offset; - int i, l2_size, nb_csectors, refcount; - int errors = 0; - - /* Read L2 table from disk */ - l2_size = s->l2_size * sizeof(uint64_t); - l2_table = qemu_malloc(l2_size); - - if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size) - goto fail; - - /* Do the actual checks */ - for(i = 0; i < s->l2_size; i++) { - offset = be64_to_cpu(l2_table[i]); - if (offset != 0) { - if (offset & QCOW_OFLAG_COMPRESSED) { - /* Compressed clusters don't have QCOW_OFLAG_COPIED */ - if (offset & QCOW_OFLAG_COPIED) { - fprintf(stderr, "ERROR: cluster %" PRId64 ": " - "copied flag must never be set for compressed " - "clusters\n", offset >> s->cluster_bits); - offset &= ~QCOW_OFLAG_COPIED; - errors++; - } - - /* Mark cluster as used */ - nb_csectors = ((offset >> s->csize_shift) & - s->csize_mask) + 1; - offset &= s->cluster_offset_mask; - errors += inc_refcounts(bs, refcount_table, - refcount_table_size, - offset & ~511, nb_csectors * 512); - } else { - /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */ - if (check_copied) { - uint64_t entry = offset; - offset &= ~QCOW_OFLAG_COPIED; - refcount = get_refcount(bs, offset >> s->cluster_bits); - if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) { - fprintf(stderr, "ERROR OFLAG_COPIED: offset=%" - PRIx64 " refcount=%d\n", entry, refcount); - errors++; - } - } - - /* Mark cluster as used */ - offset &= ~QCOW_OFLAG_COPIED; - errors += inc_refcounts(bs, refcount_table, - refcount_table_size, - offset, s->cluster_size); - - /* Correct offsets are cluster aligned */ - if (offset & (s->cluster_size - 1)) { - fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not " - "properly aligned; L2 entry corrupted.\n", offset); - errors++; - } - } - } - } - - qemu_free(l2_table); - return errors; - -fail: - fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n"); - qemu_free(l2_table); - return -EIO; -} - -/* - * Increases the refcount for the L1 table, its L2 tables and all referenced - * clusters in the given refcount table. While doing so, performs some checks - * on L1 and L2 entries. - * - * Returns the number of errors found by the checks or -errno if an internal - * error occurred. - */ -static int check_refcounts_l1(BlockDriverState *bs, - uint16_t *refcount_table, - int refcount_table_size, - int64_t l1_table_offset, int l1_size, - int check_copied) -{ - BDRVQcowState *s = bs->opaque; - uint64_t *l1_table, l2_offset, l1_size2; - int i, refcount, ret; - int errors = 0; - - l1_size2 = l1_size * sizeof(uint64_t); - - /* Mark L1 table as used */ - errors += inc_refcounts(bs, refcount_table, refcount_table_size, - l1_table_offset, l1_size2); - - /* Read L1 table entries from disk */ - l1_table = qemu_malloc(l1_size2); - if (bdrv_pread(s->hd, l1_table_offset, - l1_table, l1_size2) != l1_size2) - goto fail; - for(i = 0;i < l1_size; i++) - be64_to_cpus(&l1_table[i]); - - /* Do the actual checks */ - for(i = 0; i < l1_size; i++) { - l2_offset = l1_table[i]; - if (l2_offset) { - /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */ - if (check_copied) { - refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED) - >> s->cluster_bits); - if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) { - fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64 - " refcount=%d\n", l2_offset, refcount); - errors++; - } - } - - /* Mark L2 table as used */ - l2_offset &= ~QCOW_OFLAG_COPIED; - errors += inc_refcounts(bs, refcount_table, - refcount_table_size, - l2_offset, - s->cluster_size); - - /* L2 tables are cluster aligned */ - if (l2_offset & (s->cluster_size - 1)) { - fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not " - "cluster aligned; L1 entry corrupted\n", l2_offset); - errors++; - } - - /* Process and check L2 entries */ - ret = check_refcounts_l2(bs, refcount_table, refcount_table_size, - l2_offset, check_copied); - if (ret < 0) { - goto fail; - } - errors += ret; - } - } - qemu_free(l1_table); - return errors; - -fail: - fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n"); - qemu_free(l1_table); - return -EIO; -} - -/* - * Checks an image for refcount consistency. - * - * Returns 0 if no errors are found, the number of errors in case the image is - * detected as corrupted, and -errno when an internal error occured. - */ -static int check_refcounts(BlockDriverState *bs) -{ - BDRVQcowState *s = bs->opaque; - int64_t size; - int nb_clusters, refcount1, refcount2, i; - QCowSnapshot *sn; - uint16_t *refcount_table; - int ret, errors = 0; - - size = bdrv_getlength(s->hd); - nb_clusters = size_to_clusters(s, size); - refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t)); - - /* header */ - errors += inc_refcounts(bs, refcount_table, nb_clusters, - 0, s->cluster_size); - - /* current L1 table */ - ret = check_refcounts_l1(bs, refcount_table, nb_clusters, - s->l1_table_offset, s->l1_size, 1); - if (ret < 0) { - return ret; - } - errors += ret; - - /* snapshots */ - for(i = 0; i < s->nb_snapshots; i++) { - sn = s->snapshots + i; - check_refcounts_l1(bs, refcount_table, nb_clusters, - sn->l1_table_offset, sn->l1_size, 0); - } - errors += inc_refcounts(bs, refcount_table, nb_clusters, - s->snapshots_offset, s->snapshots_size); - - /* refcount data */ - errors += inc_refcounts(bs, refcount_table, nb_clusters, - s->refcount_table_offset, - s->refcount_table_size * sizeof(uint64_t)); - for(i = 0; i < s->refcount_table_size; i++) { - int64_t offset; - offset = s->refcount_table[i]; - if (offset != 0) { - errors += inc_refcounts(bs, refcount_table, nb_clusters, - offset, s->cluster_size); - } - } - - /* compare ref counts */ - for(i = 0; i < nb_clusters; i++) { - refcount1 = get_refcount(bs, i); - refcount2 = refcount_table[i]; - if (refcount1 != refcount2) { - fprintf(stderr, "ERROR cluster %d refcount=%d reference=%d\n", - i, refcount1, refcount2); - errors++; - } - } - - qemu_free(refcount_table); - - return errors; -} static int qcow_check(BlockDriverState *bs) { - return check_refcounts(bs); + return qcow2_check_refcounts(bs); } #if 0 @@ -3025,10 +1006,10 @@ static BlockDriver bdrv_qcow2 = { .bdrv_aio_writev = qcow_aio_writev, .bdrv_write_compressed = qcow_write_compressed, - .bdrv_snapshot_create = qcow_snapshot_create, - .bdrv_snapshot_goto = qcow_snapshot_goto, - .bdrv_snapshot_delete = qcow_snapshot_delete, - .bdrv_snapshot_list = qcow_snapshot_list, + .bdrv_snapshot_create = qcow2_snapshot_create, + .bdrv_snapshot_goto = qcow2_snapshot_goto, + .bdrv_snapshot_delete = qcow2_snapshot_delete, + .bdrv_snapshot_list = qcow2_snapshot_list, .bdrv_get_info = qcow_get_info, .bdrv_put_buffer = qcow_put_buffer, diff --git a/block/qcow2.h b/block/qcow2.h new file mode 100644 index 000000000..d73400306 --- /dev/null +++ b/block/qcow2.h @@ -0,0 +1,203 @@ +/* + * Block driver for the QCOW version 2 format + * + * Copyright (c) 2004-2006 Fabrice Bellard + * + * 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. + */ + +#ifndef BLOCK_QCOW2_H +#define BLOCK_QCOW2_H + +#include "aes.h" + +#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb) +#define QCOW_VERSION 2 + +#define QCOW_CRYPT_NONE 0 +#define QCOW_CRYPT_AES 1 + +#define QCOW_MAX_CRYPT_CLUSTERS 32 + +/* indicate that the refcount of the referenced cluster is exactly one. */ +#define QCOW_OFLAG_COPIED (1LL << 63) +/* indicate that the cluster is compressed (they never have the copied flag) */ +#define QCOW_OFLAG_COMPRESSED (1LL << 62) + +#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */ + +#define MIN_CLUSTER_BITS 9 +#define MAX_CLUSTER_BITS 16 + +#define L2_CACHE_SIZE 16 + +typedef struct QCowHeader { + uint32_t magic; + uint32_t version; + uint64_t backing_file_offset; + uint32_t backing_file_size; + uint32_t cluster_bits; + uint64_t size; /* in bytes */ + uint32_t crypt_method; + uint32_t l1_size; /* XXX: save number of clusters instead ? */ + uint64_t l1_table_offset; + uint64_t refcount_table_offset; + uint32_t refcount_table_clusters; + uint32_t nb_snapshots; + uint64_t snapshots_offset; +} QCowHeader; + +typedef struct QCowSnapshot { + uint64_t l1_table_offset; + uint32_t l1_size; + char *id_str; + char *name; + uint32_t vm_state_size; + uint32_t date_sec; + uint32_t date_nsec; + uint64_t vm_clock_nsec; +} QCowSnapshot; + +typedef struct BDRVQcowState { + BlockDriverState *hd; + int cluster_bits; + int cluster_size; + int cluster_sectors; + int l2_bits; + int l2_size; + int l1_size; + int l1_vm_state_index; + int csize_shift; + int csize_mask; + uint64_t cluster_offset_mask; + uint64_t l1_table_offset; + uint64_t *l1_table; + uint64_t *l2_cache; + uint64_t l2_cache_offsets[L2_CACHE_SIZE]; + uint32_t l2_cache_counts[L2_CACHE_SIZE]; + uint8_t *cluster_cache; + uint8_t *cluster_data; + uint64_t cluster_cache_offset; + + uint64_t *refcount_table; + uint64_t refcount_table_offset; + uint32_t refcount_table_size; + uint64_t refcount_block_cache_offset; + uint16_t *refcount_block_cache; + int64_t free_cluster_index; + int64_t free_byte_offset; + + uint32_t crypt_method; /* current crypt method, 0 if no key yet */ + uint32_t crypt_method_header; + AES_KEY aes_encrypt_key; + AES_KEY aes_decrypt_key; + uint64_t snapshots_offset; + int snapshots_size; + int nb_snapshots; + QCowSnapshot *snapshots; +} BDRVQcowState; + +/* XXX: use std qcow open function ? */ +typedef struct QCowCreateState { + int cluster_size; + int cluster_bits; + uint16_t *refcount_block; + uint64_t *refcount_table; + int64_t l1_table_offset; + int64_t refcount_table_offset; + int64_t refcount_block_offset; +} QCowCreateState; + +/* XXX This could be private for qcow2-cluster.c */ +typedef struct QCowL2Meta +{ + uint64_t offset; + int n_start; + int nb_available; + int nb_clusters; +} QCowL2Meta; + +static inline int size_to_clusters(BDRVQcowState *s, int64_t size) +{ + return (size + (s->cluster_size - 1)) >> s->cluster_bits; +} + +static inline int64_t align_offset(int64_t offset, int n) +{ + offset = (offset + n - 1) & ~(n - 1); + return offset; +} + + +// FIXME Need qcow2_ prefix to global functions + +/* qcow2.c functions */ +int qcow2_backing_read1(BlockDriverState *bs, + int64_t sector_num, uint8_t *buf, int nb_sectors); + +/* qcow2-refcount.c functions */ +int qcow2_refcount_init(BlockDriverState *bs); +void qcow2_refcount_close(BlockDriverState *bs); + +int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size); +int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size); +void qcow2_free_clusters(BlockDriverState *bs, + int64_t offset, int64_t size); +void qcow2_free_any_clusters(BlockDriverState *bs, + uint64_t cluster_offset, int nb_clusters); + +void qcow2_create_refcount_update(QCowCreateState *s, int64_t offset, + int64_t size); +int qcow2_update_snapshot_refcount(BlockDriverState *bs, + int64_t l1_table_offset, int l1_size, int addend); + +int qcow2_check_refcounts(BlockDriverState *bs); + +/* qcow2-cluster.c functions */ +int qcow2_grow_l1_table(BlockDriverState *bs, int min_size); +void qcow2_l2_cache_reset(BlockDriverState *bs); +int qcow2_decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset); +void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num, + uint8_t *out_buf, const uint8_t *in_buf, + int nb_sectors, int enc, + const AES_KEY *key); + +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); +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); + +/* qcow2-snapshot.c functions */ +int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info); +int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id); +int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id); +int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab); + +void qcow2_free_snapshots(BlockDriverState *bs); +int qcow2_read_snapshots(BlockDriverState *bs); + +#endif diff --git a/block/raw-posix.c b/block/raw-posix.c index 1ed8d5be3..41bfa373c 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -135,7 +135,8 @@ static int raw_open_common(BlockDriverState *bs, const char *filename, s->lseek_err_cnt = 0; s->open_flags |= O_BINARY; - if ((flags & BDRV_O_ACCESS) == O_RDWR) { + s->open_flags &= ~O_ACCMODE; + if ((flags & BDRV_O_ACCESS) == BDRV_O_RDWR) { s->open_flags |= O_RDWR; } else { s->open_flags |= O_RDONLY; @@ -201,7 +201,7 @@ io_thread="no" nptl="yes" mixemu="no" bluez="yes" -kvm="yes" +kvm="no" kvm_trace="no" kvm_cap_pit="no" kvm_cap_device_assignment="no" @@ -309,7 +309,6 @@ SunOS) make="gmake" install="ginstall" needs_libsunmath="no" - kvm="no" solarisrev=`uname -r | cut -f2 -d.` # have to select again, because `uname -m` returns i86pc # even on an x86_64 box. @@ -349,6 +348,7 @@ audio_possible_drivers="oss alsa sdl esd pa" linux="yes" linux_user="yes" usb="linux" +kvm="yes" if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then kqemu="yes" audio_possible_drivers="$audio_possible_drivers fmod" @@ -644,7 +644,7 @@ echo " --install=INSTALL use specified install [$install]" echo " --static enable static build [$static]" echo " --enable-debug-tcg enable TCG debugging" echo " --disable-debug-tcg disable TCG debugging (default)" -echo " --disable-debug enable common debug build options" +echo " --enable-debug enable common debug build options" echo " --enable-sparse enable sparse checker" echo " --disable-sparse disable sparse checker (default)" echo " --disable-strip disable stripping binaries" @@ -1379,6 +1379,63 @@ EOF fi fi +# check if utimensat and futimens are supported +utimens=no +cat > $TMPC << EOF +#define _ATFILE_SOURCE +#define _GNU_SOURCE +#include <stddef.h> +#include <fcntl.h> + +int main(void) +{ + utimensat(AT_FDCWD, "foo", NULL, 0); + futimens(0, NULL); + return 0; +} +EOF +if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then + utimens=yes +fi + +# check if pipe2 is there +pipe2=no +cat > $TMPC << EOF +#define _GNU_SOURCE +#include <unistd.h> +#include <fcntl.h> + +int main(void) +{ + int pipefd[2]; + pipe2(pipefd, O_CLOEXEC); + return 0; +} +EOF +if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then + pipe2=yes +fi + +# check if tee/splice is there. vmsplice was added same time. +splice=no +cat > $TMPC << EOF +#define _GNU_SOURCE +#include <unistd.h> +#include <fcntl.h> +#include <limits.h> + +int main(void) +{ + int len, fd; + len = tee(STDIN_FILENO, STDOUT_FILENO, INT_MAX, SPLICE_F_NONBLOCK); + splice(STDIN_FILENO, NULL, fd, NULL, len, SPLICE_F_MOVE); + return 0; +} +EOF +if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then + splice=yes +fi + ########################################## # signalfd probe cat > $TMPC << EOF @@ -1818,6 +1875,15 @@ fi if test "$atfile" = "yes" ; then echo "#define CONFIG_ATFILE 1" >> $config_h fi +if test "$utimens" = "yes" ; then + echo "#define CONFIG_UTIMENSAT 1" >> $config_h +fi +if test "$pipe2" = "yes" ; then + echo "#define CONFIG_PIPE2 1" >> $config_h +fi +if test "$splice" = "yes" ; then + echo "#define CONFIG_SPLICE 1" >> $config_h +fi if test "$inotify" = "yes" ; then echo "#define CONFIG_INOTIFY 1" >> $config_h fi @@ -735,12 +735,15 @@ extern unsigned long qemu_host_page_mask; #define PAGE_RESERVED 0x0020 void page_dump(FILE *f); +int walk_memory_regions(void *, + int (*fn)(void *, unsigned long, unsigned long, unsigned long)); int page_get_flags(target_ulong address); void page_set_flags(target_ulong start, target_ulong end, int flags); int page_check_range(target_ulong start, target_ulong len, int flags); void cpu_exec_init_all(unsigned long tb_size); CPUState *cpu_copy(CPUState *env); +CPUState *qemu_get_cpu(int cpu); void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), diff --git a/cpu-common.h b/cpu-common.h index 4640924a0..8f89325a8 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -41,8 +41,7 @@ void *qemu_get_ram_ptr(ram_addr_t addr); /* This should not be used by devices. */ ram_addr_t qemu_ram_addr_from_host(void *ptr); -int cpu_register_io_memory(int io_index, - CPUReadMemoryFunc **mem_read, +int cpu_register_io_memory(CPUReadMemoryFunc **mem_read, CPUWriteMemoryFunc **mem_write, void *opaque); void cpu_unregister_io_memory(int table_address); @@ -1081,7 +1081,23 @@ typedef struct elf64_shdr { #define EI_CLASS 4 #define EI_DATA 5 #define EI_VERSION 6 -#define EI_PAD 7 +#define EI_OSABI 7 +#define EI_PAD 8 + +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_LINUX 3 /* Linux. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ #define ELFMAG0 0x7f /* EI_MAG */ #define ELFMAG1 'E' @@ -1108,6 +1124,7 @@ typedef struct elf64_shdr { #define NT_PRFPREG 2 #define NT_PRPSINFO 3 #define NT_TASKSTRUCT 4 +#define NT_AUXV 6 #define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ @@ -553,6 +553,19 @@ static int cpu_common_load(QEMUFile *f, void *opaque, int version_id) } #endif +CPUState *qemu_get_cpu(int cpu) +{ + CPUState *env = first_cpu; + + while (env) { + if (env->cpu_index == cpu) + break; + env = env->next_cpu; + } + + return env; +} + void cpu_exec_init(CPUState *env) { CPUState **penv; @@ -1768,28 +1781,12 @@ void tlb_flush(CPUState *env, int flush_global) env->current_tb = NULL; for(i = 0; i < CPU_TLB_SIZE; i++) { - env->tlb_table[0][i].addr_read = -1; - env->tlb_table[0][i].addr_write = -1; - env->tlb_table[0][i].addr_code = -1; - env->tlb_table[1][i].addr_read = -1; - env->tlb_table[1][i].addr_write = -1; - env->tlb_table[1][i].addr_code = -1; -#if (NB_MMU_MODES >= 3) - env->tlb_table[2][i].addr_read = -1; - env->tlb_table[2][i].addr_write = -1; - env->tlb_table[2][i].addr_code = -1; -#endif -#if (NB_MMU_MODES >= 4) - env->tlb_table[3][i].addr_read = -1; - env->tlb_table[3][i].addr_write = -1; - env->tlb_table[3][i].addr_code = -1; -#endif -#if (NB_MMU_MODES >= 5) - env->tlb_table[4][i].addr_read = -1; - env->tlb_table[4][i].addr_write = -1; - env->tlb_table[4][i].addr_code = -1; -#endif - + int mmu_idx; + for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { + env->tlb_table[mmu_idx][i].addr_read = -1; + env->tlb_table[mmu_idx][i].addr_write = -1; + env->tlb_table[mmu_idx][i].addr_code = -1; + } } memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); @@ -1819,6 +1816,7 @@ static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr) void tlb_flush_page(CPUState *env, target_ulong addr) { int i; + int mmu_idx; #if defined(DEBUG_TLB) printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr); @@ -1829,17 +1827,8 @@ void tlb_flush_page(CPUState *env, target_ulong addr) addr &= TARGET_PAGE_MASK; i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - tlb_flush_entry(&env->tlb_table[0][i], addr); - tlb_flush_entry(&env->tlb_table[1][i], addr); -#if (NB_MMU_MODES >= 3) - tlb_flush_entry(&env->tlb_table[2][i], addr); -#endif -#if (NB_MMU_MODES >= 4) - tlb_flush_entry(&env->tlb_table[3][i], addr); -#endif -#if (NB_MMU_MODES >= 5) - tlb_flush_entry(&env->tlb_table[4][i], addr); -#endif + for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) + tlb_flush_entry(&env->tlb_table[mmu_idx][i], addr); tlb_flush_jmp_cache(env, addr); @@ -1923,22 +1912,12 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, } for(env = first_cpu; env != NULL; env = env->next_cpu) { - for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length); - for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length); -#if (NB_MMU_MODES >= 3) - for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length); -#endif -#if (NB_MMU_MODES >= 4) - for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length); -#endif -#if (NB_MMU_MODES >= 5) - for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_reset_dirty_range(&env->tlb_table[4][i], start1, length); -#endif + int mmu_idx; + for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i], + start1, length); + } } } @@ -1984,22 +1963,11 @@ static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry) void cpu_tlb_update_dirty(CPUState *env) { int i; - for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_update_dirty(&env->tlb_table[0][i]); - for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_update_dirty(&env->tlb_table[1][i]); -#if (NB_MMU_MODES >= 3) - for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_update_dirty(&env->tlb_table[2][i]); -#endif -#if (NB_MMU_MODES >= 4) - for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_update_dirty(&env->tlb_table[3][i]); -#endif -#if (NB_MMU_MODES >= 5) - for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_update_dirty(&env->tlb_table[4][i]); -#endif + int mmu_idx; + for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { + for(i = 0; i < CPU_TLB_SIZE; i++) + tlb_update_dirty(&env->tlb_table[mmu_idx][i]); + } } static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr) @@ -2013,20 +1981,12 @@ static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr) static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr) { int i; + int mmu_idx; vaddr &= TARGET_PAGE_MASK; i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - tlb_set_dirty1(&env->tlb_table[0][i], vaddr); - tlb_set_dirty1(&env->tlb_table[1][i], vaddr); -#if (NB_MMU_MODES >= 3) - tlb_set_dirty1(&env->tlb_table[2][i], vaddr); -#endif -#if (NB_MMU_MODES >= 4) - tlb_set_dirty1(&env->tlb_table[3][i], vaddr); -#endif -#if (NB_MMU_MODES >= 5) - tlb_set_dirty1(&env->tlb_table[4][i], vaddr); -#endif + for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) + tlb_set_dirty1(&env->tlb_table[mmu_idx][i], vaddr); } /* add a new TLB entry. At most one entry for a given virtual address @@ -2149,36 +2109,36 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, return 0; } -/* dump memory mappings */ -void page_dump(FILE *f) +/* + * Walks guest process memory "regions" one by one + * and calls callback function 'fn' for each region. + */ +int walk_memory_regions(void *priv, + int (*fn)(void *, unsigned long, unsigned long, unsigned long)) { unsigned long start, end; + PageDesc *p = NULL; int i, j, prot, prot1; - PageDesc *p; + int rc = 0; - fprintf(f, "%-8s %-8s %-8s %s\n", - "start", "end", "size", "prot"); - start = -1; - end = -1; + start = end = -1; prot = 0; - for(i = 0; i <= L1_SIZE; i++) { - if (i < L1_SIZE) - p = l1_map[i]; - else - p = NULL; - for(j = 0;j < L2_SIZE; j++) { - if (!p) - prot1 = 0; - else - prot1 = p[j].flags; + + for (i = 0; i <= L1_SIZE; i++) { + p = (i < L1_SIZE) ? l1_map[i] : NULL; + for (j = 0; j < L2_SIZE; j++) { + prot1 = (p == NULL) ? 0 : p[j].flags; + /* + * "region" is one continuous chunk of memory + * that has same protection flags set. + */ if (prot1 != prot) { end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); if (start != -1) { - fprintf(f, "%08lx-%08lx %08lx %c%c%c\n", - start, end, end - start, - prot & PAGE_READ ? 'r' : '-', - prot & PAGE_WRITE ? 'w' : '-', - prot & PAGE_EXEC ? 'x' : '-'); + rc = (*fn)(priv, start, end, prot); + /* callback can stop iteration by returning != 0 */ + if (rc != 0) + return (rc); } if (prot1 != 0) start = end; @@ -2186,10 +2146,33 @@ void page_dump(FILE *f) start = -1; prot = prot1; } - if (!p) + if (p == NULL) break; } } + return (rc); +} + +static int dump_region(void *priv, unsigned long start, + unsigned long end, unsigned long prot) +{ + FILE *f = (FILE *)priv; + + (void) fprintf(f, "%08lx-%08lx %08lx %c%c%c\n", + start, end, end - start, + ((prot & PAGE_READ) ? 'r' : '-'), + ((prot & PAGE_WRITE) ? 'w' : '-'), + ((prot & PAGE_EXEC) ? 'x' : '-')); + + return (0); +} + +/* dump memory mappings */ +void page_dump(FILE *f) +{ + (void) fprintf(f, "%-8s %-8s %-8s %s\n", + "start", "end", "size", "prot"); + walk_memory_regions(f, dump_region); } int page_get_flags(target_ulong address) @@ -3109,7 +3092,7 @@ static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys, mmio = qemu_mallocz(sizeof(subpage_t)); mmio->base = base; - subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio); + subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio); #if defined(DEBUG_SUBPAGE) printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__, mmio, base, TARGET_PAGE_SIZE, subpage_memory); @@ -3134,27 +3117,6 @@ static int get_free_io_mem_idx(void) return -1; } -static void io_mem_init(void) -{ - int i; - - cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL); - cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL); - cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL); - for (i=0; i<5; i++) - io_mem_used[i] = 1; - - io_mem_watch = cpu_register_io_memory(0, watch_mem_read, - watch_mem_write, NULL); -#ifdef CONFIG_KQEMU - if (kqemu_phys_ram_base) { - /* alloc dirty bits array */ - phys_ram_dirty = qemu_vmalloc(kqemu_phys_ram_size >> TARGET_PAGE_BITS); - memset(phys_ram_dirty, 0xff, kqemu_phys_ram_size >> TARGET_PAGE_BITS); - } -#endif -} - /* mem_read and mem_write are arrays of functions containing the function to access byte (index 0), word (index 1) and dword (index 2). Functions can be omitted with a NULL function pointer. @@ -3162,10 +3124,10 @@ static void io_mem_init(void) modified. If it is zero, a new io zone is allocated. The return value can be used with cpu_register_physical_memory(). (-1) is returned if error. */ -int cpu_register_io_memory(int io_index, - CPUReadMemoryFunc **mem_read, - CPUWriteMemoryFunc **mem_write, - void *opaque) +static int cpu_register_io_memory_fixed(int io_index, + CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write, + void *opaque) { int i, subwidth = 0; @@ -3174,6 +3136,7 @@ int cpu_register_io_memory(int io_index, if (io_index == -1) return io_index; } else { + io_index >>= IO_MEM_SHIFT; if (io_index >= IO_MEM_NB_ENTRIES) return -1; } @@ -3188,6 +3151,13 @@ int cpu_register_io_memory(int io_index, return (io_index << IO_MEM_SHIFT) | subwidth; } +int cpu_register_io_memory(CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write, + void *opaque) +{ + return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque); +} + void cpu_unregister_io_memory(int io_table_address) { int i; @@ -3201,6 +3171,27 @@ void cpu_unregister_io_memory(int io_table_address) io_mem_used[io_index] = 0; } +static void io_mem_init(void) +{ + int i; + + cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read, unassigned_mem_write, NULL); + cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read, unassigned_mem_write, NULL); + cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read, notdirty_mem_write, NULL); + for (i=0; i<5; i++) + io_mem_used[i] = 1; + + io_mem_watch = cpu_register_io_memory(watch_mem_read, + watch_mem_write, NULL); +#ifdef CONFIG_KQEMU + if (kqemu_phys_ram_base) { + /* alloc dirty bits array */ + phys_ram_dirty = qemu_vmalloc(kqemu_phys_ram_size >> TARGET_PAGE_BITS); + memset(phys_ram_dirty, 0xff, kqemu_phys_ram_size >> TARGET_PAGE_BITS); + } +#endif +} + #endif /* !defined(CONFIG_USER_ONLY) */ /* physical memory access (slow version, mainly for debug) */ @@ -1366,8 +1366,8 @@ int ac97_init (PCIBus *bus) c[0x3c] = 0x00; /* intr_ln interrupt line rw */ c[0x3d] = 0x01; /* intr_pn interrupt pin ro */ - pci_register_io_region (&d->dev, 0, 256 * 4, PCI_ADDRESS_SPACE_IO, ac97_map); - pci_register_io_region (&d->dev, 1, 64 * 4, PCI_ADDRESS_SPACE_IO, ac97_map); + pci_register_bar (&d->dev, 0, 256 * 4, PCI_ADDRESS_SPACE_IO, ac97_map); + pci_register_bar (&d->dev, 1, 64 * 4, PCI_ADDRESS_SPACE_IO, ac97_map); register_savevm ("ac97", 0, 2, ac97_save, ac97_load, s); qemu_register_reset (ac97_on_reset, 0, s); AUD_register_card ("ac97", &s->card); diff --git a/hw/apb_pci.c b/hw/apb_pci.c index dac5cd3af..b63ccd130 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -234,13 +234,13 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base, s->bus = pci_register_bus(NULL, "pci", pci_apb_set_irq, pci_pbm_map_irq, pic, 0, 32); - pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read, + pci_mem_config = cpu_register_io_memory(pci_apb_config_read, pci_apb_config_write, s); - apb_config = cpu_register_io_memory(0, apb_config_read, + apb_config = cpu_register_io_memory(apb_config_read, apb_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_apb_read, + pci_mem_data = cpu_register_io_memory(pci_apb_read, pci_apb_write, s); - pci_ioport = cpu_register_io_memory(0, pci_apb_ioread, + pci_ioport = cpu_register_io_memory(pci_apb_ioread, pci_apb_iowrite, s); cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config); @@ -1047,7 +1047,7 @@ int apic_init(CPUState *env) if (apic_io_memory == 0) { /* NOTE: the APIC is directly connected to the CPU - it is not on the global memory bus. */ - apic_io_memory = cpu_register_io_memory(0, apic_mem_read, + apic_io_memory = cpu_register_io_memory(apic_mem_read, apic_mem_write, NULL); cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000, apic_io_memory); diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 817234da9..563397d3e 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -725,7 +725,7 @@ static void gic_init(gic_state *s) for (i = 0; i < NCPU; i++) { sysbus_init_irq(&s->busdev, &s->parent_irq[i]); } - s->iomemtype = cpu_register_io_memory(0, gic_dist_readfn, + s->iomemtype = cpu_register_io_memory(gic_dist_readfn, gic_dist_writefn, s); gic_reset(s); register_savevm("arm_gic", -1, 1, gic_save, gic_load, s); diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index 1ddb4a27c..c9d1e3ff1 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -198,7 +198,7 @@ static void arm_sysctl_init1(SysBusDevice *dev) /* The MPcore bootloader uses these flags to start secondary CPUs. We don't use a bootloader, so do this here. */ s->flags = 3; - iomemtype = cpu_register_io_memory(0, arm_sysctl_readfn, + iomemtype = cpu_register_io_memory(arm_sysctl_readfn, arm_sysctl_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); /* ??? Save/restore. */ diff --git a/hw/arm_timer.c b/hw/arm_timer.c index 226ecc472..572804f9c 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -268,7 +268,7 @@ static void sp804_init(SysBusDevice *dev) s->timer[1] = arm_timer_init(1000000); s->timer[0]->irq = qi[0]; s->timer[1]->irq = qi[1]; - iomemtype = cpu_register_io_memory(0, sp804_readfn, + iomemtype = cpu_register_io_memory(sp804_readfn, sp804_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); register_savevm("sp804", -1, 1, sp804_save, sp804_load, s); @@ -338,7 +338,7 @@ static void icp_pit_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->timer[1]->irq); sysbus_init_irq(dev, &s->timer[2]->irq); - iomemtype = cpu_register_io_memory(0, icp_pit_readfn, + iomemtype = cpu_register_io_memory(icp_pit_readfn, icp_pit_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); /* This device has no state to save/restore. The component timers will diff --git a/hw/armv7m.c b/hw/armv7m.c index c3c5b9e34..297a3e1f0 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -128,7 +128,7 @@ static void bitband_init(SysBusDevice *dev) int iomemtype; s->base = qdev_get_prop_int(&dev->qdev, "base", 0); - iomemtype = cpu_register_io_memory(0, bitband_readfn, bitband_writefn, + iomemtype = cpu_register_io_memory(bitband_readfn, bitband_writefn, &s->base); sysbus_init_mmio(dev, 0x02000000, iomemtype); } diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c index c4e09dd5e..2b1925f99 100644 --- a/hw/axis_dev88.c +++ b/hw/axis_dev88.c @@ -286,11 +286,11 @@ void axisdev88_init (ram_addr_t ram_size, /* Attach a NAND flash to CS1. */ nand_state.nand = nand_init(NAND_MFR_STMICRO, 0x39); - nand_regs = cpu_register_io_memory(0, nand_read, nand_write, &nand_state); + nand_regs = cpu_register_io_memory(nand_read, nand_write, &nand_state); cpu_register_physical_memory(0x10000000, 0x05000000, nand_regs); gpio_state.nand = &nand_state; - gpio_regs = cpu_register_io_memory(0, gpio_read, gpio_write, &gpio_state); + gpio_regs = cpu_register_io_memory(gpio_read, gpio_write, &gpio_state); cpu_register_physical_memory(0x3001a000, 0x5c, gpio_regs); diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index e94dfeb85..4e74bcde8 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -3208,7 +3208,7 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s); register_ioport_read(0x3da, 1, 1, vga_ioport_read, s); - s->vga.vga_io_memory = cpu_register_io_memory(0, cirrus_vga_mem_read, + s->vga.vga_io_memory = cpu_register_io_memory(cirrus_vga_mem_read, cirrus_vga_mem_write, s); cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, s->vga.vga_io_memory); @@ -3216,16 +3216,16 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) /* I/O handler for LFB */ s->cirrus_linear_io_addr = - cpu_register_io_memory(0, cirrus_linear_read, cirrus_linear_write, s); + cpu_register_io_memory(cirrus_linear_read, cirrus_linear_write, s); /* I/O handler for LFB */ s->cirrus_linear_bitblt_io_addr = - cpu_register_io_memory(0, cirrus_linear_bitblt_read, + cpu_register_io_memory(cirrus_linear_bitblt_read, cirrus_linear_bitblt_write, s); /* I/O handler for memory-mapped I/O */ s->cirrus_mmio_io_addr = - cpu_register_io_memory(0, cirrus_mmio_read, cirrus_mmio_write, s); + cpu_register_io_memory(cirrus_mmio_read, cirrus_mmio_write, s); s->real_vram_size = (s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024; @@ -3354,10 +3354,10 @@ void pci_cirrus_vga_init(PCIBus *bus) /* memory #0 LFB */ /* memory #1 memory-mapped I/O */ /* XXX: s->vga.vram_size must be a power of two */ - pci_register_io_region((PCIDevice *)d, 0, 0x2000000, + pci_register_bar((PCIDevice *)d, 0, 0x2000000, PCI_ADDRESS_SPACE_MEM_PREFETCH, cirrus_pci_lfb_map); if (device_id == CIRRUS_ID_CLGD5446) { - pci_register_io_region((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE, + pci_register_bar((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE, PCI_ADDRESS_SPACE_MEM, cirrus_pci_mmio_map); } /* XXX: ROM BIOS */ diff --git a/hw/cs4231.c b/hw/cs4231.c index a5ba221bd..6d7e4b1c9 100644 --- a/hw/cs4231.c +++ b/hw/cs4231.c @@ -172,7 +172,7 @@ void cs_init(target_phys_addr_t base, int irq, void *intctl) s = qemu_mallocz(sizeof(CSState)); - cs_io_memory = cpu_register_io_memory(0, cs_mem_read, cs_mem_write, s); + cs_io_memory = cpu_register_io_memory(cs_mem_read, cs_mem_write, s); cpu_register_physical_memory(base, CS_SIZE, cs_io_memory); register_savevm("cs4231", base, 1, cs_save, cs_load, s); qemu_register_reset(cs_reset, 0, s); @@ -760,7 +760,7 @@ void cuda_init (int *cuda_mem_index, qemu_irq irq) s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; s->adb_poll_timer = qemu_new_timer(vm_clock, cuda_adb_poll, s); - *cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s); + *cuda_mem_index = cpu_register_io_memory(cuda_read, cuda_write, s); register_savevm("cuda", -1, 1, cuda_save, cuda_load, s); qemu_register_reset(cuda_reset, 0, s); cuda_reset(s); diff --git a/hw/device-assignment.c b/hw/device-assignment.c index 357a9462d..838bf5a62 100644 --- a/hw/device-assignment.c +++ b/hw/device-assignment.c @@ -404,9 +404,9 @@ static int assigned_dev_register_regions(PCIRegion *io_regions, pci_dev->v_addrs[i].u.r_virtbase += (cur_region->base_addr & 0xFFF); - pci_register_io_region((PCIDevice *) pci_dev, i, - cur_region->size, t, - assigned_dev_iomem_map); + pci_register_bar((PCIDevice *) pci_dev, i, + cur_region->size, t, + assigned_dev_iomem_map); continue; } /* handle port io regions */ @@ -415,9 +415,9 @@ static int assigned_dev_register_regions(PCIRegion *io_regions, pci_dev->v_addrs[i].r_size = cur_region->size; pci_dev->v_addrs[i].e_size = 0; - pci_register_io_region((PCIDevice *) pci_dev, i, - cur_region->size, PCI_ADDRESS_SPACE_IO, - assigned_dev_ioport_map); + pci_register_bar((PCIDevice *) pci_dev, i, + cur_region->size, PCI_ADDRESS_SPACE_IO, + assigned_dev_ioport_map); /* not relevant for port io */ pci_dev->v_addrs[i].memory_index = 0; @@ -1099,7 +1099,7 @@ static int assigned_dev_register_msix_mmio(AssignedDevice *dev) return -EFAULT; } memset(dev->msix_table_page, 0, 0x1000); - dev->mmio_index = cpu_register_io_memory(0, + dev->mmio_index = cpu_register_io_memory( msix_mmio_read, msix_mmio_write, dev); return 0; } diff --git a/hw/dp8393x.c b/hw/dp8393x.c index cff84aa0a..f326a1007 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -897,6 +897,6 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, qemu_register_reset(nic_reset, 0, s); nic_reset(s); - s->mmio_index = cpu_register_io_memory(0, dp8393x_read, dp8393x_write, s); + s->mmio_index = cpu_register_io_memory(dp8393x_read, dp8393x_write, s); cpu_register_physical_memory(base, 0x40 << it_shift, s->mmio_index); } diff --git a/hw/ds1225y.c b/hw/ds1225y.c index 458a7d5b8..44757179d 100644 --- a/hw/ds1225y.c +++ b/hw/ds1225y.c @@ -171,10 +171,10 @@ void *ds1225y_init(target_phys_addr_t mem_base, const char *filename) } /* Read/write memory */ - mem_indexRW = cpu_register_io_memory(0, nvram_read, nvram_write, s); + mem_indexRW = cpu_register_io_memory(nvram_read, nvram_write, s); cpu_register_physical_memory(mem_base, s->chip_size, mem_indexRW); /* Read/write protected memory */ - mem_indexRP = cpu_register_io_memory(0, nvram_read, nvram_write_protected, s); + mem_indexRP = cpu_register_io_memory(nvram_read, nvram_write_protected, s); cpu_register_physical_memory(mem_base + s->chip_size, s->chip_size, mem_indexRP); return s; } diff --git a/hw/e1000.c b/hw/e1000.c index eed02a69f..cffcbde84 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -1101,13 +1101,13 @@ static void pci_e1000_init(PCIDevice *pci_dev) pci_conf[0x3d] = 1; // interrupt pin 0 - d->mmio_index = cpu_register_io_memory(0, e1000_mmio_read, + d->mmio_index = cpu_register_io_memory(e1000_mmio_read, e1000_mmio_write, d); - pci_register_io_region((PCIDevice *)d, 0, PNPMMIO_SIZE, + pci_register_bar((PCIDevice *)d, 0, PNPMMIO_SIZE, PCI_ADDRESS_SPACE_MEM, e1000_mmio_map); - pci_register_io_region((PCIDevice *)d, 1, IOPORT_SIZE, + pci_register_bar((PCIDevice *)d, 1, IOPORT_SIZE, PCI_ADDRESS_SPACE_IO, ioport_map); memmove(d->eeprom_data, e1000_eeprom_template, diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c index aa4218d18..356b80309 100644 --- a/hw/eccmemctl.c +++ b/hw/eccmemctl.c @@ -325,10 +325,10 @@ void * ecc_init(target_phys_addr_t base, qemu_irq irq, uint32_t version) s->regs[0] = version; s->irq = irq; - ecc_io_memory = cpu_register_io_memory(0, ecc_mem_read, ecc_mem_write, s); + ecc_io_memory = cpu_register_io_memory(ecc_mem_read, ecc_mem_write, s); cpu_register_physical_memory(base, ECC_SIZE, ecc_io_memory); if (version == ECC_MCC) { // SS-600MP only - ecc_io_memory = cpu_register_io_memory(0, ecc_diag_mem_read, + ecc_io_memory = cpu_register_io_memory(ecc_diag_mem_read, ecc_diag_mem_write, s); cpu_register_physical_memory(base + 0x1000, ECC_DIAG_SIZE, ecc_io_memory); diff --git a/hw/eepro100.c b/hw/eepro100.c index a6355dc75..6f47eaf84 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1750,14 +1750,14 @@ static void nic_init(PCIDevice *pci_dev, uint32_t device) /* Handler for memory-mapped I/O */ d->eepro100.mmio_index = - cpu_register_io_memory(0, pci_mmio_read, pci_mmio_write, s); + cpu_register_io_memory(pci_mmio_read, pci_mmio_write, s); - pci_register_io_region(&d->dev, 0, PCI_MEM_SIZE, + pci_register_bar(&d->dev, 0, PCI_MEM_SIZE, PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_MEM_PREFETCH, pci_mmio_map); - pci_register_io_region(&d->dev, 1, PCI_IO_SIZE, PCI_ADDRESS_SPACE_IO, + pci_register_bar(&d->dev, 1, PCI_IO_SIZE, PCI_ADDRESS_SPACE_IO, pci_map); - pci_register_io_region(&d->dev, 2, PCI_FLASH_SIZE, PCI_ADDRESS_SPACE_MEM, + pci_register_bar(&d->dev, 2, PCI_FLASH_SIZE, PCI_ADDRESS_SPACE_MEM, pci_mmio_map); qdev_get_macaddr(&d->dev.qdev, s->macaddr); diff --git a/hw/es1370.c b/hw/es1370.c index 12f2ace0a..9a88baf6e 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -1053,7 +1053,7 @@ int es1370_init (PCIBus *bus) s = &d->es1370; s->pci_dev = &d->dev; - pci_register_io_region (&d->dev, 0, 256, PCI_ADDRESS_SPACE_IO, es1370_map); + pci_register_bar (&d->dev, 0, 256, PCI_ADDRESS_SPACE_IO, es1370_map); register_savevm ("es1370", 0, 2, es1370_save, es1370_load, s); qemu_register_reset (es1370_on_reset, 0, s); @@ -728,7 +728,7 @@ int escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB, s = qemu_mallocz(sizeof(SerialState)); - escc_io_memory = cpu_register_io_memory(0, escc_mem_read, + escc_io_memory = cpu_register_io_memory(escc_mem_read, escc_mem_write, s); if (base) @@ -922,7 +922,7 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq, s->chn[0].disabled = disabled; s->chn[1].disabled = disabled; - slavio_serial_io_memory = cpu_register_io_memory(0, escc_mem_read, + slavio_serial_io_memory = cpu_register_io_memory(escc_mem_read, escc_mem_write, s); cpu_register_physical_memory(base, ESCC_SIZE << it_shift, @@ -676,7 +676,7 @@ static void esp_init1(SysBusDevice *dev) s->dma_memory_write = qdev_get_prop_ptr(&dev->qdev, "dma_memory_write"); s->dma_opaque = qdev_get_prop_ptr(&dev->qdev, "dma_opaque"); - esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s); + esp_io_memory = cpu_register_io_memory(esp_mem_read, esp_mem_write, s); sysbus_init_mmio(dev, ESP_REGS << s->it_shift, esp_io_memory); esp_reset(s); diff --git a/hw/etraxfs_dma.c b/hw/etraxfs_dma.c index 1b65d0345..41175356e 100644 --- a/hw/etraxfs_dma.c +++ b/hw/etraxfs_dma.c @@ -750,7 +750,7 @@ void *etraxfs_dmac_init(target_phys_addr_t base, int nr_channels) ctrl->nr_channels = nr_channels; ctrl->channels = qemu_mallocz(sizeof ctrl->channels[0] * nr_channels); - ctrl->map = cpu_register_io_memory(0, dma_read, dma_write, ctrl); + ctrl->map = cpu_register_io_memory(dma_read, dma_write, ctrl); cpu_register_physical_memory(base, nr_channels * 0x2000, ctrl->map); return ctrl; } diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index 469be55a4..58f9f4e1f 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -587,7 +587,7 @@ void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr) tdk_init(ð->phy); mdio_attach(ð->mdio_bus, ð->phy, eth->phyaddr); - eth->ethregs = cpu_register_io_memory(0, eth_read, eth_write, eth); + eth->ethregs = cpu_register_io_memory(eth_read, eth_write, eth); cpu_register_physical_memory (base, 0x5c, eth->ethregs); eth->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c index 585e7850f..1c6742795 100644 --- a/hw/etraxfs_pic.c +++ b/hw/etraxfs_pic.c @@ -145,7 +145,7 @@ static void etraxfs_pic_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->parent_irq); sysbus_init_irq(dev, &s->parent_nmi); - intr_vect_regs = cpu_register_io_memory(0, pic_read, pic_write, s); + intr_vect_regs = cpu_register_io_memory(pic_read, pic_write, s); sysbus_init_mmio(dev, R_MAX * 4, intr_vect_regs); } diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c index e74d11a6f..7cb5e7188 100644 --- a/hw/etraxfs_ser.c +++ b/hw/etraxfs_ser.c @@ -171,7 +171,7 @@ static void etraxfs_ser_init(SysBusDevice *dev) s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE); sysbus_init_irq(dev, &s->irq); - ser_regs = cpu_register_io_memory(0, ser_read, ser_write, s); + ser_regs = cpu_register_io_memory(ser_read, ser_write, s); sysbus_init_mmio(dev, R_MAX * 4, ser_regs); s->chr = qdev_init_chardev(&dev->qdev); if (s->chr) diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c index 79eceb892..78fa810d2 100644 --- a/hw/etraxfs_timer.c +++ b/hw/etraxfs_timer.c @@ -323,7 +323,7 @@ static void etraxfs_timer_init(SysBusDevice *dev) sysbus_init_irq(dev, &t->irq); sysbus_init_irq(dev, &t->nmi); - timer_regs = cpu_register_io_memory(0, timer_read, timer_write, t); + timer_regs = cpu_register_io_memory(timer_read, timer_write, t); sysbus_init_mmio(dev, 0x5c, timer_regs); qemu_register_reset(etraxfs_timer_reset, 0, t); @@ -1902,7 +1902,7 @@ fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, fdctrl->sun4m = 0; if (mem_mapped) { - io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, + io_mem = cpu_register_io_memory(fdctrl_mem_read, fdctrl_mem_write, fdctrl); cpu_register_physical_memory(io_base, 0x08, io_mem); } else { @@ -1927,7 +1927,7 @@ fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base, fdctrl = fdctrl_init_common(irq, -1, io_base, fds); fdctrl->sun4m = 1; - io_mem = cpu_register_io_memory(0, fdctrl_mem_read_strict, + io_mem = cpu_register_io_memory(fdctrl_mem_read_strict, fdctrl_mem_write_strict, fdctrl); cpu_register_physical_memory(io_base, 0x08, io_mem); diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index 8ac0e9dd2..276c396bd 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -266,12 +266,12 @@ void *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, register_ioport_write(data_port, 1, 1, fw_cfg_io_writeb, s); } if (ctl_addr) { - io_ctl_memory = cpu_register_io_memory(0, fw_cfg_ctl_mem_read, + io_ctl_memory = cpu_register_io_memory(fw_cfg_ctl_mem_read, fw_cfg_ctl_mem_write, s); cpu_register_physical_memory(ctl_addr, FW_CFG_SIZE, io_ctl_memory); } if (data_addr) { - io_data_memory = cpu_register_io_memory(0, fw_cfg_data_mem_read, + io_data_memory = cpu_register_io_memory(fw_cfg_data_mem_read, fw_cfg_data_mem_write, s); cpu_register_physical_memory(data_addr, FW_CFG_SIZE, io_data_memory); } diff --git a/hw/g364fb.c b/hw/g364fb.c index b9bb31841..8afc603ef 100644 --- a/hw/g364fb.c +++ b/hw/g364fb.c @@ -608,7 +608,7 @@ int g364fb_mm_init(target_phys_addr_t vram_base, cpu_register_physical_memory(vram_base, s->vram_size, s->vram_offset); - io_ctrl = cpu_register_io_memory(0, g364fb_ctrl_read, g364fb_ctrl_write, s); + io_ctrl = cpu_register_io_memory(g364fb_ctrl_read, g364fb_ctrl_write, s); cpu_register_physical_memory(ctrl_base, 0x200000, io_ctrl); return 0; diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 581d1c5d6..f08dc01ff 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -137,9 +137,9 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic) pci_grackle_set_irq, pci_grackle_map_irq, pic, 0, 4); - pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, + pci_mem_config = cpu_register_io_memory(pci_grackle_config_read, pci_grackle_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_grackle_read, + pci_mem_data = cpu_register_io_memory(pci_grackle_read, pci_grackle_write, s); cpu_register_physical_memory(base, 0x1000, pci_mem_config); cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data); diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index ce3ffe26b..3b44fc9ef 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -1131,7 +1131,7 @@ PCIBus *pci_gt64120_init(qemu_irq *pic) s->pci->bus = pci_register_bus(NULL, "pci", pci_gt64120_set_irq, pci_gt64120_map_irq, pic, 144, 4); - s->ISD_handle = cpu_register_io_memory(0, gt64120_read, gt64120_write, s); + s->ISD_handle = cpu_register_io_memory(gt64120_read, gt64120_write, s); d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice), 0, gt64120_read_config, gt64120_write_config); diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c index 38ebe9990..5bee0ceb4 100644 --- a/hw/heathrow_pic.c +++ b/hw/heathrow_pic.c @@ -226,7 +226,7 @@ qemu_irq *heathrow_pic_init(int *pmem_index, s = qemu_mallocz(sizeof(HeathrowPICS)); /* only 1 CPU */ s->irqs = irqs[0]; - *pmem_index = cpu_register_io_memory(0, pic_read, pic_write, s); + *pmem_index = cpu_register_io_memory(pic_read, pic_write, s); register_savevm("heathrow_pic", -1, 1, heathrow_pic_save, heathrow_pic_load, s); @@ -582,7 +582,7 @@ void hpet_init(qemu_irq *irq) { register_savevm("hpet", -1, 1, hpet_save, hpet_load, s); qemu_register_reset(hpet_reset, 0, s); /* HPET Area */ - iomemtype = cpu_register_io_memory(0, hpet_ram_read, + iomemtype = cpu_register_io_memory(hpet_ram_read, hpet_ram_write, s); cpu_register_physical_memory(HPET_BASE, 0x400, iomemtype); } @@ -359,6 +359,7 @@ #define ASC_INCOMPATIBLE_FORMAT 0x30 #define ASC_MEDIUM_NOT_PRESENT 0x3a #define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 +#define ASC_MEDIA_REMOVAL_PREVENTED 0x53 #define CFA_NO_ERROR 0x00 #define CFA_MISC_ERROR 0x09 @@ -1822,18 +1823,27 @@ static void ide_atapi_cmd(IDEState *s) break; case GPCMD_START_STOP_UNIT: { - int start, eject; + int start, eject, err = 0; start = packet[4] & 1; eject = (packet[4] >> 1) & 1; - if (eject && !start) { - /* eject the disk */ - bdrv_eject(s->bs, 1); - } else if (eject && start) { - /* close the tray */ - bdrv_eject(s->bs, 0); + if (eject) { + err = bdrv_eject(s->bs, !start); + } + + switch (err) { + case 0: + ide_atapi_cmd_ok(s); + break; + case -EBUSY: + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIA_REMOVAL_PREVENTED); + break; + default: + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; } - ide_atapi_cmd_ok(s); } break; case GPCMD_MECHANISM_STATUS: @@ -3309,15 +3319,15 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, pci_conf[0x51] |= 0x08; /* enable IDE1 */ } - pci_register_io_region((PCIDevice *)d, 0, 0x8, + pci_register_bar((PCIDevice *)d, 0, 0x8, PCI_ADDRESS_SPACE_IO, ide_map); - pci_register_io_region((PCIDevice *)d, 1, 0x4, + pci_register_bar((PCIDevice *)d, 1, 0x4, PCI_ADDRESS_SPACE_IO, ide_map); - pci_register_io_region((PCIDevice *)d, 2, 0x8, + pci_register_bar((PCIDevice *)d, 2, 0x8, PCI_ADDRESS_SPACE_IO, ide_map); - pci_register_io_region((PCIDevice *)d, 3, 0x4, + pci_register_bar((PCIDevice *)d, 3, 0x4, PCI_ADDRESS_SPACE_IO, ide_map); - pci_register_io_region((PCIDevice *)d, 4, 0x10, + pci_register_bar((PCIDevice *)d, 4, 0x10, PCI_ADDRESS_SPACE_IO, bmdma_map); pci_conf[0x3d] = 0x01; // interrupt on pin 1 @@ -3376,7 +3386,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, qemu_register_reset(piix3_reset, 0, d); piix3_reset(d); - pci_register_io_region((PCIDevice *)d, 4, 0x10, + pci_register_bar((PCIDevice *)d, 4, 0x10, PCI_ADDRESS_SPACE_IO, bmdma_map); ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], pic[14]); @@ -3416,7 +3426,7 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, qemu_register_reset(piix3_reset, 0, d); piix3_reset(d); - pci_register_io_region((PCIDevice *)d, 4, 0x10, + pci_register_bar((PCIDevice *)d, 4, 0x10, PCI_ADDRESS_SPACE_IO, bmdma_map); ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], pic[14]); @@ -3751,7 +3761,7 @@ int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq, if (dbdma) DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d); - pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read, + pmac_ide_memory = cpu_register_io_memory(pmac_ide_read, pmac_ide_write, d); register_savevm("ide", 0, 1, pmac_ide_save, pmac_ide_load, d); qemu_register_reset(pmac_ide_reset, 0, d); @@ -3847,8 +3857,8 @@ void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2, s->dev = ide; s->shift = shift; - mem1 = cpu_register_io_memory(0, mmio_ide_reads, mmio_ide_writes, s); - mem2 = cpu_register_io_memory(0, mmio_ide_status, mmio_ide_cmd, s); + mem1 = cpu_register_io_memory(mmio_ide_reads, mmio_ide_writes, s); + mem2 = cpu_register_io_memory(mmio_ide_status, mmio_ide_cmd, s); cpu_register_physical_memory(membase, 16 << shift, mem1); cpu_register_physical_memory(membase2, 2 << shift, mem2); } diff --git a/hw/integratorcp.c b/hw/integratorcp.c index b6fbe1523..50eae0c34 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -256,7 +256,7 @@ static void integratorcm_init(SysBusDevice *dev) s->cm_init = 0x00000112; s->flash_offset = qemu_ram_alloc(0x100000); - iomemtype = cpu_register_io_memory(0, integratorcm_readfn, + iomemtype = cpu_register_io_memory(integratorcm_readfn, integratorcm_writefn, s); sysbus_init_mmio(dev, 0x00800000, iomemtype); integratorcm_do_remap(s, 1); @@ -381,7 +381,7 @@ static void icp_pic_init(SysBusDevice *dev) qdev_init_gpio_in(&dev->qdev, icp_pic_set_irq, 32); sysbus_init_irq(dev, &s->parent_irq); sysbus_init_irq(dev, &s->parent_fiq); - iomemtype = cpu_register_io_memory(0, icp_pic_readfn, + iomemtype = cpu_register_io_memory(icp_pic_readfn, icp_pic_writefn, s); sysbus_init_mmio(dev, 0x00800000, iomemtype); } @@ -433,7 +433,7 @@ static void icp_control_init(uint32_t base) { int iomemtype; - iomemtype = cpu_register_io_memory(0, icp_control_readfn, + iomemtype = cpu_register_io_memory(icp_control_readfn, icp_control_writefn, NULL); cpu_register_physical_memory(base, 0x00800000, iomemtype); /* ??? Save/restore. */ diff --git a/hw/ioapic.c b/hw/ioapic.c index 6c178c75e..a7a5ef9fd 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -326,7 +326,7 @@ IOAPICState *ioapic_init(void) s = qemu_mallocz(sizeof(IOAPICState)); ioapic_reset(s); - io_memory = cpu_register_io_memory(0, ioapic_mem_read, + io_memory = cpu_register_io_memory(ioapic_mem_read, ioapic_mem_write, s); cpu_register_physical_memory(0xfec00000, 0x1000, io_memory); diff --git a/hw/iommu.c b/hw/iommu.c index ae0c56d3e..694adbddd 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -375,7 +375,7 @@ void *iommu_init(target_phys_addr_t addr, uint32_t version, qemu_irq irq) s->version = version; s->irq = irq; - iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, + iommu_io_memory = cpu_register_io_memory(iommu_mem_read, iommu_mem_write, s); cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory); diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c index 351961120..1d5e8dc34 100644 --- a/hw/isa_mmio.c +++ b/hw/isa_mmio.c @@ -96,7 +96,7 @@ static int isa_mmio_iomemtype = 0; void isa_mmio_init(target_phys_addr_t base, target_phys_addr_t size) { if (!isa_mmio_iomemtype) { - isa_mmio_iomemtype = cpu_register_io_memory(0, isa_mmio_read, + isa_mmio_iomemtype = cpu_register_io_memory(isa_mmio_read, isa_mmio_write, NULL); } cpu_register_physical_memory(base, size, isa_mmio_iomemtype); diff --git a/hw/jazz_led.c b/hw/jazz_led.c index 8e2036985..9fdaf8f3c 100644 --- a/hw/jazz_led.c +++ b/hw/jazz_led.c @@ -307,7 +307,7 @@ void jazz_led_init(target_phys_addr_t base) s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND; - io = cpu_register_io_memory(0, led_read, led_write, s); + io = cpu_register_io_memory(led_read, led_write, s); cpu_register_physical_memory(base, 1, io); s->ds = graphic_console_init(jazz_led_update_display, diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 9b9f7614e..71f828116 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -262,6 +262,7 @@ typedef struct { uint32_t sbc; uint32_t csbc; uint32_t scratch[18]; /* SCRATCHA-SCRATCHR */ + uint8_t sbr; /* Script ram is stored as 32-bit words in host byteorder. */ uint32_t script_ram[2048]; @@ -330,6 +331,7 @@ static void lsi_soft_reset(LSIState *s) s->ia = 0; s->sbc = 0; s->csbc = 0; + s->sbr = 0; } static int lsi_dma_40bit(LSIState *s) @@ -1401,6 +1403,7 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset) CASE_GET_REG24(dbc, 0x24) case 0x27: /* DCMD */ return s->dcmd; + CASE_GET_REG32(dnad, 0x28) CASE_GET_REG32(dsp, 0x2c) CASE_GET_REG32(dsps, 0x30) CASE_GET_REG32(scratch[0], 0x34) @@ -1408,6 +1411,8 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset) return s->dmode; case 0x39: /* DIEN */ return s->dien; + case 0x3a: /* SBR */ + return s->sbr; case 0x3b: /* DCNTL */ return s->dcntl; case 0x40: /* SIEN0 */ @@ -1487,6 +1492,11 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset) static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) { +#define CASE_SET_REG24(name, addr) \ + case addr : s->name &= 0xffffff00; s->name |= val; break; \ + case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \ + case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; + #define CASE_SET_REG32(name, addr) \ case addr : s->name &= 0xffffff00; s->name |= val; break; \ case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \ @@ -1591,6 +1601,8 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) } s->ctest5 = val; break; + CASE_SET_REG24(dbc, 0x24) + CASE_SET_REG32(dnad, 0x28) case 0x2c: /* DSP[0:7] */ s->dsp &= 0xffffff00; s->dsp |= val; @@ -1622,6 +1634,9 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) s->dien = val; lsi_update_irq(s); break; + case 0x3a: /* SBR */ + s->sbr = val; + break; case 0x3b: /* DCNTL */ s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD); if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0) @@ -1701,6 +1716,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val); } } +#undef CASE_SET_REG24 #undef CASE_SET_REG32 } @@ -1998,16 +2014,16 @@ static void lsi_scsi_init(PCIDevice *dev) /* Interrupt pin 1 */ pci_conf[0x3d] = 0x01; - s->mmio_io_addr = cpu_register_io_memory(0, lsi_mmio_readfn, + s->mmio_io_addr = cpu_register_io_memory(lsi_mmio_readfn, lsi_mmio_writefn, s); - s->ram_io_addr = cpu_register_io_memory(0, lsi_ram_readfn, + s->ram_io_addr = cpu_register_io_memory(lsi_ram_readfn, lsi_ram_writefn, s); - pci_register_io_region((struct PCIDevice *)s, 0, 256, + pci_register_bar((struct PCIDevice *)s, 0, 256, PCI_ADDRESS_SPACE_IO, lsi_io_mapfunc); - pci_register_io_region((struct PCIDevice *)s, 1, 0x400, + pci_register_bar((struct PCIDevice *)s, 1, 0x400, PCI_ADDRESS_SPACE_MEM, lsi_mmio_mapfunc); - pci_register_io_region((struct PCIDevice *)s, 2, 0x2000, + pci_register_bar((struct PCIDevice *)s, 2, 0x2000, PCI_ADDRESS_SPACE_MEM, lsi_ram_mapfunc); s->queue = qemu_malloc(sizeof(lsi_queue)); s->queue_len = 1; diff --git a/hw/m48t59.c b/hw/m48t59.c index 480444320..455da3ddb 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -632,7 +632,7 @@ m48t59_t *m48t59_init (qemu_irq IRQ, target_phys_addr_t mem_base, register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s); } if (mem_base != 0) { - s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); + s->mem_index = cpu_register_io_memory(nvram_read, nvram_write, s); cpu_register_physical_memory(mem_base, size, s->mem_index); } if (type == 59) { diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index 75a9f177b..eeceb7db1 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -837,7 +837,7 @@ void* DBDMA_init (int *dbdma_mem_index) s = qemu_mallocz(sizeof(DBDMA_channel) * DBDMA_CHANNELS); - *dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, s); + *dbdma_mem_index = cpu_register_io_memory(dbdma_read, dbdma_write, s); register_savevm("dbdma", -1, 1, dbdma_save, dbdma_load, s); qemu_register_reset(dbdma_reset, 0, s); dbdma_reset(s); diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c index 1a1ca0d17..73011455e 100644 --- a/hw/mac_nvram.c +++ b/hw/mac_nvram.c @@ -138,7 +138,7 @@ MacIONVRAMState *macio_nvram_init (int *mem_index, target_phys_addr_t size, s->size = size; s->it_shift = it_shift; - s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); + s->mem_index = cpu_register_io_memory(nvram_read, nvram_write, s); *mem_index = s->mem_index; register_savevm("macio_nvram", -1, 1, macio_nvram_save, macio_nvram_load, s); diff --git a/hw/macio.c b/hw/macio.c index 28dbaa720..8cfadfc5e 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -114,6 +114,6 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index, d->config[0x3d] = 0x01; // interrupt on pin 1 - pci_register_io_region(d, 0, 0x80000, + pci_register_bar(d, 0, 0x80000, PCI_ADDRESS_SPACE_MEM, macio_map); } diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 8c446e186..d0597ac41 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -735,7 +735,7 @@ RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq, s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100; qemu_mod_timer(s->second_timer2, s->next_second_time); - io_memory = cpu_register_io_memory(0, rtc_mm_read, rtc_mm_write, s); + io_memory = cpu_register_io_memory(rtc_mm_read, rtc_mm_write, s); cpu_register_physical_memory(base, 2 << it_shift, io_memory); register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s); diff --git a/hw/mcf5206.c b/hw/mcf5206.c index b570376a4..049099efc 100644 --- a/hw/mcf5206.c +++ b/hw/mcf5206.c @@ -524,7 +524,7 @@ qemu_irq *mcf5206_init(uint32_t base, CPUState *env) int iomemtype; s = (m5206_mbar_state *)qemu_mallocz(sizeof(m5206_mbar_state)); - iomemtype = cpu_register_io_memory(0, m5206_mbar_readfn, + iomemtype = cpu_register_io_memory(m5206_mbar_readfn, m5206_mbar_writefn, s); cpu_register_physical_memory(base, 0x00001000, iomemtype); diff --git a/hw/mcf5208.c b/hw/mcf5208.c index 47a0f3eae..1ee9680cb 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -176,7 +176,7 @@ static void mcf5208_sys_init(qemu_irq *pic) QEMUBH *bh; int i; - iomemtype = cpu_register_io_memory(0, m5208_sys_readfn, + iomemtype = cpu_register_io_memory(m5208_sys_readfn, m5208_sys_writefn, NULL); /* SDRAMC. */ cpu_register_physical_memory(0xfc0a8000, 0x00004000, iomemtype); @@ -185,7 +185,7 @@ static void mcf5208_sys_init(qemu_irq *pic) s = (m5208_timer_state *)qemu_mallocz(sizeof(m5208_timer_state)); bh = qemu_bh_new(m5208_timer_trigger, s); s->timer = ptimer_init(bh); - iomemtype = cpu_register_io_memory(0, m5208_timer_readfn, + iomemtype = cpu_register_io_memory(m5208_timer_readfn, m5208_timer_writefn, s); cpu_register_physical_memory(0xfc080000 + 0x4000 * i, 0x00004000, iomemtype); diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 179ec19e0..1676bcb75 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -458,7 +458,7 @@ void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq) s = (mcf_fec_state *)qemu_mallocz(sizeof(mcf_fec_state)); s->irq = irq; - s->mmio_index = cpu_register_io_memory(0, mcf_fec_readfn, + s->mmio_index = cpu_register_io_memory(mcf_fec_readfn, mcf_fec_writefn, s); cpu_register_physical_memory(base, 0x400, s->mmio_index); diff --git a/hw/mcf_intc.c b/hw/mcf_intc.c index ce378c2f2..e2912804f 100644 --- a/hw/mcf_intc.c +++ b/hw/mcf_intc.c @@ -148,7 +148,7 @@ qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env) s->env = env; mcf_intc_reset(s); - iomemtype = cpu_register_io_memory(0, mcf_intc_readfn, + iomemtype = cpu_register_io_memory(mcf_intc_readfn, mcf_intc_writefn, s); cpu_register_physical_memory(base, 0x100, iomemtype); diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c index a65cc772c..8300fe832 100644 --- a/hw/mcf_uart.c +++ b/hw/mcf_uart.c @@ -303,7 +303,7 @@ void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq, int iomemtype; s = mcf_uart_init(irq, chr); - iomemtype = cpu_register_io_memory(0, mcf_uart_readfn, + iomemtype = cpu_register_io_memory(mcf_uart_readfn, mcf_uart_writefn, s); cpu_register_physical_memory(base, 0x40, iomemtype); } diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index e683421d8..2b4e1e057 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -181,7 +181,7 @@ void mips_jazz_init (ram_addr_t ram_size, /* Chipset */ rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas); - s_dma_dummy = cpu_register_io_memory(0, dma_dummy_read, dma_dummy_write, NULL); + s_dma_dummy = cpu_register_io_memory(dma_dummy_read, dma_dummy_write, NULL); cpu_register_physical_memory(0x8000d000, 0x00001000, s_dma_dummy); /* ISA devices */ @@ -245,7 +245,7 @@ void mips_jazz_init (ram_addr_t ram_size, /* Real time clock */ rtc_init(0x70, i8259[8], 1980); - s_rtc = cpu_register_io_memory(0, rtc_read, rtc_write, env); + s_rtc = cpu_register_io_memory(rtc_read, rtc_write, env); cpu_register_physical_memory(0x80004000, 0x00001000, s_rtc); /* Keyboard (i8042) */ diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 970da4e60..ed104f074 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -435,7 +435,7 @@ static MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, qemu_irq uart_ir s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState)); - malta = cpu_register_io_memory(0, malta_fpga_read, + malta = cpu_register_io_memory(malta_fpga_read, malta_fpga_write, s); cpu_register_physical_memory(base, 0x900, malta); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 71832d576..a2bdd363e 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -185,7 +185,7 @@ void mips_r4k_init (ram_addr_t ram_size, cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM); if (!mips_qemu_iomemtype) { - mips_qemu_iomemtype = cpu_register_io_memory(0, mips_qemu_read, + mips_qemu_iomemtype = cpu_register_io_memory(mips_qemu_read, mips_qemu_write, NULL); } cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype); diff --git a/hw/mpcore.c b/hw/mpcore.c index a5eddd9cc..907bd990f 100644 --- a/hw/mpcore.c +++ b/hw/mpcore.c @@ -268,7 +268,7 @@ static void mpcore_priv_init(SysBusDevice *dev) int i; gic_init(&s->gic); - s->iomemtype = cpu_register_io_memory(0, mpcore_priv_readfn, + s->iomemtype = cpu_register_io_memory(mpcore_priv_readfn, mpcore_priv_writefn, s); sysbus_init_mmio_cb(dev, 0x2000, mpcore_priv_map); for (i = 0; i < 8; i++) { diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c index 84eedb797..c77328f44 100644 --- a/hw/mst_fpga.c +++ b/hw/mst_fpga.c @@ -231,7 +231,7 @@ qemu_irq *mst_irq_init(PXA2xxState *cpu, uint32_t base, int irq) qi = qemu_allocate_irqs(mst_fpga_set_irq, s, MST_NUM_IRQS); s->pins = qi; - iomemtype = cpu_register_io_memory(0, mst_fpga_readfn, + iomemtype = cpu_register_io_memory(mst_fpga_readfn, mst_fpga_writefn, s); cpu_register_physical_memory(base, 0x00100000, iomemtype); register_savevm("mainstone_fpga", 0, 0, mst_fpga_save, mst_fpga_load, s); diff --git a/hw/musicpal.c b/hw/musicpal.c index 8c70a2bec..42fdf45db 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -437,7 +437,7 @@ static i2c_interface *musicpal_audio_init(qemu_irq irq) s->wm = i2c_create_slave(i2c->bus, "wm8750", MP_WM_ADDR); wm8750_data_req_set(s->wm, audio_callback, s); - iomemtype = cpu_register_io_memory(0, musicpal_audio_readfn, + iomemtype = cpu_register_io_memory(musicpal_audio_readfn, musicpal_audio_writefn, s); cpu_register_physical_memory(MP_AUDIO_BASE, MP_AUDIO_SIZE, iomemtype); @@ -756,7 +756,7 @@ static void mv88w8618_eth_init(SysBusDevice *dev) s->vc = qdev_get_vlan_client(&dev->qdev, eth_can_receive, eth_receive, NULL, eth_cleanup, s); - s->mmio_index = cpu_register_io_memory(0, mv88w8618_eth_readfn, + s->mmio_index = cpu_register_io_memory(mv88w8618_eth_readfn, mv88w8618_eth_writefn, s); sysbus_init_mmio(dev, MP_ETH_SIZE, s->mmio_index); } @@ -946,7 +946,7 @@ static void musicpal_lcd_init(SysBusDevice *dev) musicpal_lcd_state *s = FROM_SYSBUS(musicpal_lcd_state, dev); int iomemtype; - iomemtype = cpu_register_io_memory(0, musicpal_lcd_readfn, + iomemtype = cpu_register_io_memory(musicpal_lcd_readfn, musicpal_lcd_writefn, s); sysbus_init_mmio(dev, MP_LCD_SIZE, iomemtype); cpu_register_physical_memory(MP_LCD_BASE, MP_LCD_SIZE, iomemtype); @@ -1043,7 +1043,7 @@ static void mv88w8618_pic_init(SysBusDevice *dev) qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32); sysbus_init_irq(dev, &s->parent_irq); - iomemtype = cpu_register_io_memory(0, mv88w8618_pic_readfn, + iomemtype = cpu_register_io_memory(mv88w8618_pic_readfn, mv88w8618_pic_writefn, s); sysbus_init_mmio(dev, MP_PIC_SIZE, iomemtype); @@ -1167,7 +1167,7 @@ static void mv88w8618_pit_init(SysBusDevice *dev) mv88w8618_timer_init(dev, &s->timer[i], 1000000); } - iomemtype = cpu_register_io_memory(0, mv88w8618_pit_readfn, + iomemtype = cpu_register_io_memory(mv88w8618_pit_readfn, mv88w8618_pit_writefn, s); sysbus_init_mmio(dev, MP_PIT_SIZE, iomemtype); } @@ -1224,7 +1224,7 @@ static void mv88w8618_flashcfg_init(SysBusDevice *dev) mv88w8618_flashcfg_state *s = FROM_SYSBUS(mv88w8618_flashcfg_state, dev); s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */ - iomemtype = cpu_register_io_memory(0, mv88w8618_flashcfg_readfn, + iomemtype = cpu_register_io_memory(mv88w8618_flashcfg_readfn, mv88w8618_flashcfg_writefn, s); sysbus_init_mmio(dev, MP_FLASHCFG_SIZE, iomemtype); } @@ -1266,7 +1266,7 @@ static void musicpal_misc_init(void) { int iomemtype; - iomemtype = cpu_register_io_memory(0, musicpal_misc_readfn, + iomemtype = cpu_register_io_memory(musicpal_misc_readfn, musicpal_misc_writefn, NULL); cpu_register_physical_memory(MP_MISC_BASE, MP_MISC_SIZE, iomemtype); } @@ -1311,7 +1311,7 @@ static void mv88w8618_wlan_init(SysBusDevice *dev) { int iomemtype; - iomemtype = cpu_register_io_memory(0, mv88w8618_wlan_readfn, + iomemtype = cpu_register_io_memory(mv88w8618_wlan_readfn, mv88w8618_wlan_writefn, NULL); sysbus_init_mmio(dev, MP_WLAN_SIZE, iomemtype); } @@ -1412,7 +1412,7 @@ static void musicpal_gpio_init(void) { int iomemtype; - iomemtype = cpu_register_io_memory(0, musicpal_gpio_readfn, + iomemtype = cpu_register_io_memory(musicpal_gpio_readfn, musicpal_gpio_writefn, NULL); cpu_register_physical_memory(MP_GPIO_BASE, MP_GPIO_SIZE, iomemtype); } diff --git a/hw/ne2000.c b/hw/ne2000.c index f5ae9d739..66ae9ab03 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -816,7 +816,7 @@ static void pci_ne2000_init(PCIDevice *pci_dev) pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type pci_conf[0x3d] = 1; // interrupt pin 0 - pci_register_io_region(&d->dev, 0, 0x100, + pci_register_bar(&d->dev, 0, 0x100, PCI_ADDRESS_SPACE_IO, ne2000_map); s = &d->ne2000; s->irq = d->dev.irq[0]; @@ -1116,7 +1116,7 @@ static void io_writew(void *opaque, target_phys_addr_t addr, uint32_t value) static CPUReadMemoryFunc *io_readfn[] = { io_readb, io_readh, io_readw, }; static CPUWriteMemoryFunc *io_writefn[] = { io_writeb, io_writeh, io_writew, }; -inline static int debug_register_io_memory(int io_index, +inline static int debug_register_io_memory( CPUReadMemoryFunc **mem_read, CPUWriteMemoryFunc **mem_write, void *opaque) { @@ -1126,7 +1126,7 @@ inline static int debug_register_io_memory(int io_index, s->mem_write = mem_write; s->opaque = opaque; s->in = 0; - return cpu_register_io_memory(io_index, io_readfn, io_writefn, s); + return cpu_register_io_memory(io_readfn, io_writefn, s); } # define cpu_register_io_memory debug_register_io_memory # endif @@ -1136,7 +1136,7 @@ inline static int debug_register_io_memory(int io_index, # ifdef L4_MUX_HACK # undef l4_register_io_memory -int l4_register_io_memory(int io_index, CPUReadMemoryFunc **mem_read, +int l4_register_io_memory(CPUReadMemoryFunc **mem_read, CPUWriteMemoryFunc **mem_write, void *opaque); # endif diff --git a/hw/omap1.c b/hw/omap1.c index 4a479b45d..857677df1 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -425,7 +425,7 @@ struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, omap_inth_reset(s); - iomemtype = cpu_register_io_memory(0, omap_inth_readfn, + iomemtype = cpu_register_io_memory(omap_inth_readfn, omap_inth_writefn, s); cpu_register_physical_memory(base, size, iomemtype); @@ -645,7 +645,7 @@ struct omap_intr_handler_s *omap2_inth_init(target_phys_addr_t base, omap_inth_reset(s); - iomemtype = cpu_register_io_memory(0, omap2_inth_readfn, + iomemtype = cpu_register_io_memory(omap2_inth_readfn, omap2_inth_writefn, s); cpu_register_physical_memory(base, size, iomemtype); @@ -834,7 +834,7 @@ struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base, omap_mpu_timer_reset(s); omap_timer_clk_setup(s); - iomemtype = cpu_register_io_memory(0, omap_mpu_timer_readfn, + iomemtype = cpu_register_io_memory(omap_mpu_timer_readfn, omap_mpu_timer_writefn, s); cpu_register_physical_memory(base, 0x100, iomemtype); @@ -957,7 +957,7 @@ struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base, omap_wd_timer_reset(s); omap_timer_clk_setup(&s->timer); - iomemtype = cpu_register_io_memory(0, omap_wd_timer_readfn, + iomemtype = cpu_register_io_memory(omap_wd_timer_readfn, omap_wd_timer_writefn, s); cpu_register_physical_memory(base, 0x100, iomemtype); @@ -1059,7 +1059,7 @@ struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base, omap_os_timer_reset(s); omap_timer_clk_setup(&s->timer); - iomemtype = cpu_register_io_memory(0, omap_os_timer_readfn, + iomemtype = cpu_register_io_memory(omap_os_timer_readfn, omap_os_timer_writefn, s); cpu_register_physical_memory(base, 0x800, iomemtype); @@ -1286,7 +1286,7 @@ static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu) static void omap_ulpd_pm_init(target_phys_addr_t base, struct omap_mpu_state_s *mpu) { - int iomemtype = cpu_register_io_memory(0, omap_ulpd_pm_readfn, + int iomemtype = cpu_register_io_memory(omap_ulpd_pm_readfn, omap_ulpd_pm_writefn, mpu); cpu_register_physical_memory(base, 0x800, iomemtype); @@ -1501,7 +1501,7 @@ static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu) static void omap_pin_cfg_init(target_phys_addr_t base, struct omap_mpu_state_s *mpu) { - int iomemtype = cpu_register_io_memory(0, omap_pin_cfg_readfn, + int iomemtype = cpu_register_io_memory(omap_pin_cfg_readfn, omap_pin_cfg_writefn, mpu); cpu_register_physical_memory(base, 0x800, iomemtype); @@ -1571,7 +1571,7 @@ static CPUWriteMemoryFunc *omap_id_writefn[] = { static void omap_id_init(struct omap_mpu_state_s *mpu) { - int iomemtype = cpu_register_io_memory(0, omap_id_readfn, + int iomemtype = cpu_register_io_memory(omap_id_readfn, omap_id_writefn, mpu); cpu_register_physical_memory_offset(0xfffe1800, 0x800, iomemtype, 0xfffe1800); cpu_register_physical_memory_offset(0xfffed400, 0x100, iomemtype, 0xfffed400); @@ -1654,7 +1654,7 @@ static void omap_mpui_reset(struct omap_mpu_state_s *s) static void omap_mpui_init(target_phys_addr_t base, struct omap_mpu_state_s *mpu) { - int iomemtype = cpu_register_io_memory(0, omap_mpui_readfn, + int iomemtype = cpu_register_io_memory(omap_mpui_readfn, omap_mpui_writefn, mpu); cpu_register_physical_memory(base, 0x100, iomemtype); @@ -1763,7 +1763,7 @@ struct omap_tipb_bridge_s *omap_tipb_bridge_init(target_phys_addr_t base, s->abort = abort_irq; omap_tipb_bridge_reset(s); - iomemtype = cpu_register_io_memory(0, omap_tipb_bridge_readfn, + iomemtype = cpu_register_io_memory(omap_tipb_bridge_readfn, omap_tipb_bridge_writefn, s); cpu_register_physical_memory(base, 0x100, iomemtype); @@ -1869,7 +1869,7 @@ static void omap_tcmi_reset(struct omap_mpu_state_s *mpu) static void omap_tcmi_init(target_phys_addr_t base, struct omap_mpu_state_s *mpu) { - int iomemtype = cpu_register_io_memory(0, omap_tcmi_readfn, + int iomemtype = cpu_register_io_memory(omap_tcmi_readfn, omap_tcmi_writefn, mpu); cpu_register_physical_memory(base, 0x100, iomemtype); @@ -1942,7 +1942,7 @@ static void omap_dpll_reset(struct dpll_ctl_s *s) static void omap_dpll_init(struct dpll_ctl_s *s, target_phys_addr_t base, omap_clk clk) { - int iomemtype = cpu_register_io_memory(0, omap_dpll_readfn, + int iomemtype = cpu_register_io_memory(omap_dpll_readfn, omap_dpll_writefn, s); s->dpll = clk; @@ -2089,7 +2089,7 @@ struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta, target_phys_addr_t base = omap_l4_attach(ta, 0, 0); struct omap_uart_s *s = omap_uart_init(base, irq, fclk, iclk, txdma, rxdma, chr); - int iomemtype = cpu_register_io_memory(0, omap_uart_readfn, + int iomemtype = cpu_register_io_memory(omap_uart_readfn, omap_uart_writefn, s); s->ta = ta; @@ -2504,8 +2504,8 @@ static void omap_clkm_init(target_phys_addr_t mpu_base, target_phys_addr_t dsp_base, struct omap_mpu_state_s *s) { int iomemtype[2] = { - cpu_register_io_memory(0, omap_clkm_readfn, omap_clkm_writefn, s), - cpu_register_io_memory(0, omap_clkdsp_readfn, omap_clkdsp_writefn, s), + cpu_register_io_memory(omap_clkm_readfn, omap_clkm_writefn, s), + cpu_register_io_memory(omap_clkdsp_readfn, omap_clkdsp_writefn, s), }; s->clkm.arm_idlect1 = 0x03ff; @@ -2758,7 +2758,7 @@ struct omap_mpuio_s *omap_mpuio_init(target_phys_addr_t base, s->in = qemu_allocate_irqs(omap_mpuio_set, s, 16); omap_mpuio_reset(s); - iomemtype = cpu_register_io_memory(0, omap_mpuio_readfn, + iomemtype = cpu_register_io_memory(omap_mpuio_readfn, omap_mpuio_writefn, s); cpu_register_physical_memory(base, 0x800, iomemtype); @@ -2954,7 +2954,7 @@ struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base, s->in = qemu_allocate_irqs(omap_gpio_set, s, 16); omap_gpio_reset(s); - iomemtype = cpu_register_io_memory(0, omap_gpio_readfn, + iomemtype = cpu_register_io_memory(omap_gpio_readfn, omap_gpio_writefn, s); cpu_register_physical_memory(base, 0x1000, iomemtype); @@ -3124,7 +3124,7 @@ struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, s->txdrq = dma; omap_uwire_reset(s); - iomemtype = cpu_register_io_memory(0, omap_uwire_readfn, + iomemtype = cpu_register_io_memory(omap_uwire_readfn, omap_uwire_writefn, s); cpu_register_physical_memory(base, 0x800, iomemtype); @@ -3225,7 +3225,7 @@ static void omap_pwl_init(target_phys_addr_t base, struct omap_mpu_state_s *s, omap_pwl_reset(s); - iomemtype = cpu_register_io_memory(0, omap_pwl_readfn, + iomemtype = cpu_register_io_memory(omap_pwl_readfn, omap_pwl_writefn, s); cpu_register_physical_memory(base, 0x800, iomemtype); @@ -3320,7 +3320,7 @@ static void omap_pwt_init(target_phys_addr_t base, struct omap_mpu_state_s *s, s->pwt.clk = clk; omap_pwt_reset(s); - iomemtype = cpu_register_io_memory(0, omap_pwt_readfn, + iomemtype = cpu_register_io_memory(omap_pwt_readfn, omap_pwt_writefn, s); cpu_register_physical_memory(base, 0x800, iomemtype); } @@ -3743,7 +3743,7 @@ struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, omap_rtc_reset(s); - iomemtype = cpu_register_io_memory(0, omap_rtc_readfn, + iomemtype = cpu_register_io_memory(omap_rtc_readfn, omap_rtc_writefn, s); cpu_register_physical_memory(base, 0x800, iomemtype); @@ -4263,7 +4263,7 @@ struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, s->source_timer = qemu_new_timer(vm_clock, omap_mcbsp_source_tick, s); omap_mcbsp_reset(s); - iomemtype = cpu_register_io_memory(0, omap_mcbsp_readfn, + iomemtype = cpu_register_io_memory(omap_mcbsp_readfn, omap_mcbsp_writefn, s); cpu_register_physical_memory(base, 0x800, iomemtype); @@ -4435,7 +4435,7 @@ struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk) omap_lpg_reset(s); - iomemtype = cpu_register_io_memory(0, omap_lpg_readfn, + iomemtype = cpu_register_io_memory(omap_lpg_readfn, omap_lpg_writefn, s); cpu_register_physical_memory(base, 0x800, iomemtype); @@ -4468,7 +4468,7 @@ static CPUWriteMemoryFunc *omap_mpui_io_writefn[] = { static void omap_setup_mpui_io(struct omap_mpu_state_s *mpu) { - int iomemtype = cpu_register_io_memory(0, omap_mpui_io_readfn, + int iomemtype = cpu_register_io_memory(omap_mpui_io_readfn, omap_mpui_io_writefn, mpu); cpu_register_physical_memory(OMAP_MPUI_BASE, 0x7fff, iomemtype); } diff --git a/hw/omap2.c b/hw/omap2.c index 6fccca4a3..71483da37 100644 --- a/hw/omap2.c +++ b/hw/omap2.c @@ -483,7 +483,7 @@ struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta, omap_gp_timer_reset(s); omap_gp_timer_clk_setup(s); - iomemtype = l4_register_io_memory(0, omap_gp_timer_readfn, + iomemtype = l4_register_io_memory(omap_gp_timer_readfn, omap_gp_timer_writefn, s); omap_l4_attach(ta, 0, iomemtype); @@ -554,7 +554,7 @@ void omap_synctimer_init(struct omap_target_agent_s *ta, struct omap_synctimer_s *s = &mpu->synctimer; omap_synctimer_reset(s); - omap_l4_attach(ta, 0, l4_register_io_memory(0, + omap_l4_attach(ta, 0, l4_register_io_memory( omap_synctimer_readfn, omap_synctimer_writefn, s)); } @@ -952,7 +952,7 @@ static void omap_gpio_module_init(struct omap2_gpio_s *s, s->wkup = wkup; s->in = qemu_allocate_irqs(omap_gpio_module_set, s, 32); - iomemtype = l4_register_io_memory(0, omap_gpio_module_readfn, + iomemtype = l4_register_io_memory(omap_gpio_module_readfn, omap_gpio_module_writefn, s); omap_l4_attach(ta, region, iomemtype); } @@ -1060,7 +1060,7 @@ struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta, omap_gpif_reset(s); - iomemtype = l4_register_io_memory(0, omap_gpif_top_readfn, + iomemtype = l4_register_io_memory(omap_gpif_top_readfn, omap_gpif_top_writefn, s); omap_l4_attach(ta, 1, iomemtype); @@ -1386,7 +1386,7 @@ struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum, } omap_mcspi_reset(s); - iomemtype = l4_register_io_memory(0, omap_mcspi_readfn, + iomemtype = l4_register_io_memory(omap_mcspi_readfn, omap_mcspi_writefn, s); omap_l4_attach(ta, 0, iomemtype); @@ -1975,7 +1975,7 @@ struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta, #ifdef HAS_AUDIO AUD_register_card("OMAP EAC", &s->codec.card); - iomemtype = cpu_register_io_memory(0, omap_eac_readfn, + iomemtype = cpu_register_io_memory(omap_eac_readfn, omap_eac_writefn, s); omap_l4_attach(ta, 0, iomemtype); #endif @@ -2160,11 +2160,11 @@ static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta, s->chr = chr ?: qemu_chr_open("null", "null", NULL); - iomemtype = l4_register_io_memory(0, omap_sti_readfn, + iomemtype = l4_register_io_memory(omap_sti_readfn, omap_sti_writefn, s); omap_l4_attach(ta, 0, iomemtype); - iomemtype = cpu_register_io_memory(0, omap_sti_fifo_readfn, + iomemtype = cpu_register_io_memory(omap_sti_fifo_readfn, omap_sti_fifo_writefn, s); cpu_register_physical_memory(channel_base, 0x10000, iomemtype); @@ -2204,7 +2204,7 @@ static CPUWriteMemoryFunc **omap_l4_io_writeh_fn; static CPUWriteMemoryFunc **omap_l4_io_writew_fn; static void **omap_l4_io_opaque; -int l4_register_io_memory(int io_index, CPUReadMemoryFunc **mem_read, +int l4_register_io_memory(CPUReadMemoryFunc **mem_read, CPUWriteMemoryFunc **mem_write, void *opaque) { omap_l4_io_entry[omap_l4_io_entries].mem_read = mem_read; @@ -2285,7 +2285,7 @@ struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num) omap_l4_io_entry = qemu_mallocz(125 * sizeof(*omap_l4_io_entry)); omap_cpu_io_entry = - cpu_register_io_memory(0, omap_l4_io_readfn, + cpu_register_io_memory(omap_l4_io_readfn, omap_l4_io_writefn, bus); # define L4_PAGES (0xb4000 / TARGET_PAGE_SIZE) omap_l4_io_readb_fn = qemu_mallocz(sizeof(void *) * L4_PAGES); @@ -2578,7 +2578,7 @@ struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus, int cs) ta->status = 0x00000000; ta->control = 0x00000200; /* XXX 01000200 for L4TAO */ - iomemtype = l4_register_io_memory(0, omap_l4ta_readfn, + iomemtype = l4_register_io_memory(omap_l4ta_readfn, omap_l4ta_writefn, ta); ta->base = omap_l4_attach(ta, info->ta_region, iomemtype); @@ -2708,7 +2708,7 @@ static CPUWriteMemoryFunc *omap_tap_writefn[] = { void omap_tap_init(struct omap_target_agent_s *ta, struct omap_mpu_state_s *mpu) { - omap_l4_attach(ta, 0, l4_register_io_memory(0, + omap_l4_attach(ta, 0, l4_register_io_memory( omap_tap_readfn, omap_tap_writefn, mpu)); } @@ -3521,7 +3521,7 @@ struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta, s->mpu = mpu; omap_prcm_coldreset(s); - iomemtype = l4_register_io_memory(0, omap_prcm_readfn, + iomemtype = l4_register_io_memory(omap_prcm_readfn, omap_prcm_writefn, s); omap_l4_attach(ta, 0, iomemtype); omap_l4_attach(ta, 1, iomemtype); @@ -3891,7 +3891,7 @@ struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta, s->mpu = mpu; omap_sysctl_reset(s); - iomemtype = l4_register_io_memory(0, omap_sysctl_readfn, + iomemtype = l4_register_io_memory(omap_sysctl_readfn, omap_sysctl_writefn, s); omap_l4_attach(ta, 0, iomemtype); @@ -4035,7 +4035,7 @@ struct omap_sdrc_s *omap_sdrc_init(target_phys_addr_t base) omap_sdrc_reset(s); - iomemtype = cpu_register_io_memory(0, omap_sdrc_readfn, + iomemtype = cpu_register_io_memory(omap_sdrc_readfn, omap_sdrc_writefn, s); cpu_register_physical_memory(base, 0x1000, iomemtype); @@ -4409,7 +4409,7 @@ struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq) omap_gpmc_reset(s); - iomemtype = cpu_register_io_memory(0, omap_gpmc_readfn, + iomemtype = cpu_register_io_memory(omap_gpmc_readfn, omap_gpmc_writefn, s); cpu_register_physical_memory(base, 0x1000, iomemtype); diff --git a/hw/omap_dma.c b/hw/omap_dma.c index 6df38002a..e31a14b83 100644 --- a/hw/omap_dma.c +++ b/hw/omap_dma.c @@ -1655,7 +1655,7 @@ struct soc_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs, omap_dma_reset(s->dma); omap_dma_clk_update(s, 0, 1); - iomemtype = cpu_register_io_memory(0, omap_dma_readfn, + iomemtype = cpu_register_io_memory(omap_dma_readfn, omap_dma_writefn, s); cpu_register_physical_memory(base, memsize, iomemtype); @@ -2062,7 +2062,7 @@ struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs, omap_dma_reset(s->dma); omap_dma_clk_update(s, 0, !!s->dma->freq); - iomemtype = cpu_register_io_memory(0, omap_dma4_readfn, + iomemtype = cpu_register_io_memory(omap_dma4_readfn, omap_dma4_writefn, s); cpu_register_physical_memory(base, 0x1000, iomemtype); diff --git a/hw/omap_dss.c b/hw/omap_dss.c index d8c2977b6..c69b91b9d 100644 --- a/hw/omap_dss.c +++ b/hw/omap_dss.c @@ -1037,15 +1037,15 @@ struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta, s->drq = drq; omap_dss_reset(s); - iomemtype[0] = l4_register_io_memory(0, omap_diss1_readfn, + iomemtype[0] = l4_register_io_memory(omap_diss1_readfn, omap_diss1_writefn, s); - iomemtype[1] = l4_register_io_memory(0, omap_disc1_readfn, + iomemtype[1] = l4_register_io_memory(omap_disc1_readfn, omap_disc1_writefn, s); - iomemtype[2] = l4_register_io_memory(0, omap_rfbi1_readfn, + iomemtype[2] = l4_register_io_memory(omap_rfbi1_readfn, omap_rfbi1_writefn, s); - iomemtype[3] = l4_register_io_memory(0, omap_venc1_readfn, + iomemtype[3] = l4_register_io_memory(omap_venc1_readfn, omap_venc1_writefn, s); - iomemtype[4] = cpu_register_io_memory(0, omap_im3_readfn, + iomemtype[4] = cpu_register_io_memory(omap_im3_readfn, omap_im3_writefn, s); omap_l4_attach(ta, 0, iomemtype[0]); omap_l4_attach(ta, 1, iomemtype[1]); diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c index c0dd3a549..60da5745c 100644 --- a/hw/omap_i2c.c +++ b/hw/omap_i2c.c @@ -436,7 +436,7 @@ struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base, s->bus = i2c_init_bus(NULL, "i2c"); omap_i2c_reset(s); - iomemtype = cpu_register_io_memory(0, omap_i2c_readfn, + iomemtype = cpu_register_io_memory(omap_i2c_readfn, omap_i2c_writefn, s); cpu_register_physical_memory(base, 0x800, iomemtype); @@ -457,7 +457,7 @@ struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta, s->bus = i2c_init_bus(NULL, "i2c"); omap_i2c_reset(s); - iomemtype = l4_register_io_memory(0, omap_i2c_readfn, + iomemtype = l4_register_io_memory(omap_i2c_readfn, omap_i2c_writefn, s); omap_l4_attach(ta, 0, iomemtype); diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c index 6a91b27d4..5458f2ab1 100644 --- a/hw/omap_lcdc.c +++ b/hw/omap_lcdc.c @@ -450,7 +450,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq, s->emiff_base = emiff_base; omap_lcdc_reset(s); - iomemtype = cpu_register_io_memory(0, omap_lcdc_readfn, + iomemtype = cpu_register_io_memory(omap_lcdc_readfn, omap_lcdc_writefn, s); cpu_register_physical_memory(base, 0x100, iomemtype); diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c index 81c003cd2..93dbff612 100644 --- a/hw/omap_mmc.c +++ b/hw/omap_mmc.c @@ -586,7 +586,7 @@ struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base, omap_mmc_reset(s); - iomemtype = cpu_register_io_memory(0, omap_mmc_readfn, + iomemtype = cpu_register_io_memory(omap_mmc_readfn, omap_mmc_writefn, s); cpu_register_physical_memory(base, 0x800, iomemtype); @@ -612,7 +612,7 @@ struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta, omap_mmc_reset(s); - iomemtype = l4_register_io_memory(0, omap_mmc_readfn, + iomemtype = l4_register_io_memory(omap_mmc_readfn, omap_mmc_writefn, s); omap_l4_attach(ta, 0, iomemtype); diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c index ee8e39d7c..0f6ed9ef6 100644 --- a/hw/omap_sx1.c +++ b/hw/omap_sx1.c @@ -142,12 +142,12 @@ static void sx1_init(ram_addr_t ram_size, cpu_register_physical_memory(OMAP_CS0_BASE, flash_size, (phys_flash = qemu_ram_alloc(flash_size)) | IO_MEM_ROM); - io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs0val); + io = cpu_register_io_memory(static_readfn, static_writefn, &cs0val); cpu_register_physical_memory(OMAP_CS0_BASE + flash_size, OMAP_CS0_SIZE - flash_size, io); - io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs2val); + io = cpu_register_io_memory(static_readfn, static_writefn, &cs2val); cpu_register_physical_memory(OMAP_CS2_BASE, OMAP_CS2_SIZE, io); - io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs3val); + io = cpu_register_io_memory(static_readfn, static_writefn, &cs3val); cpu_register_physical_memory(OMAP_CS3_BASE, OMAP_CS3_SIZE, io); fl_idx = 0; @@ -167,7 +167,7 @@ static void sx1_init(ram_addr_t ram_size, cpu_register_physical_memory(OMAP_CS1_BASE, flash1_size, (phys_flash = qemu_ram_alloc(flash1_size)) | IO_MEM_ROM); - io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs1val); + io = cpu_register_io_memory(static_readfn, static_writefn, &cs1val); cpu_register_physical_memory(OMAP_CS1_BASE + flash1_size, OMAP_CS1_SIZE - flash1_size, io); @@ -179,7 +179,7 @@ static void sx1_init(ram_addr_t ram_size, } fl_idx++; } else { - io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs1val); + io = cpu_register_io_memory(static_readfn, static_writefn, &cs1val); cpu_register_physical_memory(OMAP_CS1_BASE, OMAP_CS1_SIZE, io); } diff --git a/hw/onenand.c b/hw/onenand.c index 9803a0723..7388e7c79 100644 --- a/hw/onenand.c +++ b/hw/onenand.c @@ -631,7 +631,7 @@ void *onenand_init(uint32_t id, int regshift, qemu_irq irq) s->secs = size >> 9; s->blockwp = qemu_malloc(s->blocks); s->density_mask = (id & (1 << 11)) ? (1 << (6 + ((id >> 12) & 7))) : 0; - s->iomemtype = cpu_register_io_memory(0, onenand_readfn, + s->iomemtype = cpu_register_io_memory(onenand_readfn, onenand_writefn, s); if (bdrv_index == -1) s->image = memset(qemu_malloc(size + (size >> 5)), diff --git a/hw/openpic.c b/hw/openpic.c index 51c8ad827..9742d54ac 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -1046,7 +1046,7 @@ static void openpic_map(PCIDevice *pci_dev, int region_num, addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU); cpu_register_physical_memory(addr, 0x40000, opp->mem_index); #if 0 // Don't implement ISU for now - opp_io_memory = cpu_register_io_memory(0, openpic_src_read, + opp_io_memory = cpu_register_io_memory(openpic_src_read, openpic_src_write); cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2), opp_io_memory); @@ -1212,12 +1212,12 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, pci_conf[0x3d] = 0x00; // no interrupt pin /* Register I/O spaces */ - pci_register_io_region((PCIDevice *)opp, 0, 0x40000, + pci_register_bar((PCIDevice *)opp, 0, 0x40000, PCI_ADDRESS_SPACE_MEM, &openpic_map); } else { opp = qemu_mallocz(sizeof(openpic_t)); } - opp->mem_index = cpu_register_io_memory(0, openpic_read, + opp->mem_index = cpu_register_io_memory(openpic_read, openpic_write, opp); // isu_base &= 0xFFFC0000; @@ -1687,7 +1687,7 @@ qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus, for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) { int mem_index; - mem_index = cpu_register_io_memory(0, list[i].read, list[i].write, mpp); + mem_index = cpu_register_io_memory(list[i].read, list[i].write, mpp); if (mem_index < 0) { goto free; } @@ -216,14 +216,14 @@ static void palmte_init(ram_addr_t ram_size, cpu_register_physical_memory(OMAP_CS0_BASE, flash_size, (phys_flash = qemu_ram_alloc(flash_size)) | IO_MEM_ROM); - io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs0val); + io = cpu_register_io_memory(static_readfn, static_writefn, &cs0val); cpu_register_physical_memory(OMAP_CS0_BASE + flash_size, OMAP_CS0_SIZE - flash_size, io); - io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs1val); + io = cpu_register_io_memory(static_readfn, static_writefn, &cs1val); cpu_register_physical_memory(OMAP_CS1_BASE, OMAP_CS1_SIZE, io); - io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs2val); + io = cpu_register_io_memory(static_readfn, static_writefn, &cs2val); cpu_register_physical_memory(OMAP_CS2_BASE, OMAP_CS2_SIZE, io); - io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs3val); + io = cpu_register_io_memory(static_readfn, static_writefn, &cs3val); cpu_register_physical_memory(OMAP_CS3_BASE, OMAP_CS3_SIZE, io); palmte_microwire_setup(cpu); diff --git a/hw/parallel.c b/hw/parallel.c index f66e5eb7e..a23686a46 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -543,7 +543,7 @@ ParallelState *parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq parallel_reset(s); qemu_register_reset(parallel_reset, 0, s); - io_sw = cpu_register_io_memory(0, parallel_mm_read_sw, parallel_mm_write_sw, s); + io_sw = cpu_register_io_memory(parallel_mm_read_sw, parallel_mm_write_sw, s); cpu_register_physical_memory(base, 8 << it_shift, io_sw); return s; } diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index 705abfb55..271d80010 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -123,7 +123,6 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, PCIBus *pci_bus, break; case IF_VIRTIO: opaque = pci_create_simple(pci_bus, -1, "virtio-blk-pci"); - qdev_init(opaque); break; } @@ -379,7 +379,7 @@ int pci_unregister_device(PCIDevice *pci_dev, int assigned) return 0; } -void pci_register_io_region(PCIDevice *pci_dev, int region_num, +void pci_register_bar(PCIDevice *pci_dev, int region_num, uint32_t size, int type, PCIMapIORegionFunc *map_func) { @@ -197,7 +197,7 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name, PCIConfigWriteFunc *config_write); int pci_unregister_device(PCIDevice *pci_dev, int assigned); -void pci_register_io_region(PCIDevice *pci_dev, int region_num, +void pci_register_bar(PCIDevice *pci_dev, int region_num, uint32_t size, int type, PCIMapIORegionFunc *map_func); diff --git a/hw/pci_ids.h b/hw/pci_ids.h index 427fcd510..3afe6748f 100644 --- a/hw/pci_ids.h +++ b/hw/pci_ids.h @@ -35,6 +35,8 @@ #define PCI_CLASS_BRIDGE_PCI 0x0604 #define PCI_CLASS_BRIDGE_OTHER 0x0680 +#define PCI_CLASS_COMMUNICATION_OTHER 0x0780 + #define PCI_CLASS_PROCESSOR_CO 0x0b40 #define PCI_CLASS_PROCESSOR_POWERPC 0x0b20 diff --git a/hw/pckbd.c b/hw/pckbd.c index 3ef359484..092d1ba5c 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -430,7 +430,7 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, kbd_reset(s); register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s); - s_io_memory = cpu_register_io_memory(0, kbd_mm_read, kbd_mm_write, s); + s_io_memory = cpu_register_io_memory(kbd_mm_read, kbd_mm_write, s); cpu_register_physical_memory(base, size, s_io_memory); s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); diff --git a/hw/pcnet.c b/hw/pcnet.c index b5793ff24..a184146e0 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -2048,12 +2048,12 @@ static void pci_pcnet_init(PCIDevice *pci_dev) /* Handler for memory-mapped I/O */ s->mmio_index = - cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, &d->state); + cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state); - pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE, + pci_register_bar((PCIDevice *)d, 0, PCNET_IOPORT_SIZE, PCI_ADDRESS_SPACE_IO, pcnet_ioport_map); - pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, + pci_register_bar((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map); s->irq = pci_dev->irq[0]; @@ -2126,7 +2126,7 @@ static void lance_init(SysBusDevice *dev) PCNetState *s = &d->state; s->mmio_index = - cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d); + cpu_register_io_memory(lance_mem_read, lance_mem_write, d); s->dma_opaque = qdev_get_prop_ptr(&dev->qdev, "dma"); diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index d696560ac..53ed97e64 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -522,7 +522,7 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off, /* FIXME: Allocate ram ourselves. */ pfl->storage = qemu_get_ram_ptr(off); - pfl->fl_mem = cpu_register_io_memory(0, + pfl->fl_mem = cpu_register_io_memory( pflash_read_ops, pflash_write_ops, pfl); pfl->off = off; cpu_register_physical_memory(base, total_len, diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 60edbf5d2..4b963643b 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -559,7 +559,7 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off, pfl = qemu_mallocz(sizeof(pflash_t)); /* FIXME: Allocate ram ourselves. */ pfl->storage = qemu_get_ram_ptr(off); - pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops, + pfl->fl_mem = cpu_register_io_memory(pflash_read_ops, pflash_write_ops, pfl); pfl->off = off; pfl->base = base; diff --git a/hw/pl011.c b/hw/pl011.c index 3a1a4cbd9..0528bfe7d 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -291,7 +291,7 @@ static void pl011_init(SysBusDevice *dev, const unsigned char *id) int iomemtype; pl011_state *s = FROM_SYSBUS(pl011_state, dev); - iomemtype = cpu_register_io_memory(0, pl011_readfn, + iomemtype = cpu_register_io_memory(pl011_readfn, pl011_writefn, s); sysbus_init_mmio(dev, 0x1000,iomemtype); sysbus_init_irq(dev, &s->irq); diff --git a/hw/pl022.c b/hw/pl022.c index 27cb7aff6..78076e087 100644 --- a/hw/pl022.c +++ b/hw/pl022.c @@ -293,7 +293,7 @@ static void pl022_init(SysBusDevice *dev) pl022_state *s = FROM_SYSBUS(pl022_state, dev); int iomemtype; - iomemtype = cpu_register_io_memory(0, pl022_readfn, + iomemtype = cpu_register_io_memory(pl022_readfn, pl022_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); sysbus_init_irq(dev, &s->irq); diff --git a/hw/pl031.c b/hw/pl031.c index 11ecf7328..5c9992edf 100644 --- a/hw/pl031.c +++ b/hw/pl031.c @@ -189,7 +189,7 @@ static void pl031_init(SysBusDevice *dev) pl031_state *s = FROM_SYSBUS(pl031_state, dev); struct tm tm; - iomemtype = cpu_register_io_memory(0, pl031_readfn, pl031_writefn, s); + iomemtype = cpu_register_io_memory(pl031_readfn, pl031_writefn, s); if (iomemtype == -1) { hw_error("pl031_init: Can't register I/O memory\n"); } diff --git a/hw/pl050.c b/hw/pl050.c index 1f8878c21..c8818e0dc 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -127,7 +127,7 @@ static void pl050_init(SysBusDevice *dev, int is_mouse) pl050_state *s = FROM_SYSBUS(pl050_state, dev); int iomemtype; - iomemtype = cpu_register_io_memory(0, pl050_readfn, + iomemtype = cpu_register_io_memory(pl050_readfn, pl050_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); sysbus_init_irq(dev, &s->irq); diff --git a/hw/pl061.c b/hw/pl061.c index aa0a32223..a003b97ab 100644 --- a/hw/pl061.c +++ b/hw/pl061.c @@ -296,7 +296,7 @@ static void pl061_init(SysBusDevice *dev) int iomemtype; pl061_state *s = FROM_SYSBUS(pl061_state, dev); - iomemtype = cpu_register_io_memory(0, pl061_readfn, + iomemtype = cpu_register_io_memory(pl061_readfn, pl061_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); sysbus_init_irq(dev, &s->irq); diff --git a/hw/pl080.c b/hw/pl080.c index e43b11df7..9c17be683 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -324,7 +324,7 @@ static void pl08x_init(SysBusDevice *dev, int nchannels) int iomemtype; pl080_state *s = FROM_SYSBUS(pl080_state, dev); - iomemtype = cpu_register_io_memory(0, pl080_readfn, + iomemtype = cpu_register_io_memory(pl080_readfn, pl080_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); sysbus_init_irq(dev, &s->irq); diff --git a/hw/pl110.c b/hw/pl110.c index b45204c63..45b7dbeb9 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -354,7 +354,7 @@ static void pl110_init(SysBusDevice *dev) pl110_state *s = FROM_SYSBUS(pl110_state, dev); int iomemtype; - iomemtype = cpu_register_io_memory(0, pl110_readfn, + iomemtype = cpu_register_io_memory(pl110_readfn, pl110_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); sysbus_init_irq(dev, &s->irq); diff --git a/hw/pl181.c b/hw/pl181.c index 2ba7f28e3..12f4ca79a 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -451,7 +451,7 @@ static void pl181_init(SysBusDevice *dev) pl181_state *s = FROM_SYSBUS(pl181_state, dev); BlockDriverState *bd; - iomemtype = cpu_register_io_memory(0, pl181_readfn, + iomemtype = cpu_register_io_memory(pl181_readfn, pl181_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); sysbus_init_irq(dev, &s->irq[0]); diff --git a/hw/pl190.c b/hw/pl190.c index 10857683d..f68fb4252 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -232,7 +232,7 @@ static void pl190_init(SysBusDevice *dev) pl190_state *s = FROM_SYSBUS(pl190_state, dev); int iomemtype; - iomemtype = cpu_register_io_memory(0, pl190_readfn, + iomemtype = cpu_register_io_memory(pl190_readfn, pl190_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); qdev_init_gpio_in(&dev->qdev, pl190_set_irq, 32); diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index 0dec1317e..2ab170e70 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -161,7 +161,7 @@ static void ref405ep_fpga_init (uint32_t base) int fpga_memory; fpga = qemu_mallocz(sizeof(ref405ep_fpga_t)); - fpga_memory = cpu_register_io_memory(0, ref405ep_fpga_read, + fpga_memory = cpu_register_io_memory(ref405ep_fpga_read, ref405ep_fpga_write, fpga); cpu_register_physical_memory(base, 0x00000100, fpga_memory); ref405ep_fpga_reset(fpga); @@ -485,7 +485,7 @@ static void taihu_cpld_init (uint32_t base) int cpld_memory; cpld = qemu_mallocz(sizeof(taihu_cpld_t)); - cpld_memory = cpu_register_io_memory(0, taihu_cpld_read, + cpld_memory = cpu_register_io_memory(taihu_cpld_read, taihu_cpld_write, cpld); cpu_register_physical_memory(base, 0x00000100, cpld_memory); taihu_cpld_reset(cpld); diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index 5c8d2734a..81bab8e96 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -247,7 +247,7 @@ ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base) mmio = qemu_mallocz(sizeof(ppc4xx_mmio_t)); mmio->base = base; - mmio_memory = cpu_register_io_memory(0, mmio_read, mmio_write, mmio); + mmio_memory = cpu_register_io_memory(mmio_read, mmio_write, mmio); #if defined(DEBUG_MMIO) printf("%s: base " PADDRX " len %08x %d\n", __func__, base, TARGET_PAGE_SIZE, mmio_memory); diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c index 45ab3be21..516fce955 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -384,14 +384,14 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4], pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER); /* CFGADDR */ - index = cpu_register_io_memory(0, pci4xx_cfgaddr_read, + index = cpu_register_io_memory(pci4xx_cfgaddr_read, pci4xx_cfgaddr_write, controller); if (index < 0) goto free; cpu_register_physical_memory(config_space + PCIC0_CFGADDR, 4, index); /* CFGDATA */ - index = cpu_register_io_memory(0, pci4xx_cfgdata_read, + index = cpu_register_io_memory(pci4xx_cfgdata_read, pci4xx_cfgdata_write, &controller->pci_state); if (index < 0) @@ -399,7 +399,7 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4], cpu_register_physical_memory(config_space + PCIC0_CFGDATA, 4, index); /* Internal registers */ - index = cpu_register_io_memory(0, pci_reg_read, pci_reg_write, controller); + index = cpu_register_io_memory(pci_reg_read, pci_reg_write, controller); if (index < 0) goto free; cpu_register_physical_memory(registers, PCI_REG_SIZE, index); diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index f0d167dbd..22beedb87 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -246,7 +246,7 @@ static void ppc_core99_init (ram_addr_t ram_size, isa_mmio_init(0xf2000000, 0x00800000); /* UniN init */ - unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL); + unin_memory = cpu_register_io_memory(unin_read, unin_write, NULL); cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory); openpic_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *)); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 2d308f3cc..83f2ecad6 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -659,7 +659,7 @@ static void ppc_prep_init (ram_addr_t ram_size, pci_bus = pci_prep_init(i8259); // pci_bus = i440fx_init(); /* Register 8 MB of ISA IO space (needed for non-contiguous map) */ - PPC_io_memory = cpu_register_io_memory(0, PPC_prep_io_read, + PPC_io_memory = cpu_register_io_memory(PPC_prep_io_read, PPC_prep_io_write, sysctrl); cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory); @@ -728,12 +728,12 @@ static void ppc_prep_init (ram_addr_t ram_size, register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, sysctrl); register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl); /* PCI intack location */ - PPC_io_memory = cpu_register_io_memory(0, PPC_intack_read, + PPC_io_memory = cpu_register_io_memory(PPC_intack_read, PPC_intack_write, NULL); cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); /* PowerPC control and status register group */ #if 0 - PPC_io_memory = cpu_register_io_memory(0, PPC_XCSR_read, PPC_XCSR_write, + PPC_io_memory = cpu_register_io_memory(PPC_XCSR_read, PPC_XCSR_write, NULL); cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory); #endif diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 79703a3ff..1a8a6c995 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -332,21 +332,21 @@ PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers) controller->pci_dev = d; /* CFGADDR */ - index = cpu_register_io_memory(0, pcie500_cfgaddr_read, + index = cpu_register_io_memory(pcie500_cfgaddr_read, pcie500_cfgaddr_write, controller); if (index < 0) goto free; cpu_register_physical_memory(registers + PCIE500_CFGADDR, 4, index); /* CFGDATA */ - index = cpu_register_io_memory(0, pcie500_cfgdata_read, + index = cpu_register_io_memory(pcie500_cfgdata_read, pcie500_cfgdata_write, &controller->pci_state); if (index < 0) goto free; cpu_register_physical_memory(registers + PCIE500_CFGDATA, 4, index); - index = cpu_register_io_memory(0, e500_pci_reg_read, + index = cpu_register_io_memory(e500_pci_reg_read, e500_pci_reg_write, controller); if (index < 0) goto free; diff --git a/hw/prep_pci.c b/hw/prep_pci.c index e747e3972..80058b16c 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -149,7 +149,7 @@ PCIBus *pci_prep_init(qemu_irq *pic) register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s); register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s); - PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, + PPC_io_memory = cpu_register_io_memory(PPC_PCIIO_read, PPC_PCIIO_write, s); cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory); diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index e001d1fc7..f2e98ffc2 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -857,7 +857,7 @@ static void pxa2xx_ssp_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); - iomemtype = cpu_register_io_memory(0, pxa2xx_ssp_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_ssp_readfn, pxa2xx_ssp_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); register_savevm("pxa2xx_ssp", -1, 0, @@ -1509,7 +1509,7 @@ PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base, s->bus = i2c_init_bus(NULL, "i2c"); s->offset = base - (base & (~region_size) & TARGET_PAGE_MASK); - iomemtype = cpu_register_io_memory(0, pxa2xx_i2c_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_i2c_readfn, pxa2xx_i2c_writefn, s); cpu_register_physical_memory(base & ~region_size, region_size + 1, iomemtype); @@ -1747,7 +1747,7 @@ static PXA2xxI2SState *pxa2xx_i2s_init(target_phys_addr_t base, pxa2xx_i2s_reset(s); - iomemtype = cpu_register_io_memory(0, pxa2xx_i2s_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_i2s_readfn, pxa2xx_i2s_writefn, s); cpu_register_physical_memory(base, 0x100000, iomemtype); @@ -2006,7 +2006,7 @@ static PXA2xxFIrState *pxa2xx_fir_init(target_phys_addr_t base, pxa2xx_fir_reset(s); - iomemtype = cpu_register_io_memory(0, pxa2xx_fir_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_fir_readfn, pxa2xx_fir_writefn, s); cpu_register_physical_memory(base, 0x1000, iomemtype); @@ -2090,7 +2090,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision) s->cm_base = 0x41300000; s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */ s->clkcfg = 0x00000009; /* Turbo mode active */ - iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn, pxa2xx_cm_writefn, s); cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype); register_savevm("pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s); @@ -2101,13 +2101,13 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision) s->mm_regs[MDMRS >> 2] = 0x00020002; s->mm_regs[MDREFR >> 2] = 0x03ca4000; s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */ - iomemtype = cpu_register_io_memory(0, pxa2xx_mm_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn, pxa2xx_mm_writefn, s); cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype); register_savevm("pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s); s->pm_base = 0x40f00000; - iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn, pxa2xx_pm_writefn, s); cpu_register_physical_memory(s->pm_base, 0x100, iomemtype); register_savevm("pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s); @@ -2129,7 +2129,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision) s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000); s->rtc_base = 0x40900000; - iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_rtc_readfn, pxa2xx_rtc_writefn, s); cpu_register_physical_memory(s->rtc_base, 0x1000, iomemtype); pxa2xx_rtc_init(s); @@ -2202,7 +2202,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size) s->cm_base = 0x41300000; s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */ s->clkcfg = 0x00000009; /* Turbo mode active */ - iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_cm_readfn, pxa2xx_cm_writefn, s); cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype); register_savevm("pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s); @@ -2213,13 +2213,13 @@ PXA2xxState *pxa255_init(unsigned int sdram_size) s->mm_regs[MDMRS >> 2] = 0x00020002; s->mm_regs[MDREFR >> 2] = 0x03ca4000; s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */ - iomemtype = cpu_register_io_memory(0, pxa2xx_mm_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_mm_readfn, pxa2xx_mm_writefn, s); cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype); register_savevm("pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s); s->pm_base = 0x40f00000; - iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_pm_readfn, pxa2xx_pm_writefn, s); cpu_register_physical_memory(s->pm_base, 0x100, iomemtype); register_savevm("pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s); @@ -2241,7 +2241,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size) s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000); s->rtc_base = 0x40900000; - iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_rtc_readfn, pxa2xx_rtc_writefn, s); cpu_register_physical_memory(s->rtc_base, 0x1000, iomemtype); pxa2xx_rtc_init(s); diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index 0b350a203..f0351c476 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -503,7 +503,7 @@ static PXA2xxDMAState *pxa2xx_dma_init(target_phys_addr_t base, memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS); - iomemtype = cpu_register_io_memory(0, pxa2xx_dma_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_dma_readfn, pxa2xx_dma_writefn, s); cpu_register_physical_memory(base, 0x00010000, iomemtype); diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 9749cb791..27f72ecff 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -308,7 +308,7 @@ PXA2xxGPIOInfo *pxa2xx_gpio_init(target_phys_addr_t base, s->cpu_env = env; s->in = qemu_allocate_irqs(pxa2xx_gpio_set, s, lines); - iomemtype = cpu_register_io_memory(0, pxa2xx_gpio_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_gpio_readfn, pxa2xx_gpio_writefn, s); cpu_register_physical_memory(base, 0x00001000, iomemtype); diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c index 07f8d20a3..80dcb5815 100644 --- a/hw/pxa2xx_keypad.c +++ b/hw/pxa2xx_keypad.c @@ -313,7 +313,7 @@ PXA2xxKeyPadState *pxa27x_keypad_init(target_phys_addr_t base, s = (PXA2xxKeyPadState *) qemu_mallocz(sizeof(PXA2xxKeyPadState)); s->irq = irq; - iomemtype = cpu_register_io_memory(0, pxa2xx_keypad_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_keypad_readfn, pxa2xx_keypad_writefn, s); cpu_register_physical_memory(base, 0x00100000, iomemtype); diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index 12bfc1303..c9fefc319 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -928,7 +928,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq) pxa2xx_lcdc_orientation(s, graphic_rotate); - iomemtype = cpu_register_io_memory(0, pxa2xx_lcdc_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_lcdc_readfn, pxa2xx_lcdc_writefn, s); cpu_register_physical_memory(base, 0x00100000, iomemtype); diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c index 8ce28f726..4c306cf4e 100644 --- a/hw/pxa2xx_mmci.c +++ b/hw/pxa2xx_mmci.c @@ -527,7 +527,7 @@ PXA2xxMMCIState *pxa2xx_mmci_init(target_phys_addr_t base, s->irq = irq; s->dma = dma; - iomemtype = cpu_register_io_memory(0, pxa2xx_mmci_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_mmci_readfn, pxa2xx_mmci_writefn, s); cpu_register_physical_memory(base, 0x00100000, iomemtype); diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c index 6e9c956e7..cb13a2638 100644 --- a/hw/pxa2xx_pcmcia.c +++ b/hw/pxa2xx_pcmcia.c @@ -139,19 +139,19 @@ PXA2xxPCMCIAState *pxa2xx_pcmcia_init(target_phys_addr_t base) qemu_mallocz(sizeof(PXA2xxPCMCIAState)); /* Socket I/O Memory Space */ - iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_io_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_pcmcia_io_readfn, pxa2xx_pcmcia_io_writefn, s); cpu_register_physical_memory(base | 0x00000000, 0x04000000, iomemtype); /* Then next 64 MB is reserved */ /* Socket Attribute Memory Space */ - iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_attr_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_pcmcia_attr_readfn, pxa2xx_pcmcia_attr_writefn, s); cpu_register_physical_memory(base | 0x08000000, 0x04000000, iomemtype); /* Socket Common Memory Space */ - iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_common_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_pcmcia_common_readfn, pxa2xx_pcmcia_common_writefn, s); cpu_register_physical_memory(base | 0x0c000000, 0x04000000, iomemtype); diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c index aa17ba37f..a4d56d816 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -299,7 +299,7 @@ qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env) qi = qemu_allocate_irqs(pxa2xx_pic_set_irq, s, PXA2XX_PIC_SRCS); /* Enable IC memory-mapped registers access. */ - iomemtype = cpu_register_io_memory(0, pxa2xx_pic_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_pic_readfn, pxa2xx_pic_writefn, s); cpu_register_physical_memory(base, 0x00100000, iomemtype); diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index 3725dd1ed..4d47e4ddf 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -451,7 +451,7 @@ static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base, pxa2xx_timer_tick, &s->timer[i]); } - iomemtype = cpu_register_io_memory(0, pxa2xx_timer_readfn, + iomemtype = cpu_register_io_memory(pxa2xx_timer_readfn, pxa2xx_timer_writefn, s); cpu_register_physical_memory(base, 0x00001000, iomemtype); @@ -176,7 +176,7 @@ static qemu_irq *r2d_fpga_init(target_phys_addr_t base, qemu_irq irl) s->irl = irl; - iomemtype = cpu_register_io_memory(0, r2d_fpga_readfn, + iomemtype = cpu_register_io_memory(r2d_fpga_readfn, r2d_fpga_writefn, s); cpu_register_physical_memory(base, 0x40, iomemtype); return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS); diff --git a/hw/rc4030.c b/hw/rc4030.c index a35360ab5..40610c061 100644 --- a/hw/rc4030.c +++ b/hw/rc4030.c @@ -814,9 +814,9 @@ void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus, register_savevm("rc4030", 0, 2, rc4030_save, rc4030_load, s); rc4030_reset(s); - s_chipset = cpu_register_io_memory(0, rc4030_read, rc4030_write, s); + s_chipset = cpu_register_io_memory(rc4030_read, rc4030_write, s); cpu_register_physical_memory(0x80000000, 0x300, s_chipset); - s_jazzio = cpu_register_io_memory(0, jazzio_read, jazzio_write, s); + s_jazzio = cpu_register_io_memory(jazzio_read, jazzio_write, s); cpu_register_physical_memory(0xf0000000, 0x00001000, s_jazzio); return s; diff --git a/hw/realview_gic.c b/hw/realview_gic.c index cae0f7ee7..089d94c55 100644 --- a/hw/realview_gic.c +++ b/hw/realview_gic.c @@ -63,7 +63,7 @@ static void realview_gic_init(SysBusDevice *dev) RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev); gic_init(&s->gic); - s->iomemtype = cpu_register_io_memory(0, realview_gic_cpu_readfn, + s->iomemtype = cpu_register_io_memory(realview_gic_cpu_readfn, realview_gic_cpu_writefn, s); sysbus_init_mmio_cb(dev, 0x2000, realview_gic_map); } diff --git a/hw/rtl8139.c b/hw/rtl8139.c index de5a68fc9..13646062d 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3469,12 +3469,12 @@ static void pci_rtl8139_init(PCIDevice *dev) /* I/O handler for memory-mapped I/O */ s->rtl8139_mmio_io_addr = - cpu_register_io_memory(0, rtl8139_mmio_read, rtl8139_mmio_write, s); + cpu_register_io_memory(rtl8139_mmio_read, rtl8139_mmio_write, s); - pci_register_io_region(&d->dev, 0, 0x100, + pci_register_bar(&d->dev, 0, 0x100, PCI_ADDRESS_SPACE_IO, rtl8139_ioport_map); - pci_register_io_region(&d->dev, 1, 0x100, + pci_register_bar(&d->dev, 1, 0x100, PCI_ADDRESS_SPACE_MEM, rtl8139_mmio_map); s->pci_dev = (PCIDevice *)d; @@ -151,7 +151,7 @@ void *sbi_init(target_phys_addr_t addr, qemu_irq **irq, qemu_irq **cpu_irq, s->cpu_irqs[i] = parent_irq[i]; } - sbi_io_memory = cpu_register_io_memory(0, sbi_mem_read, sbi_mem_write, s); + sbi_io_memory = cpu_register_io_memory(sbi_mem_read, sbi_mem_write, s); cpu_register_physical_memory(addr, SBI_SIZE, sbi_io_memory); register_savevm("sbi", addr, 1, sbi_save, sbi_load, s); diff --git a/hw/serial.c b/hw/serial.c index 71f545d86..b255ea90e 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -831,7 +831,7 @@ SerialState *serial_mm_init (target_phys_addr_t base, int it_shift, register_savevm("serial", base, 3, serial_save, serial_load, s); if (ioregister) { - s_io_memory = cpu_register_io_memory(0, serial_mm_read, + s_io_memory = cpu_register_io_memory(serial_mm_read, serial_mm_write, s); cpu_register_physical_memory(base, 8 << it_shift, s_io_memory); } diff --git a/hw/sh7750.c b/hw/sh7750.c index f079781b2..ac1cc01d4 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -709,8 +709,7 @@ SH7750State *sh7750_init(CPUSH4State * cpu) s = qemu_mallocz(sizeof(SH7750State)); s->cpu = cpu; s->periph_freq = 60000000; /* 60MHz */ - sh7750_io_memory = cpu_register_io_memory(0, - sh7750_mem_read, + sh7750_io_memory = cpu_register_io_memory(sh7750_mem_read, sh7750_mem_write, s); cpu_register_physical_memory_offset(0x1f000000, 0x1000, sh7750_io_memory, 0x1f000000); @@ -725,8 +724,7 @@ SH7750State *sh7750_init(CPUSH4State * cpu) cpu_register_physical_memory_offset(0xffc00000, 0x1000, sh7750_io_memory, 0x1fc00000); - sh7750_mm_cache_and_tlb = cpu_register_io_memory(0, - sh7750_mmct_read, + sh7750_mm_cache_and_tlb = cpu_register_io_memory(sh7750_mmct_read, sh7750_mmct_write, s); cpu_register_physical_memory(0xf0000000, 0x08000000, sh7750_mm_cache_and_tlb); diff --git a/hw/sh_intc.c b/hw/sh_intc.c index b75d794e1..9938160a0 100644 --- a/hw/sh_intc.c +++ b/hw/sh_intc.c @@ -442,7 +442,7 @@ int sh_intc_init(struct intc_desc *desc, desc->irqs = qemu_allocate_irqs(sh_intc_set_irq, desc, nr_sources); - desc->iomemtype = cpu_register_io_memory(0, sh_intc_readfn, + desc->iomemtype = cpu_register_io_memory(sh_intc_readfn, sh_intc_writefn, desc); if (desc->mask_regs) { for (i = 0; i < desc->nr_mask_regs; i++) { diff --git a/hw/sh_pci.c b/hw/sh_pci.c index 2ec4b43bd..1b148ab39 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -179,9 +179,9 @@ PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, p->dev = pci_register_device(p->bus, "SH PCIC", sizeof(PCIDevice), -1, NULL, NULL); - reg = cpu_register_io_memory(0, sh_pci_reg.r, sh_pci_reg.w, p); - iop = cpu_register_io_memory(0, sh_pci_iop.r, sh_pci_iop.w, p); - mem = cpu_register_io_memory(0, sh_pci_mem.r, sh_pci_mem.w, p); + reg = cpu_register_io_memory(sh_pci_reg.r, sh_pci_reg.w, p); + iop = cpu_register_io_memory(sh_pci_iop.r, sh_pci_iop.w, p); + mem = cpu_register_io_memory(sh_pci_mem.r, sh_pci_mem.w, p); cpu_register_physical_memory(0x1e200000, 0x224, reg); cpu_register_physical_memory(0x1e240000, 0x40000, iop); cpu_register_physical_memory(0x1d000000, 0x1000000, mem); diff --git a/hw/sh_serial.c b/hw/sh_serial.c index ee0c52c42..ddf63d52f 100644 --- a/hw/sh_serial.c +++ b/hw/sh_serial.c @@ -394,7 +394,7 @@ void sh_serial_init (target_phys_addr_t base, int feat, sh_serial_clear_fifo(s); - s_io_memory = cpu_register_io_memory(0, sh_serial_readfn, + s_io_memory = cpu_register_io_memory(sh_serial_readfn, sh_serial_writefn, s); cpu_register_physical_memory(P4ADDR(base), 0x28, s_io_memory); cpu_register_physical_memory(A7ADDR(base), 0x28, s_io_memory); diff --git a/hw/sh_timer.c b/hw/sh_timer.c index 1a1404c22..5b9c90339 100644 --- a/hw/sh_timer.c +++ b/hw/sh_timer.c @@ -318,7 +318,7 @@ void tmu012_init(target_phys_addr_t base, int feat, uint32_t freq, if (feat & TMU012_FEAT_3CHAN) s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT, ch2_irq0); /* ch2_irq1 not supported */ - iomemtype = cpu_register_io_memory(0, tmu012_readfn, + iomemtype = cpu_register_io_memory(tmu012_readfn, tmu012_writefn, s); cpu_register_physical_memory(P4ADDR(base), 0x00001000, iomemtype); cpu_register_physical_memory(A7ADDR(base), 0x00001000, iomemtype); diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index e39e4f975..a2f085fef 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -388,8 +388,7 @@ void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, slave->cpu = i; slave->master = s; - slavio_intctl_io_memory = cpu_register_io_memory(0, - slavio_intctl_mem_read, + slavio_intctl_io_memory = cpu_register_io_memory(slavio_intctl_mem_read, slavio_intctl_mem_write, slave); cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_SIZE, @@ -399,8 +398,7 @@ void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, s->cpu_irqs[i] = parent_irq[i]; } - slavio_intctlm_io_memory = cpu_register_io_memory(0, - slavio_intctlm_mem_read, + slavio_intctlm_io_memory = cpu_register_io_memory(slavio_intctlm_mem_read, slavio_intctlm_mem_write, s); cpu_register_physical_memory(addrg, INTCTLM_SIZE, slavio_intctlm_io_memory); diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index f335863b1..170dc1029 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -448,28 +448,28 @@ void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, /* 8 bit registers */ // Slavio control - io = cpu_register_io_memory(0, slavio_cfg_mem_read, + io = cpu_register_io_memory(slavio_cfg_mem_read, slavio_cfg_mem_write, s); cpu_register_physical_memory(base + MISC_CFG, MISC_SIZE, io); // Diagnostics - io = cpu_register_io_memory(0, slavio_diag_mem_read, + io = cpu_register_io_memory(slavio_diag_mem_read, slavio_diag_mem_write, s); cpu_register_physical_memory(base + MISC_DIAG, MISC_SIZE, io); // Modem control - io = cpu_register_io_memory(0, slavio_mdm_mem_read, + io = cpu_register_io_memory(slavio_mdm_mem_read, slavio_mdm_mem_write, s); cpu_register_physical_memory(base + MISC_MDM, MISC_SIZE, io); /* 16 bit registers */ - io = cpu_register_io_memory(0, slavio_led_mem_read, + io = cpu_register_io_memory(slavio_led_mem_read, slavio_led_mem_write, s); /* ss600mp diag LEDs */ cpu_register_physical_memory(base + MISC_LEDS, MISC_SIZE, io); /* 32 bit registers */ - io = cpu_register_io_memory(0, slavio_sysctrl_mem_read, + io = cpu_register_io_memory(slavio_sysctrl_mem_read, slavio_sysctrl_mem_write, s); // System control cpu_register_physical_memory(base + MISC_SYS, SYSCTRL_SIZE, io); @@ -477,21 +477,21 @@ void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, // AUX 1 (Misc System Functions) if (aux1_base) { - io = cpu_register_io_memory(0, slavio_aux1_mem_read, + io = cpu_register_io_memory(slavio_aux1_mem_read, slavio_aux1_mem_write, s); cpu_register_physical_memory(aux1_base, MISC_SIZE, io); } // AUX 2 (Software Powerdown Control) if (aux2_base) { - io = cpu_register_io_memory(0, slavio_aux2_mem_read, + io = cpu_register_io_memory(slavio_aux2_mem_read, slavio_aux2_mem_write, s); cpu_register_physical_memory(aux2_base, MISC_SIZE, io); } // Power management (APC) XXX: not a Slavio device if (power_base) { - io = cpu_register_io_memory(0, apc_mem_read, apc_mem_write, s); + io = cpu_register_io_memory(apc_mem_read, apc_mem_write, s); cpu_register_physical_memory(power_base, MISC_SIZE, io); } diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index b5f9ec32a..08dc5ffab 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -381,7 +381,7 @@ static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr, ptimer_set_period(s->timer, TIMER_PERIOD); } - slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, + slavio_timer_io_memory = cpu_register_io_memory(slavio_timer_mem_read, slavio_timer_mem_write, s); if (master) cpu_register_physical_memory(addr, CPU_TIMER_SIZE, diff --git a/hw/sm501.c b/hw/sm501.c index 4b0df8fec..df40aaa1f 100644 --- a/hw/sm501.c +++ b/hw/sm501.c @@ -1080,11 +1080,11 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq, /* map mmio */ sm501_system_config_index - = cpu_register_io_memory(0, sm501_system_config_readfn, + = cpu_register_io_memory(sm501_system_config_readfn, sm501_system_config_writefn, s); cpu_register_physical_memory(base + MMIO_BASE_OFFSET, 0x6c, sm501_system_config_index); - sm501_disp_ctrl_index = cpu_register_io_memory(0, sm501_disp_ctrl_readfn, + sm501_disp_ctrl_index = cpu_register_io_memory(sm501_disp_ctrl_readfn, sm501_disp_ctrl_writefn, s); cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_DC, 0x1000, sm501_disp_ctrl_index); diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 93a1fae0d..cf8d864e5 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -704,7 +704,7 @@ static void smc91c111_init1(SysBusDevice *dev) { smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev); - s->mmio_index = cpu_register_io_memory(0, smc91c111_readfn, + s->mmio_index = cpu_register_io_memory(smc91c111_readfn, smc91c111_writefn, s); sysbus_init_mmio(dev, 16, s->mmio_index); sysbus_init_irq(dev, &s->irq); diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index 6893b888b..ce027cc7f 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -252,7 +252,7 @@ void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq, s->irq = parent_irq; s->iommu = iommu; - dma_io_memory = cpu_register_io_memory(0, dma_mem_read, dma_mem_write, s); + dma_io_memory = cpu_register_io_memory(dma_mem_read, dma_mem_write, s); cpu_register_physical_memory(daddr, DMA_SIZE, dma_io_memory); register_savevm("sparc32_dma", daddr, 2, dma_save, dma_load, s); diff --git a/hw/spitz.c b/hw/spitz.c index 4da70609f..d9ff85eac 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -174,7 +174,7 @@ static void sl_flash_register(PXA2xxState *cpu, int size) else if (size == FLASH_1024M) s->nand = nand_init(NAND_MFR_SAMSUNG, 0xf1); - iomemtype = cpu_register_io_memory(0, sl_readfn, + iomemtype = cpu_register_io_memory(sl_readfn, sl_writefn, s); cpu_register_physical_memory(FLASH_BASE, 0x40, iomemtype); diff --git a/hw/stellaris.c b/hw/stellaris.c index bf339e8aa..5f44bff5d 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -347,7 +347,7 @@ static void stellaris_gptm_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); qdev_init_gpio_out(&dev->qdev, &s->trigger, 1); - iomemtype = cpu_register_io_memory(0, gptm_readfn, + iomemtype = cpu_register_io_memory(gptm_readfn, gptm_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); @@ -668,7 +668,7 @@ static void stellaris_sys_init(uint32_t base, qemu_irq irq, s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16); s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16); - iomemtype = cpu_register_io_memory(0, ssys_readfn, + iomemtype = cpu_register_io_memory(ssys_readfn, ssys_writefn, s); cpu_register_physical_memory(base, 0x00001000, iomemtype); ssys_reset(s); @@ -880,7 +880,7 @@ static void stellaris_i2c_init(SysBusDevice * dev) bus = i2c_init_bus(&dev->qdev, "i2c"); s->bus = bus; - iomemtype = cpu_register_io_memory(0, stellaris_i2c_readfn, + iomemtype = cpu_register_io_memory(stellaris_i2c_readfn, stellaris_i2c_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); /* ??? For now we only implement the master interface. */ @@ -1188,7 +1188,7 @@ static void stellaris_adc_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq[n]); } - iomemtype = cpu_register_io_memory(0, stellaris_adc_readfn, + iomemtype = cpu_register_io_memory(stellaris_adc_readfn, stellaris_adc_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); stellaris_adc_reset(s); diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 8586db612..43fa30543 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -400,7 +400,7 @@ static void stellaris_enet_init(SysBusDevice *dev) { stellaris_enet_state *s = FROM_SYSBUS(stellaris_enet_state, dev); - s->mmio_index = cpu_register_io_memory(0, stellaris_enet_readfn, + s->mmio_index = cpu_register_io_memory(stellaris_enet_readfn, stellaris_enet_writefn, s); sysbus_init_mmio(dev, 0x1000, s->mmio_index); sysbus_init_irq(dev, &s->irq); diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c index 8978e48aa..caad6611d 100644 --- a/hw/sun4c_intctl.c +++ b/hw/sun4c_intctl.c @@ -205,7 +205,7 @@ void *sun4c_intctl_init(target_phys_addr_t addr, qemu_irq **irq, s = qemu_mallocz(sizeof(Sun4c_INTCTLState)); - sun4c_intctl_io_memory = cpu_register_io_memory(0, sun4c_intctl_mem_read, + sun4c_intctl_io_memory = cpu_register_io_memory(sun4c_intctl_mem_read, sun4c_intctl_mem_write, s); cpu_register_physical_memory(addr, INTCTL_SIZE, sun4c_intctl_io_memory); s->cpu_irqs = parent_irq; diff --git a/hw/sun4u.c b/hw/sun4u.c index 7d020182f..e6bdcb2bc 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -320,9 +320,9 @@ pci_ebus_init(PCIBus *bus, int devfn) s->config[0x0D] = 0x0a; // latency_timer s->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type - pci_register_io_region(s, 0, 0x1000000, PCI_ADDRESS_SPACE_MEM, + pci_register_bar(s, 0, 0x1000000, PCI_ADDRESS_SPACE_MEM, ebus_mmio_mapfunc); - pci_register_io_region(s, 1, 0x800000, PCI_ADDRESS_SPACE_MEM, + pci_register_bar(s, 1, 0x800000, PCI_ADDRESS_SPACE_MEM, ebus_mmio_mapfunc); } diff --git a/hw/syborg_fb.c b/hw/syborg_fb.c index 90254e44f..42c62744c 100644 --- a/hw/syborg_fb.c +++ b/hw/syborg_fb.c @@ -511,7 +511,7 @@ static void syborg_fb_init(SysBusDevice *dev) int height; sysbus_init_irq(dev, &s->irq); - iomemtype = cpu_register_io_memory(0, syborg_fb_readfn, + iomemtype = cpu_register_io_memory(syborg_fb_readfn, syborg_fb_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); diff --git a/hw/syborg_interrupt.c b/hw/syborg_interrupt.c index 29e0d1a74..569c7f61c 100644 --- a/hw/syborg_interrupt.c +++ b/hw/syborg_interrupt.c @@ -210,7 +210,7 @@ static void syborg_int_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->parent_irq); s->num_irqs = qdev_get_prop_int(&dev->qdev, "num-interrupts", 64); qdev_init_gpio_in(&dev->qdev, syborg_int_set_irq, s->num_irqs); - iomemtype = cpu_register_io_memory(0, syborg_int_readfn, + iomemtype = cpu_register_io_memory(syborg_int_readfn, syborg_int_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); s->flags = qemu_mallocz(s->num_irqs * sizeof(syborg_int_flags)); diff --git a/hw/syborg_keyboard.c b/hw/syborg_keyboard.c index 69976e4dd..84a099ed0 100644 --- a/hw/syborg_keyboard.c +++ b/hw/syborg_keyboard.c @@ -209,7 +209,7 @@ static void syborg_keyboard_init(SysBusDevice *dev) int iomemtype; sysbus_init_irq(dev, &s->irq); - iomemtype = cpu_register_io_memory(0, syborg_keyboard_readfn, + iomemtype = cpu_register_io_memory(syborg_keyboard_readfn, syborg_keyboard_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); s->fifo_size = qdev_get_prop_int(&dev->qdev, "fifo-size", 16); diff --git a/hw/syborg_pointer.c b/hw/syborg_pointer.c index e5a72d3cd..e0a892d00 100644 --- a/hw/syborg_pointer.c +++ b/hw/syborg_pointer.c @@ -205,7 +205,7 @@ static void syborg_pointer_init(SysBusDevice *dev) int iomemtype; sysbus_init_irq(dev, &s->irq); - iomemtype = cpu_register_io_memory(0, syborg_pointer_readfn, + iomemtype = cpu_register_io_memory(syborg_pointer_readfn, syborg_pointer_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); diff --git a/hw/syborg_rtc.c b/hw/syborg_rtc.c index b480d5348..48853f7f9 100644 --- a/hw/syborg_rtc.c +++ b/hw/syborg_rtc.c @@ -129,7 +129,7 @@ static void syborg_rtc_init(SysBusDevice *dev) struct tm tm; int iomemtype; - iomemtype = cpu_register_io_memory(0, syborg_rtc_readfn, + iomemtype = cpu_register_io_memory(syborg_rtc_readfn, syborg_rtc_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); diff --git a/hw/syborg_serial.c b/hw/syborg_serial.c index 48f11e98a..f43050801 100644 --- a/hw/syborg_serial.c +++ b/hw/syborg_serial.c @@ -321,7 +321,7 @@ static void syborg_serial_init(SysBusDevice *dev) int iomemtype; sysbus_init_irq(dev, &s->irq); - iomemtype = cpu_register_io_memory(0, syborg_serial_readfn, + iomemtype = cpu_register_io_memory(syborg_serial_readfn, syborg_serial_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); s->chr = qdev_init_chardev(&dev->qdev); diff --git a/hw/syborg_timer.c b/hw/syborg_timer.c index b6d7f0cd4..4f5e3a178 100644 --- a/hw/syborg_timer.c +++ b/hw/syborg_timer.c @@ -215,7 +215,7 @@ static void syborg_timer_init(SysBusDevice *dev) exit(1); } sysbus_init_irq(dev, &s->irq); - iomemtype = cpu_register_io_memory(0, syborg_timer_readfn, + iomemtype = cpu_register_io_memory(syborg_timer_readfn, syborg_timer_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); diff --git a/hw/syborg_virtio.c b/hw/syborg_virtio.c index 37c219cda..8e665c6f2 100644 --- a/hw/syborg_virtio.c +++ b/hw/syborg_virtio.c @@ -249,7 +249,7 @@ static void syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev) proxy->vdev = vdev; sysbus_init_irq(&proxy->busdev, &proxy->irq); - iomemtype = cpu_register_io_memory(0, syborg_virtio_readfn, + iomemtype = cpu_register_io_memory(syborg_virtio_readfn, syborg_virtio_writefn, proxy); sysbus_init_mmio(&proxy->busdev, 0x1000, iomemtype); diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c index 7803a4c8a..3962d98a9 100644 --- a/hw/tc6393xb.c +++ b/hw/tc6393xb.c @@ -589,7 +589,7 @@ TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq) s->flash = nand_init(NAND_MFR_TOSHIBA, 0x76); - iomemtype = cpu_register_io_memory(0, tc6393xb_readfn, + iomemtype = cpu_register_io_memory(tc6393xb_readfn, tc6393xb_writefn, s); cpu_register_physical_memory(base, 0x10000, iomemtype); @@ -523,11 +523,11 @@ void tcx_init(target_phys_addr_t addr, int vram_size, int width, int height, vram_offset += size; vram_base += size; - io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s); + io_memory = cpu_register_io_memory(tcx_dac_read, tcx_dac_write, s); cpu_register_physical_memory(addr + 0x00200000ULL, TCX_DAC_NREGS, io_memory); - dummy_memory = cpu_register_io_memory(0, tcx_dummy_read, tcx_dummy_write, + dummy_memory = cpu_register_io_memory(tcx_dummy_read, tcx_dummy_write, s); cpu_register_physical_memory(addr + 0x00700000ULL, TCX_TEC_NREGS, dummy_memory); diff --git a/hw/tusb6010.c b/hw/tusb6010.c index f3aa7b1f8..622de81d5 100644 --- a/hw/tusb6010.c +++ b/hw/tusb6010.c @@ -742,7 +742,7 @@ TUSBState *tusb6010_init(qemu_irq intr) s->mask = 0xffffffff; s->intr = 0x00000000; s->otg_timer_val = 0; - s->iomemtype[1] = cpu_register_io_memory(0, tusb_async_readfn, + s->iomemtype[1] = cpu_register_io_memory(tusb_async_readfn, tusb_async_writefn, s); s->irq = intr; s->otg_timer = qemu_new_timer(vm_clock, tusb_otg_tick, s); diff --git a/hw/unin_pci.c b/hw/unin_pci.c index a9ef21733..b2ebc31c5 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -179,9 +179,9 @@ PCIBus *pci_pmac_init(qemu_irq *pic) pci_unin_set_irq, pci_unin_map_irq, pic, 11 << 3, 4); - pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, + pci_mem_config = cpu_register_io_memory(pci_unin_main_config_read, pci_unin_main_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read, + pci_mem_data = cpu_register_io_memory(pci_unin_main_read, pci_unin_main_write, s); cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config); cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data); @@ -226,9 +226,9 @@ PCIBus *pci_pmac_init(qemu_irq *pic) #endif /* Uninorth AGP bus */ - pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, + pci_mem_config = cpu_register_io_memory(pci_unin_config_read, pci_unin_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read, + pci_mem_data = cpu_register_io_memory(pci_unin_main_read, pci_unin_main_write, s); cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config); cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data); @@ -247,9 +247,9 @@ PCIBus *pci_pmac_init(qemu_irq *pic) #if 0 // XXX: not needed for now /* Uninorth internal bus */ s = &pci_bridge[2]; - pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, + pci_mem_config = cpu_register_io_memory(pci_unin_config_read, pci_unin_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_unin_read, + pci_mem_data = cpu_register_io_memory(pci_unin_read, pci_unin_write, s); cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config); cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data); diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 1cc1b6208..c575480b4 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -1682,7 +1682,7 @@ static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn, usb_frame_time, usb_bit_time); } - ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci); + ohci->mem = cpu_register_io_memory(ohci_readfn, ohci_writefn, ohci); ohci->localmem_base = localmem_base; ohci->name = name; @@ -1732,7 +1732,7 @@ void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn) usb_ohci_init(&ohci->state, num_ports, devfn, ohci->pci_dev.irq[0], OHCI_TYPE_PCI, ohci->pci_dev.name, 0); - pci_register_io_region((struct PCIDevice *)ohci, 0, 256, + pci_register_bar((struct PCIDevice *)ohci, 0, 256, PCI_ADDRESS_SPACE_MEM, ohci_mapfunc); } diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 689d40ac6..00e740b47 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -1097,7 +1097,7 @@ void usb_uhci_piix3_init(PCIBus *bus, int devfn) /* Use region 4 for consistency with real hardware. BSD guests seem to rely on this. */ - pci_register_io_region(&s->dev, 4, 0x20, + pci_register_bar(&s->dev, 4, 0x20, PCI_ADDRESS_SPACE_IO, uhci_map); register_savevm("uhci", 0, 1, uhci_save, uhci_load, s); @@ -1131,7 +1131,7 @@ void usb_uhci_piix4_init(PCIBus *bus, int devfn) /* Use region 4 for consistency with real hardware. BSD guests seem to rely on this. */ - pci_register_io_region(&s->dev, 4, 0x20, + pci_register_bar(&s->dev, 4, 0x20, PCI_ADDRESS_SPACE_IO, uhci_map); register_savevm("uhci", 0, 1, uhci_save, uhci_load, s); diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index e454d498d..e89add1be 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -124,7 +124,7 @@ static void pci_vpb_init(SysBusDevice *dev) /* ??? Register memory space. */ - s->mem_config = cpu_register_io_memory(0, pci_vpb_config_read, + s->mem_config = cpu_register_io_memory(pci_vpb_config_read, pci_vpb_config_write, bus); sysbus_init_mmio_cb(dev, 0x04000000, pci_vpb_map); diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 03cf4d8f3..1f1b1bcca 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -140,7 +140,7 @@ static void vpb_sic_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->parent[i]); } s->irq = 31; - iomemtype = cpu_register_io_memory(0, vpb_sic_readfn, + iomemtype = cpu_register_io_memory(vpb_sic_readfn, vpb_sic_writefn, s); sysbus_init_mmio(dev, 0x1000, iomemtype); /* ??? Save/restore. */ @@ -2388,7 +2388,7 @@ void vga_init(VGAState *s) #endif #endif /* CONFIG_BOCHS_VBE */ - vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s); + vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s); cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, vga_io_memory); qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000); @@ -2458,8 +2458,8 @@ static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base, int s_ioport_ctrl, vga_io_memory; s->it_shift = it_shift; - s_ioport_ctrl = cpu_register_io_memory(0, vga_mm_read_ctrl, vga_mm_write_ctrl, s); - vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s); + s_ioport_ctrl = cpu_register_io_memory(vga_mm_read_ctrl, vga_mm_write_ctrl, s); + vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s); register_savevm("vga", 0, 2, vga_save, vga_load, s); @@ -2553,7 +2553,7 @@ int pci_vga_init(PCIBus *bus, pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type /* XXX: VGA_RAM_SIZE must be a power of two */ - pci_register_io_region(&d->dev, 0, VGA_RAM_SIZE, + pci_register_bar(&d->dev, 0, VGA_RAM_SIZE, PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); if (vga_bios_size != 0) { unsigned int bios_total_size; @@ -2563,7 +2563,7 @@ int pci_vga_init(PCIBus *bus, bios_total_size = 1; while (bios_total_size < vga_bios_size) bios_total_size <<= 1; - pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size, + pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size, PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); } return 0; @@ -2627,8 +2627,9 @@ static void vga_screen_dump_blank(VGAState *s, const char *filename) { FILE *f; unsigned int y, x, w, h; + unsigned char blank_sample[3] = { 0, 0, 0 }; - w = s->last_scr_width * sizeof(uint32_t); + w = s->last_scr_width; h = s->last_scr_height; f = fopen(filename, "wb"); @@ -2637,7 +2638,7 @@ static void vga_screen_dump_blank(VGAState *s, const char *filename) fprintf(f, "P6\n%d %d\n%d\n", w, h, 255); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { - fputc(0, f); + fwrite(blank_sample, 3, 1, f); } } fclose(f); diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 9a0c0674f..5d3355996 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -294,6 +294,7 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) bdrv_get_geometry(s->bs, &capacity); bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs); + memset(&blkcfg, 0, sizeof(blkcfg)); stq_raw(&blkcfg.capacity, capacity); stl_raw(&blkcfg.seg_max, 128 - 2); stw_raw(&blkcfg.cylinders, cylinders); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index c072423dc..24fe837be 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -276,7 +276,7 @@ static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev, if (size & (size-1)) size = 1 << qemu_fls(size); - pci_register_io_region(&proxy->pci_dev, 0, size, PCI_ADDRESS_SPACE_IO, + pci_register_bar(&proxy->pci_dev, 0, size, PCI_ADDRESS_SPACE_IO, virtio_map); virtio_bind_device(vdev, &virtio_pci_bindings, proxy); diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 79da1ffd6..9c354dd10 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -1201,7 +1201,7 @@ static void pci_vmsvga_map_mem(PCIDevice *pci_dev, int region_num, s->vram_base = addr; #ifdef DIRECT_VRAM - iomemtype = cpu_register_io_memory(0, vmsvga_vram_read, + iomemtype = cpu_register_io_memory(vmsvga_vram_read, vmsvga_vram_write, s); #else iomemtype = s->vga.vram_offset | IO_MEM_RAM; @@ -1231,9 +1231,9 @@ void pci_vmsvga_init(PCIBus *bus) s->card.config[0x2f] = SVGA_PCI_DEVICE_ID >> 8; s->card.config[0x3c] = 0xff; /* End */ - pci_register_io_region(&s->card, 0, 0x10, + pci_register_bar(&s->card, 0, 0x10, PCI_ADDRESS_SPACE_IO, pci_vmsvga_map_ioport); - pci_register_io_region(&s->card, 1, VGA_RAM_SIZE, + pci_register_bar(&s->card, 1, VGA_RAM_SIZE, PCI_ADDRESS_SPACE_MEM_PREFETCH, pci_vmsvga_map_mem); vmsvga_init(&s->chip, VGA_RAM_SIZE); diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c index f7ddea279..42642c77f 100644 --- a/hw/wdt_i6300esb.c +++ b/hw/wdt_i6300esb.c @@ -368,7 +368,7 @@ static void i6300esb_map(PCIDevice *dev, int region_num, i6300esb_debug("addr = %x, size = %x, type = %d\n", addr, size, type); - io_mem = cpu_register_io_memory (0, mem_read, mem_write, d); + io_mem = cpu_register_io_memory(mem_read, mem_write, d); cpu_register_physical_memory (addr, 0x10, io_mem); /* qemu_register_coalesced_mmio (addr, 0x10); ? */ } @@ -451,7 +451,7 @@ static void i6300esb_pc_init(PCIBus *pci_bus) pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); pci_conf[0x0e] = 0x00; - pci_register_io_region(&d->dev, 0, 0x10, + pci_register_bar(&d->dev, 0, 0x10, PCI_ADDRESS_SPACE_MEM, i6300esb_map); register_savevm("i6300esb_wdt", -1, sizeof(I6300State), diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index 77cd6fb05..2e1909fe4 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -218,7 +218,7 @@ static void xilinx_ethlite_init(SysBusDevice *dev) s->c_rx_pingpong = qdev_get_prop_int(&dev->qdev, "rxpingpong", 1); s->rxbuf = 0; - regs = cpu_register_io_memory(0, eth_read, eth_write, s); + regs = cpu_register_io_memory(eth_read, eth_write, s); sysbus_init_mmio(dev, R_MAX * 4, regs); qdev_get_macaddr(&dev->qdev, s->macaddr); diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c index 0b17fae28..0540f52d0 100644 --- a/hw/xilinx_intc.c +++ b/hw/xilinx_intc.c @@ -154,7 +154,7 @@ static void xilinx_intc_init(SysBusDevice *dev) qdev_init_gpio_in(&dev->qdev, irq_handler, 32); sysbus_init_irq(dev, &p->parent_irq); - pic_regs = cpu_register_io_memory(0, pic_read, pic_write, p); + pic_regs = cpu_register_io_memory(pic_read, pic_write, p); sysbus_init_mmio(dev, R_MAX * 4, pic_regs); } diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c index d0e8f1862..a64ad2d80 100644 --- a/hw/xilinx_timer.c +++ b/hw/xilinx_timer.c @@ -211,7 +211,7 @@ static void xilinx_timer_init(SysBusDevice *dev) ptimer_set_freq(xt->ptimer, freq_hz); } - timer_regs = cpu_register_io_memory(0, timer_read, timer_write, t); + timer_regs = cpu_register_io_memory(timer_read, timer_write, t); sysbus_init_mmio(dev, R_MAX * 4 * t->nr_timers, timer_regs); } diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c index 5cfb36c48..9bf2e9106 100644 --- a/hw/xilinx_uartlite.c +++ b/hw/xilinx_uartlite.c @@ -201,7 +201,7 @@ static void xilinx_uartlite_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); uart_update_status(s); - uart_regs = cpu_register_io_memory(0, uart_read, uart_write, s); + uart_regs = cpu_register_io_memory(uart_read, uart_write, s); sysbus_init_mmio(dev, R_MAX * 4, uart_regs); s->chr = qdev_init_chardev(&dev->qdev); diff --git a/hw/zaurus.c b/hw/zaurus.c index 7cf47b9c9..53191ef9e 100644 --- a/hw/zaurus.c +++ b/hw/zaurus.c @@ -228,7 +228,7 @@ ScoopInfo *scoop_init(PXA2xxState *cpu, s->status = 0x02; s->in = qemu_allocate_irqs(scoop_gpio_set, s, 16); - iomemtype = cpu_register_io_memory(0, scoop_readfn, + iomemtype = cpu_register_io_memory(scoop_readfn, scoop_writefn, s); cpu_register_physical_memory(target_base, 0x1000, iomemtype); register_savevm("scoop", instance, 1, scoop_save, scoop_load, s); @@ -990,7 +990,7 @@ static CPUWriteMemoryFunc *qpi_mem_write[3] = { static void qpi_init(void) { kqemu_comm_base = 0xff000000 | 1; - qpi_io_memory = cpu_register_io_memory(0, + qpi_io_memory = cpu_register_io_memory( qpi_mem_read, qpi_mem_write, NULL); cpu_register_physical_memory(kqemu_comm_base & ~0xfff, @@ -578,14 +578,13 @@ int kvm_cpu_exec(CPUState *env) dprintf("kvm_cpu_exec()\n"); do { - kvm_arch_pre_run(env, run); - if (env->exit_request) { dprintf("interrupt exit requested\n"); ret = 0; break; } + kvm_arch_pre_run(env, run); ret = kvm_vcpu_ioctl(env, KVM_RUN, 0); kvm_arch_post_run(env, run); diff --git a/linux-user/arm/syscall_nr.h b/linux-user/arm/syscall_nr.h index 9ca3a5df3..b1db34152 100644 --- a/linux-user/arm/syscall_nr.h +++ b/linux-user/arm/syscall_nr.h @@ -356,3 +356,12 @@ #define TARGET_NR_signalfd (349) #define TARGET_NR_timerfd (350) #define TARGET_NR_eventfd (351) +#define TARGET_NR_fallocate (352) +#define TARGET_NR_timerfd_settime (353) +#define TARGET_NR_timerfd_gettime (354) +#define TARGET_NR_signalfd4 (355) +#define TARGET_NR_eventfd2 (356) +#define TARGET_NR_epoll_create1 (357) +#define TARGET_NR_dup3 (358) +#define TARGET_NR_pipe2 (359) +#define TARGET_NR_inotify_init1 (360) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 190ad143e..d31cca71d 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1,4 +1,6 @@ /* This is the Linux kernel elf-loading code, ported into user space */ +#include <sys/time.h> +#include <sys/param.h> #include <stdio.h> #include <sys/types.h> @@ -6,8 +8,10 @@ #include <errno.h> #include <unistd.h> #include <sys/mman.h> +#include <sys/resource.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include "qemu.h" #include "disas.h" @@ -21,6 +25,8 @@ #undef ELF_ARCH #endif +#define ELF_OSABI ELFOSABI_SYSV + /* from personality.h */ /* @@ -128,6 +134,52 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->rip = infop->entry; } +typedef target_ulong elf_greg_t; +typedef uint32_t target_uid_t; +typedef uint32_t target_gid_t; +typedef int32_t target_pid_t; + +#define ELF_NREG 27 +typedef elf_greg_t elf_gregset_t[ELF_NREG]; + +/* + * Note that ELF_NREG should be 29 as there should be place for + * TRAPNO and ERR "registers" as well but linux doesn't dump + * those. + * + * See linux kernel: arch/x86/include/asm/elf.h + */ +static void elf_core_copy_regs(elf_gregset_t *regs, const CPUState *env) +{ + (*regs)[0] = env->regs[15]; + (*regs)[1] = env->regs[14]; + (*regs)[2] = env->regs[13]; + (*regs)[3] = env->regs[12]; + (*regs)[4] = env->regs[R_EBP]; + (*regs)[5] = env->regs[R_EBX]; + (*regs)[6] = env->regs[11]; + (*regs)[7] = env->regs[10]; + (*regs)[8] = env->regs[9]; + (*regs)[9] = env->regs[8]; + (*regs)[10] = env->regs[R_EAX]; + (*regs)[11] = env->regs[R_ECX]; + (*regs)[12] = env->regs[R_EDX]; + (*regs)[13] = env->regs[R_ESI]; + (*regs)[14] = env->regs[R_EDI]; + (*regs)[15] = env->regs[R_EAX]; /* XXX */ + (*regs)[16] = env->eip; + (*regs)[17] = env->segs[R_CS].selector & 0xffff; + (*regs)[18] = env->eflags; + (*regs)[19] = env->regs[R_ESP]; + (*regs)[20] = env->segs[R_SS].selector & 0xffff; + (*regs)[21] = env->segs[R_FS].selector & 0xffff; + (*regs)[22] = env->segs[R_GS].selector & 0xffff; + (*regs)[23] = env->segs[R_DS].selector & 0xffff; + (*regs)[24] = env->segs[R_ES].selector & 0xffff; + (*regs)[25] = env->segs[R_FS].selector & 0xffff; + (*regs)[26] = env->segs[R_GS].selector & 0xffff; +} + #else #define ELF_START_MMAP 0x80000000 @@ -158,6 +210,42 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i A value of 0 tells we have no such handler. */ regs->edx = 0; } + +typedef target_ulong elf_greg_t; +typedef uint16_t target_uid_t; +typedef uint16_t target_gid_t; +typedef int32_t target_pid_t; + +#define ELF_NREG 17 +typedef elf_greg_t elf_gregset_t[ELF_NREG]; + +/* + * Note that ELF_NREG should be 19 as there should be place for + * TRAPNO and ERR "registers" as well but linux doesn't dump + * those. + * + * See linux kernel: arch/x86/include/asm/elf.h + */ +static void elf_core_copy_regs(elf_gregset_t *regs, const CPUState *env) +{ + (*regs)[0] = env->regs[R_EBX]; + (*regs)[1] = env->regs[R_ECX]; + (*regs)[2] = env->regs[R_EDX]; + (*regs)[3] = env->regs[R_ESI]; + (*regs)[4] = env->regs[R_EDI]; + (*regs)[5] = env->regs[R_EBP]; + (*regs)[6] = env->regs[R_EAX]; + (*regs)[7] = env->segs[R_DS].selector & 0xffff; + (*regs)[8] = env->segs[R_ES].selector & 0xffff; + (*regs)[9] = env->segs[R_FS].selector & 0xffff; + (*regs)[10] = env->segs[R_GS].selector & 0xffff; + (*regs)[11] = env->regs[R_EAX]; /* XXX */ + (*regs)[12] = env->eip; + (*regs)[13] = env->segs[R_CS].selector & 0xffff; + (*regs)[14] = env->eflags; + (*regs)[15] = env->regs[R_ESP]; + (*regs)[16] = env->segs[R_SS].selector & 0xffff; +} #endif #define USE_ELF_CORE_DUMP @@ -198,6 +286,37 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->ARM_r10 = infop->start_data; } +typedef uint32_t elf_greg_t; +typedef uint16_t target_uid_t; +typedef uint16_t target_gid_t; +typedef int32_t target_pid_t; + +#define ELF_NREG 18 +typedef elf_greg_t elf_gregset_t[ELF_NREG]; + +static void elf_core_copy_regs(elf_gregset_t *regs, const CPUState *env) +{ + (*regs)[0] = env->regs[0]; + (*regs)[1] = env->regs[1]; + (*regs)[2] = env->regs[2]; + (*regs)[3] = env->regs[3]; + (*regs)[4] = env->regs[4]; + (*regs)[5] = env->regs[5]; + (*regs)[6] = env->regs[6]; + (*regs)[7] = env->regs[7]; + (*regs)[8] = env->regs[8]; + (*regs)[9] = env->regs[9]; + (*regs)[10] = env->regs[10]; + (*regs)[11] = env->regs[11]; + (*regs)[12] = env->regs[12]; + (*regs)[13] = env->regs[13]; + (*regs)[14] = env->regs[14]; + (*regs)[15] = env->regs[15]; + + (*regs)[16] = cpsr_read((CPUState *)env); + (*regs)[17] = env->regs[0]; /* XXX */ +} + #define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 @@ -418,7 +537,6 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * _regs->gpr[5] = pos; } -#define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 #endif @@ -448,7 +566,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->regs[29] = infop->start_stack; } -#define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 #endif /* TARGET_MIPS */ @@ -470,7 +587,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i } -#define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 #endif /* TARGET_MICROBLAZE */ @@ -492,7 +608,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->regs[15] = infop->start_stack; } -#define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 #endif @@ -512,7 +627,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->erp = infop->entry; } -#define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 8192 #endif @@ -537,7 +651,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->pc = infop->entry; } -#define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 8192 #endif @@ -562,7 +675,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->unique, infop->start_data); } -#define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 8192 #endif /* TARGET_ALPHA */ @@ -680,6 +792,20 @@ static void bswap_sym(struct elf_sym *sym) } #endif +#ifdef USE_ELF_CORE_DUMP +static int elf_core_dump(int, const CPUState *); + +#ifdef BSWAP_NEEDED +static void bswap_note(struct elf_note *en) +{ + bswaptls(&en->n_namesz); + bswaptls(&en->n_descsz); + bswaptls(&en->n_type); +} +#endif /* BSWAP_NEEDED */ + +#endif /* USE_ELF_CORE_DUMP */ + /* * 'copy_elf_strings()' copies argument/envelope strings from user * memory to free pages in kernel mem. These are in a format ready @@ -904,6 +1030,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, #endif #undef NEW_AUX_ENT + info->saved_auxv = sp; + sp = loader_build_argptr(envc, argc, sp, p, !ibcs); return sp; } @@ -1586,9 +1714,876 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, info->entry = elf_entry; +#ifdef USE_ELF_CORE_DUMP + bprm->core_dump = &elf_core_dump; +#endif + return 0; } +#ifdef USE_ELF_CORE_DUMP + +/* + * Definitions to generate Intel SVR4-like core files. + * These mostly have the same names as the SVR4 types with "elf_" + * tacked on the front to prevent clashes with linux definitions, + * and the typedef forms have been avoided. This is mostly like + * the SVR4 structure, but more Linuxy, with things that Linux does + * not support and which gdb doesn't really use excluded. + * + * Fields we don't dump (their contents is zero) in linux-user qemu + * are marked with XXX. + * + * Core dump code is copied from linux kernel (fs/binfmt_elf.c). + * + * Porting ELF coredump for target is (quite) simple process. First you + * define ELF_USE_CORE_DUMP in target ELF code (where init_thread() for + * the target resides): + * + * #define USE_ELF_CORE_DUMP + * + * Next you define type of register set used for dumping. ELF specification + * says that it needs to be array of elf_greg_t that has size of ELF_NREG. + * + * typedef <target_regtype> elf_greg_t; + * #define ELF_NREG <number of registers> + * typedef elf_greg_t elf_gregset_t[ELF_NREG]; + * + * Then define following types to match target types. Actual types can + * be found from linux kernel (arch/<ARCH>/include/asm/posix_types.h): + * + * typedef <target_uid_type> target_uid_t; + * typedef <target_gid_type> target_gid_t; + * typedef <target_pid_type> target_pid_t; + * + * Last step is to implement target specific function that copies registers + * from given cpu into just specified register set. Prototype is: + * + * static void elf_core_copy_regs(elf_gregset_t *regs, const CPUState *env); + * + * Parameters: + * regs - copy register values into here (allocated and zeroed by caller) + * env - copy registers from here + * + * Example for ARM target is provided in this file. + */ + +/* An ELF note in memory */ +struct memelfnote { + const char *name; + size_t namesz; + size_t namesz_rounded; + int type; + size_t datasz; + void *data; + size_t notesz; +}; + +struct elf_siginfo { + int si_signo; /* signal number */ + int si_code; /* extra code */ + int si_errno; /* errno */ +}; + +struct elf_prstatus { + struct elf_siginfo pr_info; /* Info associated with signal */ + short pr_cursig; /* Current signal */ + target_ulong pr_sigpend; /* XXX */ + target_ulong pr_sighold; /* XXX */ + target_pid_t pr_pid; + target_pid_t pr_ppid; + target_pid_t pr_pgrp; + target_pid_t pr_sid; + struct target_timeval pr_utime; /* XXX User time */ + struct target_timeval pr_stime; /* XXX System time */ + struct target_timeval pr_cutime; /* XXX Cumulative user time */ + struct target_timeval pr_cstime; /* XXX Cumulative system time */ + elf_gregset_t pr_reg; /* GP registers */ + int pr_fpvalid; /* XXX */ +}; + +#define ELF_PRARGSZ (80) /* Number of chars for args */ + +struct elf_prpsinfo { + char pr_state; /* numeric process state */ + char pr_sname; /* char for pr_state */ + char pr_zomb; /* zombie */ + char pr_nice; /* nice val */ + target_ulong pr_flag; /* flags */ + target_uid_t pr_uid; + target_gid_t pr_gid; + target_pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid; + /* Lots missing */ + char pr_fname[16]; /* filename of executable */ + char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ +}; + +/* Here is the structure in which status of each thread is captured. */ +struct elf_thread_status { + TAILQ_ENTRY(elf_thread_status) ets_link; + struct elf_prstatus prstatus; /* NT_PRSTATUS */ +#if 0 + elf_fpregset_t fpu; /* NT_PRFPREG */ + struct task_struct *thread; + elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */ +#endif + struct memelfnote notes[1]; + int num_notes; +}; + +struct elf_note_info { + struct memelfnote *notes; + struct elf_prstatus *prstatus; /* NT_PRSTATUS */ + struct elf_prpsinfo *psinfo; /* NT_PRPSINFO */ + + TAILQ_HEAD(thread_list_head, elf_thread_status) thread_list; +#if 0 + /* + * Current version of ELF coredump doesn't support + * dumping fp regs etc. + */ + elf_fpregset_t *fpu; + elf_fpxregset_t *xfpu; + int thread_status_size; +#endif + int notes_size; + int numnote; +}; + +struct vm_area_struct { + abi_ulong vma_start; /* start vaddr of memory region */ + abi_ulong vma_end; /* end vaddr of memory region */ + abi_ulong vma_flags; /* protection etc. flags for the region */ + TAILQ_ENTRY(vm_area_struct) vma_link; +}; + +struct mm_struct { + TAILQ_HEAD(, vm_area_struct) mm_mmap; + int mm_count; /* number of mappings */ +}; + +static struct mm_struct *vma_init(void); +static void vma_delete(struct mm_struct *); +static int vma_add_mapping(struct mm_struct *, abi_ulong, + abi_ulong, abi_ulong); +static int vma_get_mapping_count(const struct mm_struct *); +static struct vm_area_struct *vma_first(const struct mm_struct *); +static struct vm_area_struct *vma_next(struct vm_area_struct *); +static abi_ulong vma_dump_size(const struct vm_area_struct *); +static int vma_walker(void *priv, unsigned long start, unsigned long end, + unsigned long flags); + +static void fill_elf_header(struct elfhdr *, int, uint16_t, uint32_t); +static void fill_note(struct memelfnote *, const char *, int, + unsigned int, void *); +static void fill_prstatus(struct elf_prstatus *, const TaskState *, int); +static int fill_psinfo(struct elf_prpsinfo *, const TaskState *); +static void fill_auxv_note(struct memelfnote *, const TaskState *); +static void fill_elf_note_phdr(struct elf_phdr *, int, off_t); +static size_t note_size(const struct memelfnote *); +static void free_note_info(struct elf_note_info *); +static int fill_note_info(struct elf_note_info *, long, const CPUState *); +static void fill_thread_info(struct elf_note_info *, const CPUState *); +static int core_dump_filename(const TaskState *, char *, size_t); + +static int dump_write(int, const void *, size_t); +static int write_note(struct memelfnote *, int); +static int write_note_info(struct elf_note_info *, int); + +#ifdef BSWAP_NEEDED +static void bswap_prstatus(struct elf_prstatus *); +static void bswap_psinfo(struct elf_prpsinfo *); + +static void bswap_prstatus(struct elf_prstatus *prstatus) +{ + prstatus->pr_info.si_signo = tswapl(prstatus->pr_info.si_signo); + prstatus->pr_info.si_code = tswapl(prstatus->pr_info.si_code); + prstatus->pr_info.si_errno = tswapl(prstatus->pr_info.si_errno); + prstatus->pr_cursig = tswap16(prstatus->pr_cursig); + prstatus->pr_sigpend = tswapl(prstatus->pr_sigpend); + prstatus->pr_sighold = tswapl(prstatus->pr_sighold); + prstatus->pr_pid = tswap32(prstatus->pr_pid); + prstatus->pr_ppid = tswap32(prstatus->pr_ppid); + prstatus->pr_pgrp = tswap32(prstatus->pr_pgrp); + prstatus->pr_sid = tswap32(prstatus->pr_sid); + /* cpu times are not filled, so we skip them */ + /* regs should be in correct format already */ + prstatus->pr_fpvalid = tswap32(prstatus->pr_fpvalid); +} + +static void bswap_psinfo(struct elf_prpsinfo *psinfo) +{ + psinfo->pr_flag = tswapl(psinfo->pr_flag); + psinfo->pr_uid = tswap16(psinfo->pr_uid); + psinfo->pr_gid = tswap16(psinfo->pr_gid); + psinfo->pr_pid = tswap32(psinfo->pr_pid); + psinfo->pr_ppid = tswap32(psinfo->pr_ppid); + psinfo->pr_pgrp = tswap32(psinfo->pr_pgrp); + psinfo->pr_sid = tswap32(psinfo->pr_sid); +} +#endif /* BSWAP_NEEDED */ + +/* + * Minimal support for linux memory regions. These are needed + * when we are finding out what memory exactly belongs to + * emulated process. No locks needed here, as long as + * thread that received the signal is stopped. + */ + +static struct mm_struct *vma_init(void) +{ + struct mm_struct *mm; + + if ((mm = qemu_malloc(sizeof (*mm))) == NULL) + return (NULL); + + mm->mm_count = 0; + TAILQ_INIT(&mm->mm_mmap); + + return (mm); +} + +static void vma_delete(struct mm_struct *mm) +{ + struct vm_area_struct *vma; + + while ((vma = vma_first(mm)) != NULL) { + TAILQ_REMOVE(&mm->mm_mmap, vma, vma_link); + qemu_free(vma); + } + qemu_free(mm); +} + +static int vma_add_mapping(struct mm_struct *mm, abi_ulong start, + abi_ulong end, abi_ulong flags) +{ + struct vm_area_struct *vma; + + if ((vma = qemu_mallocz(sizeof (*vma))) == NULL) + return (-1); + + vma->vma_start = start; + vma->vma_end = end; + vma->vma_flags = flags; + + TAILQ_INSERT_TAIL(&mm->mm_mmap, vma, vma_link); + mm->mm_count++; + + return (0); +} + +static struct vm_area_struct *vma_first(const struct mm_struct *mm) +{ + return (TAILQ_FIRST(&mm->mm_mmap)); +} + +static struct vm_area_struct *vma_next(struct vm_area_struct *vma) +{ + return (TAILQ_NEXT(vma, vma_link)); +} + +static int vma_get_mapping_count(const struct mm_struct *mm) +{ + return (mm->mm_count); +} + +/* + * Calculate file (dump) size of given memory region. + */ +static abi_ulong vma_dump_size(const struct vm_area_struct *vma) +{ + /* if we cannot even read the first page, skip it */ + if (!access_ok(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE)) + return (0); + + /* + * Usually we don't dump executable pages as they contain + * non-writable code that debugger can read directly from + * target library etc. However, thread stacks are marked + * also executable so we read in first page of given region + * and check whether it contains elf header. If there is + * no elf header, we dump it. + */ + if (vma->vma_flags & PROT_EXEC) { + char page[TARGET_PAGE_SIZE]; + + copy_from_user(page, vma->vma_start, sizeof (page)); + if ((page[EI_MAG0] == ELFMAG0) && + (page[EI_MAG1] == ELFMAG1) && + (page[EI_MAG2] == ELFMAG2) && + (page[EI_MAG3] == ELFMAG3)) { + /* + * Mappings are possibly from ELF binary. Don't dump + * them. + */ + return (0); + } + } + + return (vma->vma_end - vma->vma_start); +} + +static int vma_walker(void *priv, unsigned long start, unsigned long end, + unsigned long flags) +{ + struct mm_struct *mm = (struct mm_struct *)priv; + + /* + * Don't dump anything that qemu has reserved for internal use. + */ + if (flags & PAGE_RESERVED) + return (0); + + vma_add_mapping(mm, start, end, flags); + return (0); +} + +static void fill_note(struct memelfnote *note, const char *name, int type, + unsigned int sz, void *data) +{ + unsigned int namesz; + + namesz = strlen(name) + 1; + note->name = name; + note->namesz = namesz; + note->namesz_rounded = roundup(namesz, sizeof (int32_t)); + note->type = type; + note->datasz = roundup(sz, sizeof (int32_t));; + note->data = data; + + /* + * We calculate rounded up note size here as specified by + * ELF document. + */ + note->notesz = sizeof (struct elf_note) + + note->namesz_rounded + note->datasz; +} + +static void fill_elf_header(struct elfhdr *elf, int segs, uint16_t machine, + uint32_t flags) +{ + (void) memset(elf, 0, sizeof(*elf)); + + (void) memcpy(elf->e_ident, ELFMAG, SELFMAG); + elf->e_ident[EI_CLASS] = ELF_CLASS; + elf->e_ident[EI_DATA] = ELF_DATA; + elf->e_ident[EI_VERSION] = EV_CURRENT; + elf->e_ident[EI_OSABI] = ELF_OSABI; + + elf->e_type = ET_CORE; + elf->e_machine = machine; + elf->e_version = EV_CURRENT; + elf->e_phoff = sizeof(struct elfhdr); + elf->e_flags = flags; + elf->e_ehsize = sizeof(struct elfhdr); + elf->e_phentsize = sizeof(struct elf_phdr); + elf->e_phnum = segs; + +#ifdef BSWAP_NEEDED + bswap_ehdr(elf); +#endif +} + +static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset) +{ + phdr->p_type = PT_NOTE; + phdr->p_offset = offset; + phdr->p_vaddr = 0; + phdr->p_paddr = 0; + phdr->p_filesz = sz; + phdr->p_memsz = 0; + phdr->p_flags = 0; + phdr->p_align = 0; + +#ifdef BSWAP_NEEDED + bswap_phdr(phdr); +#endif +} + +static size_t note_size(const struct memelfnote *note) +{ + return (note->notesz); +} + +static void fill_prstatus(struct elf_prstatus *prstatus, + const TaskState *ts, int signr) +{ + (void) memset(prstatus, 0, sizeof (*prstatus)); + prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; + prstatus->pr_pid = ts->ts_tid; + prstatus->pr_ppid = getppid(); + prstatus->pr_pgrp = getpgrp(); + prstatus->pr_sid = getsid(0); + +#ifdef BSWAP_NEEDED + bswap_prstatus(prstatus); +#endif +} + +static int fill_psinfo(struct elf_prpsinfo *psinfo, const TaskState *ts) +{ + char *filename, *base_filename; + unsigned int i, len; + + (void) memset(psinfo, 0, sizeof (*psinfo)); + + len = ts->info->arg_end - ts->info->arg_start; + if (len >= ELF_PRARGSZ) + len = ELF_PRARGSZ - 1; + if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_start, len)) + return -EFAULT; + for (i = 0; i < len; i++) + if (psinfo->pr_psargs[i] == 0) + psinfo->pr_psargs[i] = ' '; + psinfo->pr_psargs[len] = 0; + + psinfo->pr_pid = getpid(); + psinfo->pr_ppid = getppid(); + psinfo->pr_pgrp = getpgrp(); + psinfo->pr_sid = getsid(0); + psinfo->pr_uid = getuid(); + psinfo->pr_gid = getgid(); + + filename = strdup(ts->bprm->filename); + base_filename = strdup(basename(filename)); + (void) strncpy(psinfo->pr_fname, base_filename, + sizeof(psinfo->pr_fname)); + free(base_filename); + free(filename); + +#ifdef BSWAP_NEEDED + bswap_psinfo(psinfo); +#endif + return (0); +} + +static void fill_auxv_note(struct memelfnote *note, const TaskState *ts) +{ + elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv; + elf_addr_t orig_auxv = auxv; + abi_ulong val; + void *ptr; + int i, len; + + /* + * Auxiliary vector is stored in target process stack. It contains + * {type, value} pairs that we need to dump into note. This is not + * strictly necessary but we do it here for sake of completeness. + */ + + /* find out lenght of the vector, AT_NULL is terminator */ + i = len = 0; + do { + get_user_ual(val, auxv); + i += 2; + auxv += 2 * sizeof (elf_addr_t); + } while (val != AT_NULL); + len = i * sizeof (elf_addr_t); + + /* read in whole auxv vector and copy it to memelfnote */ + ptr = lock_user(VERIFY_READ, orig_auxv, len, 0); + if (ptr != NULL) { + fill_note(note, "CORE", NT_AUXV, len, ptr); + unlock_user(ptr, auxv, len); + } +} + +/* + * Constructs name of coredump file. We have following convention + * for the name: + * qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core + * + * Returns 0 in case of success, -1 otherwise (errno is set). + */ +static int core_dump_filename(const TaskState *ts, char *buf, + size_t bufsize) +{ + char timestamp[64]; + char *filename = NULL; + char *base_filename = NULL; + struct timeval tv; + struct tm tm; + + assert(bufsize >= PATH_MAX); + + if (gettimeofday(&tv, NULL) < 0) { + (void) fprintf(stderr, "unable to get current timestamp: %s", + strerror(errno)); + return (-1); + } + + filename = strdup(ts->bprm->filename); + base_filename = strdup(basename(filename)); + (void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S", + localtime_r(&tv.tv_sec, &tm)); + (void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core", + base_filename, timestamp, (int)getpid()); + free(base_filename); + free(filename); + + return (0); +} + +static int dump_write(int fd, const void *ptr, size_t size) +{ + const char *bufp = (const char *)ptr; + ssize_t bytes_written, bytes_left; + struct rlimit dumpsize; + off_t pos; + + bytes_written = 0; + getrlimit(RLIMIT_CORE, &dumpsize); + if ((pos = lseek(fd, 0, SEEK_CUR))==-1) { + if (errno == ESPIPE) { /* not a seekable stream */ + bytes_left = size; + } else { + return pos; + } + } else { + if (dumpsize.rlim_cur <= pos) { + return -1; + } else if (dumpsize.rlim_cur == RLIM_INFINITY) { + bytes_left = size; + } else { + size_t limit_left=dumpsize.rlim_cur - pos; + bytes_left = limit_left >= size ? size : limit_left ; + } + } + + /* + * In normal conditions, single write(2) should do but + * in case of socket etc. this mechanism is more portable. + */ + do { + bytes_written = write(fd, bufp, bytes_left); + if (bytes_written < 0) { + if (errno == EINTR) + continue; + return (-1); + } else if (bytes_written == 0) { /* eof */ + return (-1); + } + bufp += bytes_written; + bytes_left -= bytes_written; + } while (bytes_left > 0); + + return (0); +} + +static int write_note(struct memelfnote *men, int fd) +{ + struct elf_note en; + + en.n_namesz = men->namesz; + en.n_type = men->type; + en.n_descsz = men->datasz; + +#ifdef BSWAP_NEEDED + bswap_note(&en); +#endif + + if (dump_write(fd, &en, sizeof(en)) != 0) + return (-1); + if (dump_write(fd, men->name, men->namesz_rounded) != 0) + return (-1); + if (dump_write(fd, men->data, men->datasz) != 0) + return (-1); + + return (0); +} + +static void fill_thread_info(struct elf_note_info *info, const CPUState *env) +{ + TaskState *ts = (TaskState *)env->opaque; + struct elf_thread_status *ets; + + ets = qemu_mallocz(sizeof (*ets)); + ets->num_notes = 1; /* only prstatus is dumped */ + fill_prstatus(&ets->prstatus, ts, 0); + elf_core_copy_regs(&ets->prstatus.pr_reg, env); + fill_note(&ets->notes[0], "CORE", NT_PRSTATUS, sizeof (ets->prstatus), + &ets->prstatus); + + TAILQ_INSERT_TAIL(&info->thread_list, ets, ets_link); + + info->notes_size += note_size(&ets->notes[0]); +} + +static int fill_note_info(struct elf_note_info *info, + long signr, const CPUState *env) +{ +#define NUMNOTES 3 + CPUState *cpu = NULL; + TaskState *ts = (TaskState *)env->opaque; + int i; + + (void) memset(info, 0, sizeof (*info)); + + TAILQ_INIT(&info->thread_list); + + info->notes = qemu_mallocz(NUMNOTES * sizeof (struct memelfnote)); + if (info->notes == NULL) + return (-ENOMEM); + info->prstatus = qemu_mallocz(sizeof (*info->prstatus)); + if (info->prstatus == NULL) + return (-ENOMEM); + info->psinfo = qemu_mallocz(sizeof (*info->psinfo)); + if (info->prstatus == NULL) + return (-ENOMEM); + + /* + * First fill in status (and registers) of current thread + * including process info & aux vector. + */ + fill_prstatus(info->prstatus, ts, signr); + elf_core_copy_regs(&info->prstatus->pr_reg, env); + fill_note(&info->notes[0], "CORE", NT_PRSTATUS, + sizeof (*info->prstatus), info->prstatus); + fill_psinfo(info->psinfo, ts); + fill_note(&info->notes[1], "CORE", NT_PRPSINFO, + sizeof (*info->psinfo), info->psinfo); + fill_auxv_note(&info->notes[2], ts); + info->numnote = 3; + + info->notes_size = 0; + for (i = 0; i < info->numnote; i++) + info->notes_size += note_size(&info->notes[i]); + + /* read and fill status of all threads */ + cpu_list_lock(); + for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) { + if (cpu == thread_env) + continue; + fill_thread_info(info, cpu); + } + cpu_list_unlock(); + + return (0); +} + +static void free_note_info(struct elf_note_info *info) +{ + struct elf_thread_status *ets; + + while (!TAILQ_EMPTY(&info->thread_list)) { + ets = TAILQ_FIRST(&info->thread_list); + TAILQ_REMOVE(&info->thread_list, ets, ets_link); + qemu_free(ets); + } + + qemu_free(info->prstatus); + qemu_free(info->psinfo); + qemu_free(info->notes); +} + +static int write_note_info(struct elf_note_info *info, int fd) +{ + struct elf_thread_status *ets; + int i, error = 0; + + /* write prstatus, psinfo and auxv for current thread */ + for (i = 0; i < info->numnote; i++) + if ((error = write_note(&info->notes[i], fd)) != 0) + return (error); + + /* write prstatus for each thread */ + for (ets = info->thread_list.tqh_first; ets != NULL; + ets = ets->ets_link.tqe_next) { + if ((error = write_note(&ets->notes[0], fd)) != 0) + return (error); + } + + return (0); +} + +/* + * Write out ELF coredump. + * + * See documentation of ELF object file format in: + * http://www.caldera.com/developers/devspecs/gabi41.pdf + * + * Coredump format in linux is following: + * + * 0 +----------------------+ \ + * | ELF header | ET_CORE | + * +----------------------+ | + * | ELF program headers | |--- headers + * | - NOTE section | | + * | - PT_LOAD sections | | + * +----------------------+ / + * | NOTEs: | + * | - NT_PRSTATUS | + * | - NT_PRSINFO | + * | - NT_AUXV | + * +----------------------+ <-- aligned to target page + * | Process memory dump | + * : : + * . . + * : : + * | | + * +----------------------+ + * + * NT_PRSTATUS -> struct elf_prstatus (per thread) + * NT_PRSINFO -> struct elf_prpsinfo + * NT_AUXV is array of { type, value } pairs (see fill_auxv_note()). + * + * Format follows System V format as close as possible. Current + * version limitations are as follows: + * - no floating point registers are dumped + * + * Function returns 0 in case of success, negative errno otherwise. + * + * TODO: make this work also during runtime: it should be + * possible to force coredump from running process and then + * continue processing. For example qemu could set up SIGUSR2 + * handler (provided that target process haven't registered + * handler for that) that does the dump when signal is received. + */ +static int elf_core_dump(int signr, const CPUState *env) +{ + const TaskState *ts = (const TaskState *)env->opaque; + struct vm_area_struct *vma = NULL; + char corefile[PATH_MAX]; + struct elf_note_info info; + struct elfhdr elf; + struct elf_phdr phdr; + struct rlimit dumpsize; + struct mm_struct *mm = NULL; + off_t offset = 0, data_offset = 0; + int segs = 0; + int fd = -1; + + errno = 0; + getrlimit(RLIMIT_CORE, &dumpsize); + if (dumpsize.rlim_cur == 0) + return 0; + + if (core_dump_filename(ts, corefile, sizeof (corefile)) < 0) + return (-errno); + + if ((fd = open(corefile, O_WRONLY | O_CREAT, + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) + return (-errno); + + /* + * Walk through target process memory mappings and + * set up structure containing this information. After + * this point vma_xxx functions can be used. + */ + if ((mm = vma_init()) == NULL) + goto out; + + walk_memory_regions(mm, vma_walker); + segs = vma_get_mapping_count(mm); + + /* + * Construct valid coredump ELF header. We also + * add one more segment for notes. + */ + fill_elf_header(&elf, segs + 1, ELF_MACHINE, 0); + if (dump_write(fd, &elf, sizeof (elf)) != 0) + goto out; + + /* fill in in-memory version of notes */ + if (fill_note_info(&info, signr, env) < 0) + goto out; + + offset += sizeof (elf); /* elf header */ + offset += (segs + 1) * sizeof (struct elf_phdr); /* program headers */ + + /* write out notes program header */ + fill_elf_note_phdr(&phdr, info.notes_size, offset); + + offset += info.notes_size; + if (dump_write(fd, &phdr, sizeof (phdr)) != 0) + goto out; + + /* + * ELF specification wants data to start at page boundary so + * we align it here. + */ + offset = roundup(offset, ELF_EXEC_PAGESIZE); + + /* + * Write program headers for memory regions mapped in + * the target process. + */ + for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) { + (void) memset(&phdr, 0, sizeof (phdr)); + + phdr.p_type = PT_LOAD; + phdr.p_offset = offset; + phdr.p_vaddr = vma->vma_start; + phdr.p_paddr = 0; + phdr.p_filesz = vma_dump_size(vma); + offset += phdr.p_filesz; + phdr.p_memsz = vma->vma_end - vma->vma_start; + phdr.p_flags = vma->vma_flags & PROT_READ ? PF_R : 0; + if (vma->vma_flags & PROT_WRITE) + phdr.p_flags |= PF_W; + if (vma->vma_flags & PROT_EXEC) + phdr.p_flags |= PF_X; + phdr.p_align = ELF_EXEC_PAGESIZE; + + dump_write(fd, &phdr, sizeof (phdr)); + } + + /* + * Next we write notes just after program headers. No + * alignment needed here. + */ + if (write_note_info(&info, fd) < 0) + goto out; + + /* align data to page boundary */ + data_offset = lseek(fd, 0, SEEK_CUR); + data_offset = TARGET_PAGE_ALIGN(data_offset); + if (lseek(fd, data_offset, SEEK_SET) != data_offset) + goto out; + + /* + * Finally we can dump process memory into corefile as well. + */ + for (vma = vma_first(mm); vma != NULL; vma = vma_next(vma)) { + abi_ulong addr; + abi_ulong end; + + end = vma->vma_start + vma_dump_size(vma); + + for (addr = vma->vma_start; addr < end; + addr += TARGET_PAGE_SIZE) { + char page[TARGET_PAGE_SIZE]; + int error; + + /* + * Read in page from target process memory and + * write it to coredump file. + */ + error = copy_from_user(page, addr, sizeof (page)); + if (error != 0) { + (void) fprintf(stderr, "unable to dump " TARGET_FMT_lx "\n", + addr); + errno = -error; + goto out; + } + if (dump_write(fd, page, TARGET_PAGE_SIZE) < 0) + goto out; + } + } + +out: + free_note_info(&info); + if (mm != NULL) + vma_delete(mm); + (void) close(fd); + + if (errno != 0) + return (-errno); + return (0); +} + +#endif /* USE_ELF_CORE_DUMP */ + static int load_aout_interp(void * exptr, int interp_fd) { printf("a.out interpreter not yet supported\n"); diff --git a/linux-user/i386/syscall_nr.h b/linux-user/i386/syscall_nr.h index 62662ccc5..3ef71ce00 100644 --- a/linux-user/i386/syscall_nr.h +++ b/linux-user/i386/syscall_nr.h @@ -327,3 +327,11 @@ #define TARGET_NR_timerfd 322 #define TARGET_NR_eventfd 323 #define TARGET_NR_fallocate 324 +#define TARGET_NR_timerfd_settime 325 +#define TARGET_NR_timerfd_gettime 326 +#define TARGET_NR_signalfd4 327 +#define TARGET_NR_eventfd2 328 +#define TARGET_NR_epoll_create1 329 +#define TARGET_NR_dup3 330 +#define TARGET_NR_pipe2 331 +#define TARGET_NR_inotify_init1 332 diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index ada7c697d..14c433ea2 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -115,6 +115,7 @@ static int prepare_binprm(struct linux_binprm *bprm) abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, abi_ulong stringp, int push_ptr) { + TaskState *ts = (TaskState *)thread_env->opaque; int n = sizeof(abi_ulong); abi_ulong envp; abi_ulong argv; @@ -133,13 +134,14 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, sp -= n; /* FIXME - handle put_user() failures */ put_user_ual(argc, sp); - + ts->info->arg_start = stringp; while (argc-- > 0) { /* FIXME - handle put_user() failures */ put_user_ual(stringp, argv); argv += n; stringp += target_strlen(stringp) + 1; } + ts->info->arg_end = stringp; /* FIXME - handle put_user() failures */ put_user_ual(0, argv); while (envc-- > 0) { @@ -155,45 +157,45 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, } int loader_exec(const char * filename, char ** argv, char ** envp, - struct target_pt_regs * regs, struct image_info *infop) + struct target_pt_regs * regs, struct image_info *infop, + struct linux_binprm *bprm) { - struct linux_binprm bprm; int retval; int i; - bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); + bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ - bprm.page[i] = 0; + bprm->page[i] = 0; retval = open(filename, O_RDONLY); if (retval < 0) return retval; - bprm.fd = retval; - bprm.filename = (char *)filename; - bprm.argc = count(argv); - bprm.argv = argv; - bprm.envc = count(envp); - bprm.envp = envp; + bprm->fd = retval; + bprm->filename = (char *)filename; + bprm->argc = count(argv); + bprm->argv = argv; + bprm->envc = count(envp); + bprm->envp = envp; - retval = prepare_binprm(&bprm); + retval = prepare_binprm(bprm); infop->host_argv = argv; if(retval>=0) { - if (bprm.buf[0] == 0x7f - && bprm.buf[1] == 'E' - && bprm.buf[2] == 'L' - && bprm.buf[3] == 'F') { + if (bprm->buf[0] == 0x7f + && bprm->buf[1] == 'E' + && bprm->buf[2] == 'L' + && bprm->buf[3] == 'F') { #ifndef TARGET_HAS_ELFLOAD32 - retval = load_elf_binary(&bprm,regs,infop); + retval = load_elf_binary(bprm,regs,infop); #else - retval = load_elf_binary_multi(&bprm, regs, infop); + retval = load_elf_binary_multi(bprm, regs, infop); #endif #if defined(TARGET_HAS_BFLT) - } else if (bprm.buf[0] == 'b' - && bprm.buf[1] == 'F' - && bprm.buf[2] == 'L' - && bprm.buf[3] == 'T') { - retval = load_flt_binary(&bprm,regs,infop); + } else if (bprm->buf[0] == 'b' + && bprm->buf[1] == 'F' + && bprm->buf[2] == 'L' + && bprm->buf[3] == 'T') { + retval = load_flt_binary(bprm,regs,infop); #endif } else { fprintf(stderr, "Unknown binary format\n"); @@ -209,7 +211,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp, /* Something went wrong, return the inode and free the argument pages*/ for (i=0 ; i<MAX_ARG_PAGES ; i++) { - free(bprm.page[i]); + free(bprm->page[i]); } return(retval); } diff --git a/linux-user/m68k/syscall_nr.h b/linux-user/m68k/syscall_nr.h index 0a802f43b..1c0ba07bf 100644 --- a/linux-user/m68k/syscall_nr.h +++ b/linux-user/m68k/syscall_nr.h @@ -320,3 +320,11 @@ #define TARGET_NR_timerfd 318 #define TARGET_NR_eventfd 319 #define TARGET_NR_fallocate 320 +#define TARGET_NR_timerfd_settime 321 +#define TARGET_NR_timerfd_gettime 322 +#define TARGET_NR_signalfd4 323 +#define TARGET_NR_eventfd2 324 +#define TARGET_NR_epoll_create1 325 +#define TARGET_NR_dup3 326 +#define TARGET_NR_pipe2 327 +#define TARGET_NR_inotify_init1 328 diff --git a/linux-user/main.c b/linux-user/main.c index 4832d3f86..7eabd0c22 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -25,6 +25,7 @@ #include <errno.h> #include <unistd.h> #include <sys/mman.h> +#include <sys/syscall.h> #include "qemu.h" #include "qemu-common.h" @@ -2319,6 +2320,27 @@ static void usage(void) THREAD CPUState *thread_env; +void task_settid(TaskState *ts) +{ + if (ts->ts_tid == 0) { +#ifdef USE_NPTL + ts->ts_tid = (pid_t)syscall(SYS_gettid); +#else + /* when no threads are used, tid becomes pid */ + ts->ts_tid = getpid(); +#endif + } +} + +void stop_all_tasks(void) +{ + /* + * We trust that when using NPTL, start_exclusive() + * handles thread stopping correctly. + */ + start_exclusive(); +} + /* Assumes contents are already zeroed. */ void init_task_state(TaskState *ts) { @@ -2338,6 +2360,7 @@ int main(int argc, char **argv, char **envp) const char *cpu_model; struct target_pt_regs regs1, *regs = ®s1; struct image_info info1, *info = &info1; + struct linux_binprm bprm; TaskState ts1, *ts = &ts1; CPUState *env; int optind; @@ -2467,6 +2490,8 @@ int main(int argc, char **argv, char **envp) /* Zero out image_info */ memset(info, 0, sizeof(struct image_info)); + memset(&bprm, 0, sizeof (bprm)); + /* Scan interp_prefix dir for replacement files. */ init_paths(interp_prefix); @@ -2543,7 +2568,16 @@ int main(int argc, char **argv, char **envp) } target_argv[target_argc] = NULL; - if (loader_exec(filename, target_argv, target_environ, regs, info) != 0) { + memset(ts, 0, sizeof(TaskState)); + init_task_state(ts); + /* build Task State */ + ts->info = info; + ts->bprm = &bprm; + env->opaque = ts; + task_settid(ts); + + if (loader_exec(filename, target_argv, target_environ, regs, + info, &bprm) != 0) { printf("Error loading %s\n", filename); _exit(1); } @@ -2579,12 +2613,6 @@ int main(int argc, char **argv, char **envp) syscall_init(); signal_init(); - /* build Task State */ - memset(ts, 0, sizeof(TaskState)); - init_task_state(ts); - ts->info = info; - env->opaque = ts; - #if defined(TARGET_I386) cpu_x86_set_cpl(env, 3); diff --git a/linux-user/mips/syscall_nr.h b/linux-user/mips/syscall_nr.h index f900ae23f..822861607 100644 --- a/linux-user/mips/syscall_nr.h +++ b/linux-user/mips/syscall_nr.h @@ -323,3 +323,12 @@ #define TARGET_NR_timerfd (TARGET_NR_Linux + 318) #define TARGET_NR_eventfd (TARGET_NR_Linux + 319) #define TARGET_NR_fallocate (TARGET_NR_Linux + 320) +#define TARGET_NR_timerfd_create (TARGET_NR_Linux + 321) +#define TARGET_NR_timerfd_gettime (TARGET_NR_Linux + 322) +#define TARGET_NR_timerfd_settime (TARGET_NR_Linux + 323) +#define TARGET_NR_signalfd4 (TARGET_NR_Linux + 324) +#define TARGET_NR_eventfd2 (TARGET_NR_Linux + 325) +#define TARGET_NR_epoll_create1 (TARGET_NR_Linux + 326) +#define TARGET_NR_dup3 (TARGET_NR_Linux + 327) +#define TARGET_NR_pipe2 (TARGET_NR_Linux + 328) +#define TARGET_NR_inotify_init1 (TARGET_NR_Linux + 329) diff --git a/linux-user/mips64/syscall_nr.h b/linux-user/mips64/syscall_nr.h index 28e1883b7..ee1d13414 100644 --- a/linux-user/mips64/syscall_nr.h +++ b/linux-user/mips64/syscall_nr.h @@ -282,3 +282,12 @@ #define TARGET_NR_timerfd (TARGET_NR_Linux + 277) #define TARGET_NR_eventfd (TARGET_NR_Linux + 278) #define TARGET_NR_fallocate (TARGET_NR_Linux + 279) +#define TARGET_NR_timerfd_create (TARGET_NR_Linux + 280) +#define TARGET_NR_timerfd_gettime (TARGET_NR_Linux + 281) +#define TARGET_NR_timerfd_settime (TARGET_NR_Linux + 282) +#define TARGET_NR_signalfd4 (TARGET_NR_Linux + 283) +#define TARGET_NR_eventfd2 (TARGET_NR_Linux + 284) +#define TARGET_NR_epoll_create1 (TARGET_NR_Linux + 285) +#define TARGET_NR_dup3 (TARGET_NR_Linux + 286) +#define TARGET_NR_pipe2 (TARGET_NR_Linux + 287) +#define TARGET_NR_inotify_init1 (TARGET_NR_Linux + 288) diff --git a/linux-user/mipsn32/syscall_nr.h b/linux-user/mipsn32/syscall_nr.h index a83c4c9b8..60a99ddf6 100644 --- a/linux-user/mipsn32/syscall_nr.h +++ b/linux-user/mipsn32/syscall_nr.h @@ -286,3 +286,12 @@ #define TARGET_NR_timerfd (TARGET_NR_Linux + 281) #define TARGET_NR_eventfd (TARGET_NR_Linux + 282) #define TARGET_NR_fallocate (TARGET_NR_Linux + 283) +#define TARGET_NR_timerfd_create (TARGET_NR_Linux + 284) +#define TARGET_NR_timerfd_gettime (TARGET_NR_Linux + 285) +#define TARGET_NR_timerfd_settime (TARGET_NR_Linux + 286) +#define TARGET_NR_signalfd4 (TARGET_NR_Linux + 287) +#define TARGET_NR_eventfd2 (TARGET_NR_Linux + 288) +#define TARGET_NR_epoll_create1 (TARGET_NR_Linux + 289) +#define TARGET_NR_dup3 (TARGET_NR_Linux + 290) +#define TARGET_NR_pipe2 (TARGET_NR_Linux + 291) +#define TARGET_NR_inotify_init1 (TARGET_NR_Linux + 292) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 6f300a040..aa22006ff 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -36,7 +36,7 @@ //#define DEBUG_MMAP #if defined(USE_NPTL) -pthread_mutex_t mmap_mutex; +pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER; static int __thread mmap_lock_count; void mmap_lock(void) @@ -281,7 +281,7 @@ unsigned long last_brk; */ /* page_init() marks pages used by the host as reserved to be sure not to use them. */ -static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) +abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) { abi_ulong addr, addr1, addr_start; int prot; diff --git a/linux-user/ppc/syscall_nr.h b/linux-user/ppc/syscall_nr.h index 8fa5bef3b..f54276ba3 100644 --- a/linux-user/ppc/syscall_nr.h +++ b/linux-user/ppc/syscall_nr.h @@ -323,3 +323,12 @@ #define TARGET_NR_eventfd 307 #define TARGET_NR_sync_file_range2 308 #define TARGET_NR_fallocate 309 +#define TARGET_NR_subpage_prot 310 +#define TARGET_NR_timerfd_settime 311 +#define TARGET_NR_timerfd_gettime 312 +#define TARGET_NR_signalfd4 313 +#define TARGET_NR_eventfd2 314 +#define TARGET_NR_epoll_create1 315 +#define TARGET_NR_dup3 316 +#define TARGET_NR_pipe2 317 +#define TARGET_NR_inotify_init1 318 diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 9454e668f..e04a31c69 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -18,6 +18,7 @@ #include "syscall.h" #include "target_signal.h" #include "gdbstub.h" +#include "sys-queue.h" #if defined(USE_NPTL) #define THREAD __thread @@ -44,6 +45,9 @@ struct image_info { abi_ulong entry; abi_ulong code_offset; abi_ulong data_offset; + abi_ulong saved_auxv; + abi_ulong arg_start; + abi_ulong arg_end; char **host_argv; int personality; }; @@ -87,7 +91,7 @@ struct emulated_sigtable { /* NOTE: we force a big alignment so that the stack stored after is aligned too */ typedef struct TaskState { - struct TaskState *next; + pid_t ts_tid; /* tid (or pid) of this task */ #ifdef TARGET_ARM /* FPA state */ FPA11 fpa; @@ -114,6 +118,7 @@ typedef struct TaskState { #endif int used; /* non zero if used */ struct image_info *info; + struct linux_binprm *bprm; struct emulated_sigtable sigtab[TARGET_NSIG]; struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ @@ -125,6 +130,8 @@ typedef struct TaskState { extern char *exec_path; void init_task_state(TaskState *ts); +void task_settid(TaskState *); +void stop_all_tasks(void); extern const char *qemu_uname_release; /* ??? See if we can avoid exposing so much of the loader internals. */ @@ -149,13 +156,15 @@ struct linux_binprm { char **argv; char **envp; char * filename; /* Name of binary */ + int (*core_dump)(int, const CPUState *); /* coredump routine */ }; void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, abi_ulong stringp, int push_ptr); int loader_exec(const char * filename, char ** argv, char ** envp, - struct target_pt_regs * regs, struct image_info *infop); + struct target_pt_regs * regs, struct image_info *infop, + struct linux_binprm *); int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, struct image_info * info); @@ -229,6 +238,7 @@ int target_msync(abi_ulong start, abi_ulong len, int flags); extern unsigned long last_brk; void mmap_lock(void); void mmap_unlock(void); +abi_ulong mmap_find_vma(abi_ulong, abi_ulong); void cpu_list_lock(void); void cpu_list_unlock(void); #if defined(USE_NPTL) diff --git a/linux-user/sh4/syscall_nr.h b/linux-user/sh4/syscall_nr.h index b29705c7a..262b23633 100644 --- a/linux-user/sh4/syscall_nr.h +++ b/linux-user/sh4/syscall_nr.h @@ -326,3 +326,11 @@ #define TARGET_NR_timerfd 322 #define TARGET_NR_eventfd 323 #define TARGET_NR_fallocate 324 +#define TARGET_NR_timerfd_settime 325 +#define TARGET_NR_timerfd_gettime 326 +#define TARGET_NR_signalfd4 327 +#define TARGET_NR_eventfd2 328 +#define TARGET_NR_epoll_create1 329 +#define TARGET_NR_dup3 330 +#define TARGET_NR_pipe2 331 +#define TARGET_NR_inotify_init1 332 diff --git a/linux-user/signal.c b/linux-user/signal.c index 371927e2a..6a34171aa 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -27,6 +27,7 @@ #include <errno.h> #include <assert.h> #include <sys/ucontext.h> +#include <sys/resource.h> #include "qemu.h" #include "qemu-common.h" @@ -287,6 +288,23 @@ static int fatal_signal (int sig) } } +/* returns 1 if given signal should dump core if not handled */ +static int core_dump_signal(int sig) +{ + switch (sig) { + case TARGET_SIGABRT: + case TARGET_SIGFPE: + case TARGET_SIGILL: + case TARGET_SIGQUIT: + case TARGET_SIGSEGV: + case TARGET_SIGTRAP: + case TARGET_SIGBUS: + return (1); + default: + return (0); + } +} + void signal_init(void) { struct sigaction act; @@ -352,13 +370,29 @@ static inline void free_sigqueue(CPUState *env, struct sigqueue *q) /* abort execution with signal */ static void QEMU_NORETURN force_sig(int sig) { - int host_sig; + TaskState *ts = (TaskState *)thread_env->opaque; + int host_sig, core_dumped = 0; struct sigaction act; host_sig = target_to_host_signal(sig); - fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", - sig, strsignal(host_sig)); gdb_signalled(thread_env, sig); + /* dump core if supported by target binary format */ + if (core_dump_signal(sig) && (ts->bprm->core_dump != NULL)) { + stop_all_tasks(); + core_dumped = + ((*ts->bprm->core_dump)(sig, thread_env) == 0); + } + if (core_dumped) { + /* we already dumped the core of target process, we don't want + * a coredump of qemu itself */ + struct rlimit nodump; + getrlimit(RLIMIT_CORE, &nodump); + nodump.rlim_cur=0; + setrlimit(RLIMIT_CORE, &nodump); + (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) - %s\n", + sig, strsignal(host_sig), "core dumped" ); + } + /* The proper exit code for dieing from an uncaught signal is * -<signal>. The kernel doesn't allow exit() or _exit() to pass * a negative value. To get the proper exit code we need to diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h index 6419570dd..5d1ac21ac 100644 --- a/linux-user/sparc/syscall_nr.h +++ b/linux-user/sparc/syscall_nr.h @@ -276,3 +276,12 @@ #define TARGET_NR_timerfd 312 #define TARGET_NR_eventfd 313 #define TARGET_NR_fallocate 314 +#define TARGET_NR_timerfd_settime 315 +#define TARGET_NR_timerfd_gettime 316 +#define TARGET_NR_signalfd4 317 +#define TARGET_NR_eventfd2 318 +#define TARGET_NR_epoll_create1 319 +#define TARGET_NR_dup3 320 +#define TARGET_NR_pipe2 321 +#define TARGET_NR_inotify_init1 322 +#define TARGET_NR_accept4 323 diff --git a/linux-user/sparc64/syscall_nr.h b/linux-user/sparc64/syscall_nr.h index 70bee8080..bdca2a733 100644 --- a/linux-user/sparc64/syscall_nr.h +++ b/linux-user/sparc64/syscall_nr.h @@ -313,3 +313,12 @@ #define TARGET_NR_timerfd 312 #define TARGET_NR_eventfd 313 #define TARGET_NR_fallocate 314 +#define TARGET_NR_timerfd_settime 315 +#define TARGET_NR_timerfd_gettime 316 +#define TARGET_NR_signalfd4 317 +#define TARGET_NR_eventfd2 318 +#define TARGET_NR_epoll_create1 319 +#define TARGET_NR_dup3 320 +#define TARGET_NR_pipe2 321 +#define TARGET_NR_inotify_init1 322 +#define TARGET_NR_accept4 323 diff --git a/linux-user/strace.c b/linux-user/strace.c index b4caffe1b..5ea9acb08 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -6,6 +6,9 @@ #include <sys/shm.h> #include <sys/select.h> #include <sys/types.h> +#include <sys/mount.h> +#include <sys/mman.h> +#include <linux/futex.h> #include <unistd.h> #include "qemu.h" @@ -21,6 +24,47 @@ struct syscallname { void (*result)(const struct syscallname *, abi_long); }; +#ifdef __GNUC__ +/* + * It is possible that target doesn't have syscall that uses + * following flags but we don't want the compiler to warn + * us about them being unused. Same applies to utility print + * functions. It is ok to keep them while not used. + */ +#define UNUSED __attribute__ ((unused)) +#else +#define UNUSED +#endif + +/* + * Structure used to translate flag values into strings. This is + * similar that is in the actual strace tool. + */ +struct flags { + abi_long f_value; /* flag */ + const char *f_string; /* stringified flag */ +}; + +/* common flags for all architectures */ +#define FLAG_GENERIC(name) { name, #name } +/* target specific flags (syscall_defs.h has TARGET_<flag>) */ +#define FLAG_TARGET(name) { TARGET_ ## name, #name } +/* end of flags array */ +#define FLAG_END { 0, NULL } + +UNUSED static const char *get_comma(int); +UNUSED static void print_pointer(abi_long, int); +UNUSED static void print_flags(const struct flags *, abi_long, int); +UNUSED static void print_at_dirfd(abi_long, int); +UNUSED static void print_file_mode(abi_long, int); +UNUSED static void print_open_flags(abi_long, int); +UNUSED static void print_syscall_prologue(const struct syscallname *); +UNUSED static void print_syscall_epilogue(const struct syscallname *); +UNUSED static void print_string(abi_long, int); +UNUSED static void print_raw_param(const char *, abi_long, int); +UNUSED static void print_timeval(abi_ulong, int); +UNUSED static void print_number(abi_long, int); + /* * Utility functions */ @@ -100,22 +144,6 @@ print_fdset(int n, abi_ulong target_fds_addr) } gemu_log("]"); } - -static void -print_timeval(abi_ulong tv_addr) -{ - if( tv_addr ) { - struct target_timeval *tv; - - tv = lock_user(VERIFY_READ, tv_addr, sizeof(*tv), 1); - if (!tv) - return; - gemu_log("{" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "}", - tv->tv_sec, tv->tv_usec); - unlock_user(tv, tv_addr, 0); - } else - gemu_log("NULL"); -} #endif /* @@ -142,7 +170,7 @@ print_newselect(const struct syscallname *name, gemu_log(","); print_fdset(arg1, arg4); gemu_log(","); - print_timeval(arg5); + print_timeval(arg5, 1); gemu_log(")"); /* save for use in the return output function below */ @@ -250,11 +278,1019 @@ print_syscall_ret_newselect(const struct syscallname *name, abi_long ret) gemu_log(","); print_fdset(newselect_arg1,newselect_arg4); gemu_log(","); - print_timeval(newselect_arg5); + print_timeval(newselect_arg5, 1); gemu_log(")\n"); } #endif +UNUSED static struct flags access_flags[] = { + FLAG_GENERIC(F_OK), + FLAG_GENERIC(R_OK), + FLAG_GENERIC(W_OK), + FLAG_GENERIC(X_OK), + FLAG_END, +}; + +UNUSED static struct flags at_file_flags[] = { +#ifdef AT_EACCESS + FLAG_GENERIC(AT_EACCESS), +#endif +#ifdef AT_SYMLINK_NOFOLLOW + FLAG_GENERIC(AT_SYMLINK_NOFOLLOW), +#endif + FLAG_END, +}; + +UNUSED static struct flags unlinkat_flags[] = { +#ifdef AT_REMOVEDIR + FLAG_GENERIC(AT_REMOVEDIR), +#endif + FLAG_END, +}; + +UNUSED static struct flags mode_flags[] = { + FLAG_GENERIC(S_IFSOCK), + FLAG_GENERIC(S_IFLNK), + FLAG_GENERIC(S_IFREG), + FLAG_GENERIC(S_IFBLK), + FLAG_GENERIC(S_IFDIR), + FLAG_GENERIC(S_IFCHR), + FLAG_GENERIC(S_IFIFO), + FLAG_END, +}; + +UNUSED static struct flags open_access_flags[] = { + FLAG_TARGET(O_RDONLY), + FLAG_TARGET(O_WRONLY), + FLAG_TARGET(O_RDWR), + FLAG_END, +}; + +UNUSED static struct flags open_flags[] = { + FLAG_TARGET(O_APPEND), + FLAG_TARGET(O_CREAT), + FLAG_TARGET(O_DIRECTORY), + FLAG_TARGET(O_EXCL), + FLAG_TARGET(O_LARGEFILE), + FLAG_TARGET(O_NOCTTY), + FLAG_TARGET(O_NOFOLLOW), + FLAG_TARGET(O_NONBLOCK), /* also O_NDELAY */ + FLAG_TARGET(O_SYNC), + FLAG_TARGET(O_TRUNC), +#ifdef O_DIRECT + FLAG_TARGET(O_DIRECT), +#endif + FLAG_END, +}; + +UNUSED static struct flags mount_flags[] = { +#ifdef MS_BIND + FLAG_GENERIC(MS_BIND), +#endif +#ifdef MS_DIRSYNC + FLAG_GENERIC(MS_DIRSYNC), +#endif + FLAG_GENERIC(MS_MANDLOCK), +#ifdef MS_MOVE + FLAG_GENERIC(MS_MOVE), +#endif + FLAG_GENERIC(MS_NOATIME), + FLAG_GENERIC(MS_NODEV), + FLAG_GENERIC(MS_NODIRATIME), + FLAG_GENERIC(MS_NOEXEC), + FLAG_GENERIC(MS_NOSUID), + FLAG_GENERIC(MS_RDONLY), +#ifdef MS_RELATIME + FLAG_GENERIC(MS_RELATIME), +#endif + FLAG_GENERIC(MS_REMOUNT), + FLAG_GENERIC(MS_SYNCHRONOUS), + FLAG_END, +}; + +UNUSED static struct flags umount2_flags[] = { +#ifdef MNT_FORCE + FLAG_GENERIC(MNT_FORCE), +#endif +#ifdef MNT_DETACH + FLAG_GENERIC(MNT_DETACH), +#endif +#ifdef MNT_EXPIRE + FLAG_GENERIC(MNT_EXPIRE), +#endif + FLAG_END, +}; + +UNUSED static struct flags mmap_prot_flags[] = { + FLAG_GENERIC(PROT_NONE), + FLAG_GENERIC(PROT_EXEC), + FLAG_GENERIC(PROT_READ), + FLAG_GENERIC(PROT_WRITE), + FLAG_END, +}; + +UNUSED static struct flags mmap_flags[] = { + FLAG_TARGET(MAP_SHARED), + FLAG_TARGET(MAP_PRIVATE), + FLAG_TARGET(MAP_ANONYMOUS), + FLAG_TARGET(MAP_DENYWRITE), + FLAG_TARGET(MAP_FIXED), + FLAG_TARGET(MAP_GROWSDOWN), +#ifdef MAP_LOCKED + FLAG_TARGET(MAP_LOCKED), +#endif +#ifdef MAP_NONBLOCK + FLAG_TARGET(MAP_NONBLOCK), +#endif + FLAG_TARGET(MAP_NORESERVE), +#ifdef MAP_POPULATE + FLAG_TARGET(MAP_POPULATE), +#endif + FLAG_END, +}; + +UNUSED static struct flags fcntl_flags[] = { + FLAG_TARGET(F_DUPFD), + FLAG_TARGET(F_GETFD), + FLAG_TARGET(F_SETFD), + FLAG_TARGET(F_GETFL), + FLAG_TARGET(F_SETFL), + FLAG_TARGET(F_GETLK), + FLAG_TARGET(F_SETLK), + FLAG_TARGET(F_SETLKW), + FLAG_END, +}; + +/* + * print_xxx utility functions. These are used to print syscall + * parameters in certain format. All of these have parameter + * named 'last'. This parameter is used to add comma to output + * when last == 0. + */ + +static const char * +get_comma(int last) +{ + return ((last) ? "" : ","); +} + +static void +print_flags(const struct flags *f, abi_long tflags, int last) +{ + const char *sep = ""; + int flags; + int n; + + flags = (int)tswap32(tflags); + + if ((flags == 0) && (f->f_value == 0)) { + gemu_log("%s%s", f->f_string, get_comma(last)); + return; + } + for (n = 0; f->f_string != NULL; f++) { + if ((f->f_value != 0) && ((flags & f->f_value) == f->f_value)) { + gemu_log("%s%s", sep, f->f_string); + flags &= ~f->f_value; + sep = "|"; + n++; + } + } + + if (n > 0) { + /* print rest of the flags as numeric */ + if (flags != 0) { + gemu_log("%s%#x%s", sep, flags, get_comma(last)); + } else { + gemu_log("%s", get_comma(last)); + } + } else { + /* no string version of flags found, print them in hex then */ + gemu_log("%#x%s", flags, get_comma(last)); + } +} + +static void +print_at_dirfd(abi_long tdirfd, int last) +{ + int dirfd = tswap32(tdirfd); + +#ifdef AT_FDCWD + if (dirfd == AT_FDCWD) { + gemu_log("AT_FDCWD%s", get_comma(last)); + return; + } +#endif + gemu_log("%d%s", dirfd, get_comma(last)); +} + +static void +print_file_mode(abi_long tmode, int last) +{ + const char *sep = ""; + const struct flags *m; + mode_t mode = (mode_t)tswap32(tmode); + + for (m = &mode_flags[0]; m->f_string != NULL; m++) { + if ((m->f_value & mode) == m->f_value) { + gemu_log("%s%s", m->f_string, sep); + sep = "|"; + mode &= ~m->f_value; + break; + } + } + + mode &= ~S_IFMT; + /* print rest of the mode as octal */ + if (mode != 0) + gemu_log("%s%#o", sep, mode); + + gemu_log("%s", get_comma(last)); +} + +static void +print_open_flags(abi_long tflags, int last) +{ + int flags = tswap32(tflags); + + print_flags(open_access_flags, flags & TARGET_O_ACCMODE, 1); + flags &= ~TARGET_O_ACCMODE; + if (flags == 0) { + gemu_log("%s", get_comma(last)); + return; + } + gemu_log("|"); + print_flags(open_flags, flags, last); +} + +static void +print_syscall_prologue(const struct syscallname *sc) +{ + gemu_log("%s(", sc->name); +} + +/*ARGSUSED*/ +static void +print_syscall_epilogue(const struct syscallname *sc) +{ + (void)sc; + gemu_log(")"); +} + +static void +print_string(abi_long addr, int last) +{ + char *s; + + if ((s = lock_user_string(addr)) != NULL) { + gemu_log("\"%s\"%s", s, get_comma(last)); + unlock_user(s, addr, 0); + } else { + /* can't get string out of it, so print it as pointer */ + print_pointer(addr, last); + } +} + +/* + * Prints out raw parameter using given format. Caller needs + * to do byte swapping if needed. + */ +static void +print_raw_param(const char *fmt, abi_long param, int last) +{ + char format[64]; + + (void) snprintf(format, sizeof (format), "%s%s", fmt, get_comma(last)); + gemu_log(format, param); +} + +static void +print_pointer(abi_long p, int last) +{ + if (p == 0) + gemu_log("NULL%s", get_comma(last)); + else + gemu_log("0x" TARGET_ABI_FMT_lx "%s", p, get_comma(last)); +} + +/* + * Reads 32-bit (int) number from guest address space from + * address 'addr' and prints it. + */ +static void +print_number(abi_long addr, int last) +{ + if (addr == 0) { + gemu_log("NULL%s", get_comma(last)); + } else { + int num; + + get_user_s32(num, addr); + gemu_log("[%d]%s", num, get_comma(last)); + } +} + +static void +print_timeval(abi_ulong tv_addr, int last) +{ + if( tv_addr ) { + struct target_timeval *tv; + + tv = lock_user(VERIFY_READ, tv_addr, sizeof(*tv), 1); + if (!tv) + return; + gemu_log("{" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "}%s", + tv->tv_sec, tv->tv_usec, get_comma(last)); + unlock_user(tv, tv_addr, 0); + } else + gemu_log("NULL%s", get_comma(last)); +} + +#undef UNUSED + +#ifdef TARGET_NR_accept +static void +print_accept(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_raw_param("%d", tswap32(arg0), 0); + print_pointer(arg1, 0); + print_number(arg2, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_access +static void +print_access(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_flags(access_flags, arg1, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_brk +static void +print_brk(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_pointer(arg0, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_chdir +static void +print_chdir(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_chmod +static void +print_chmod(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_file_mode(arg1, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_creat +static void +print_creat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_file_mode(arg1, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_execv +static void +print_execv(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_raw_param("0x" TARGET_ABI_FMT_lx, tswapl(arg1), 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_faccessat +static void +print_faccessat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_at_dirfd(arg0, 0); + print_string(arg1, 0); + print_flags(access_flags, arg2, 0); + print_flags(at_file_flags, arg3, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_fchmodat +static void +print_fchmodat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_at_dirfd(arg0, 0); + print_string(arg1, 0); + print_file_mode(arg2, 0); + print_flags(at_file_flags, arg3, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_fchownat +static void +print_fchownat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_at_dirfd(arg0, 0); + print_string(arg1, 0); +#ifdef USE_UID16 + print_raw_param("%d", tswap16(arg2), 0); + print_raw_param("%d", tswap16(arg3), 0); +#else + print_raw_param("%d", tswap32(arg2), 0); + print_raw_param("%d", tswap32(arg3), 0); +#endif + print_flags(at_file_flags, arg4, 1); + print_syscall_epilogue(name); +} +#endif + +#if defined(TARGET_NR_fcntl) || defined(TARGET_NR_fcntl64) +static void +print_fcntl(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_raw_param("%d", tswap32(arg0), 0); + print_flags(fcntl_flags, arg1, 0); + /* + * TODO: check flags and print following argument only + * when needed. + */ + print_pointer(arg2, 1); + print_syscall_epilogue(name); +} +#define print_fcntl64 print_fcntl +#endif + + +#ifdef TARGET_NR_futimesat +static void +print_futimesat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_at_dirfd(arg0, 0); + print_string(arg1, 0); + print_timeval(arg2, 0); + print_timeval(arg2 + sizeof (struct target_timeval), 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_link +static void +print_link(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_string(arg1, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_linkat +static void +print_linkat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_at_dirfd(arg0, 0); + print_string(arg1, 0); + print_at_dirfd(arg2, 0); + print_string(arg3, 0); + print_flags(at_file_flags, arg4, 1); + print_syscall_epilogue(name); +} +#endif + +#if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) || \ + defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64) +static void +print_stat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_pointer(arg1, 1); + print_syscall_epilogue(name); +} +#define print_lstat print_stat +#define print_stat64 print_stat +#define print_lstat64 print_stat +#endif + +#if defined(TARGET_NR_fstat) || defined(TARGET_NR_fstat64) +static void +print_fstat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_raw_param("%d", tswap32(arg0), 0); + print_pointer(arg1, 1); + print_syscall_epilogue(name); +} +#define print_fstat64 print_fstat +#endif + +#ifdef TARGET_NR_mkdir +static void +print_mkdir(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_file_mode(arg1, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_mkdirat +static void +print_mkdirat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_at_dirfd(arg0, 0); + print_string(arg1, 0); + print_file_mode(arg2, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_mknod +static void +print_mknod(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + int hasdev = (tswapl(arg1) & (S_IFCHR|S_IFBLK)); + + print_syscall_prologue(name); + print_string(arg0, 0); + print_file_mode(arg1, (hasdev == 0)); + if (hasdev) { + print_raw_param("makedev(%d", major(tswapl(arg2)), 0); + print_raw_param("%d)", minor(tswapl(arg2)), 1); + } + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_mknodat +static void +print_mknodat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + int hasdev = (tswapl(arg2) & (S_IFCHR|S_IFBLK)); + + print_syscall_prologue(name); + print_at_dirfd(arg0, 0); + print_string(arg1, 0); + print_file_mode(arg2, (hasdev == 0)); + if (hasdev) { + print_raw_param("makedev(%d", major(tswapl(arg3)), 0); + print_raw_param("%d)", minor(tswapl(arg3)), 1); + } + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_mq_open +static void +print_mq_open(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + int is_creat = (tswapl(arg1) & TARGET_O_CREAT); + + print_syscall_prologue(name); + print_string(arg0, 0); + print_open_flags(arg1, (is_creat == 0)); + if (is_creat) { + print_file_mode(arg2, 0); + print_pointer(arg3, 1); + } + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_open +static void +print_open(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + int is_creat = (tswap32(arg1) & TARGET_O_CREAT); + + print_syscall_prologue(name); + print_string(arg0, 0); + print_open_flags(arg1, (is_creat == 0)); + if (is_creat) + print_file_mode(arg2, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_openat +static void +print_openat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + int is_creat = (tswap32(arg2) & TARGET_O_CREAT); + + print_syscall_prologue(name); + print_at_dirfd(arg0, 0); + print_string(arg1, 0); + print_open_flags(arg2, (is_creat == 0)); + if (is_creat) + print_file_mode(arg3, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_mq_unlink +static void +print_mq_unlink(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 1); + print_syscall_epilogue(name); +} +#endif + +#if defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat) +static void +print_fstatat64(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_at_dirfd(arg0, 0); + print_string(arg1, 0); + print_pointer(arg2, 0); + print_flags(at_file_flags, arg3, 1); + print_syscall_epilogue(name); +} +#define print_newfstatat print_fstatat64 +#endif + +#ifdef TARGET_NR_readlink +static void +print_readlink(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_pointer(arg1, 0); + print_raw_param("%u", tswapl(arg2), 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_readlinkat +static void +print_readlinkat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_at_dirfd(arg0, 0); + print_string(arg1, 0); + print_pointer(arg2, 0); + print_raw_param("%u", tswapl(arg3), 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_rename +static void +print_rename(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_string(arg1, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_renameat +static void +print_renameat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_at_dirfd(arg0, 0); + print_string(arg1, 0); + print_at_dirfd(arg2, 0); + print_string(arg3, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_statfs +static void +print_statfs(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_pointer(arg1, 1); + print_syscall_epilogue(name); +} +#define print_statfs64 print_statfs +#endif + +#ifdef TARGET_NR_symlink +static void +print_symlink(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_string(arg1, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_symlinkat +static void +print_symlinkat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_at_dirfd(arg1, 0); + print_string(arg2, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_mount +static void +print_mount(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_string(arg1, 0); + print_string(arg2, 0); + print_flags(mount_flags, arg3, 0); + print_pointer(arg4, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_umount +static void +print_umount(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_umount2 +static void +print_umount2(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_flags(umount2_flags, arg1, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_unlink +static void +print_unlink(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_unlinkat +static void +print_unlinkat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_at_dirfd(arg0, 0); + print_string(arg1, 0); + print_flags(unlinkat_flags, arg2, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_utime +static void +print_utime(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_pointer(arg1, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_utimes +static void +print_utimes(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_string(arg0, 0); + print_pointer(arg1, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_utimensat +static void +print_utimensat(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_at_dirfd(arg0, 0); + print_string(arg1, 0); + print_pointer(arg2, 0); + print_flags(at_file_flags, arg3, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_mmap +static void +print_mmap(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_pointer(arg0, 0); + print_raw_param("%d", tswapl(arg1), 0); + print_flags(mmap_prot_flags, arg2, 0); + print_flags(mmap_flags, arg3, 0); + print_raw_param("%d", tswapl(arg4), 0); + print_raw_param("%#x", tswapl(arg5), 1); + print_syscall_epilogue(name); +} +#define print_mmap2 print_mmap +#endif + +#ifdef TARGET_NR_mprotect +static void +print_mprotect(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_pointer(arg0, 0); + print_raw_param("%d", tswapl(arg1), 0); + print_flags(mmap_prot_flags, arg2, 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_munmap +static void +print_munmap(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_pointer(arg0, 0); + print_raw_param("%d", tswapl(arg1), 1); + print_syscall_epilogue(name); +} +#endif + +#ifdef TARGET_NR_futex +static void print_futex_op(abi_long tflag, int last) +{ +#define print_op(val) \ +if( cmd == val ) { \ + gemu_log(#val); \ + return; \ +} + + int cmd = (int)tswap32(tflag); +#ifdef FUTEX_PRIVATE_FLAG + if (cmd == FUTEX_PRIVATE_FLAG) + gemu_log("FUTEX_PRIVATE_FLAG|"); +#endif + print_op(FUTEX_WAIT) + print_op(FUTEX_WAKE) + print_op(FUTEX_FD) + print_op(FUTEX_REQUEUE) + print_op(FUTEX_CMP_REQUEUE) + print_op(FUTEX_WAKE_OP) + print_op(FUTEX_LOCK_PI) + print_op(FUTEX_UNLOCK_PI) + print_op(FUTEX_TRYLOCK_PI) +#ifdef FUTEX_WAIT_BITSET + print_op(FUTEX_WAIT_BITSET) +#endif +#ifdef FUTEX_WAKE_BITSET + print_op(FUTEX_WAKE_BITSET) +#endif + /* unknown values */ + gemu_log("%d",cmd); +} + +static void +print_futex(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_pointer(arg0, 0); + print_futex_op(arg1, 0); + print_raw_param(",%d", tswapl(arg2), 0); + print_pointer(arg3, 0); /* struct timespec */ + print_pointer(arg4, 0); + print_raw_param("%d", tswapl(arg4), 1); + print_syscall_epilogue(name); +} +#endif + /* * An array of all of the syscalls we know about */ diff --git a/linux-user/strace.list b/linux-user/strace.list index 3f688dbca..97b7f7691 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -1,8 +1,13 @@ +/* + * Note that if you change format strings in these, check also + * that corresponding print functions are able to handle string + * locking correctly (see strace.c). + */ #ifdef TARGET_NR_accept -{ TARGET_NR_accept, "accept" , "%s(%d,%#x,%#x)", NULL, NULL }, +{ TARGET_NR_accept, "accept" , NULL, print_accept, NULL }, #endif #ifdef TARGET_NR_access -{ TARGET_NR_access, "access" , "%s(\"%s\",%#o)", NULL, NULL }, +{ TARGET_NR_access, "access" , NULL, print_access, NULL }, #endif #ifdef TARGET_NR_acct { TARGET_NR_acct, "acct" , NULL, NULL, NULL }, @@ -38,7 +43,7 @@ { TARGET_NR_break, "break" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_brk -{ TARGET_NR_brk, "brk" , NULL, NULL, print_syscall_ret_addr }, +{ TARGET_NR_brk, "brk" , NULL, print_brk, print_syscall_ret_addr }, #endif #ifdef TARGET_NR_cachectl { TARGET_NR_cachectl, "cachectl" , NULL, NULL, NULL }, @@ -53,10 +58,10 @@ { TARGET_NR_capset, "capset" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_chdir -{ TARGET_NR_chdir, "chdir" , "%s(\"%s\")", NULL, NULL }, +{ TARGET_NR_chdir, "chdir" , NULL, print_chdir, NULL }, #endif #ifdef TARGET_NR_chmod -{ TARGET_NR_chmod, "chmod" , "%s(\"%s\",%#o)", NULL, NULL }, +{ TARGET_NR_chmod, "chmod" , NULL, print_chmod, NULL }, #endif #ifdef TARGET_NR_chown { TARGET_NR_chown, "chown" , NULL, NULL, NULL }, @@ -89,7 +94,7 @@ { TARGET_NR_connect, "connect" , "%s(%d,%#x,%d)", NULL, NULL }, #endif #ifdef TARGET_NR_creat -{ TARGET_NR_creat, "creat" , "%s(\"%s\",%#o)", NULL, NULL }, +{ TARGET_NR_creat, "creat" , NULL, print_creat, NULL }, #endif #ifdef TARGET_NR_create_module { TARGET_NR_create_module, "create_module" , NULL, NULL, NULL }, @@ -122,7 +127,7 @@ { TARGET_NR_epoll_wait_old, "epoll_wait_old" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_execv -{ TARGET_NR_execv, "execv" , "%s(\"%s\",%ld,%ld,%ld,%ld,%ld)\n", NULL, NULL }, +{ TARGET_NR_execv, "execv" , NULL, print_execv, NULL }, #endif #ifdef TARGET_NR_execve { TARGET_NR_execve, "execve" , NULL, print_execve, NULL }, @@ -140,7 +145,7 @@ { TARGET_NR_exit_group, "exit_group" , "%s(%d)\n", NULL, NULL }, #endif #ifdef TARGET_NR_faccessat -{ TARGET_NR_faccessat, "faccessat" , "%s(%d,\"%s\",%#o,%#x)", NULL, NULL }, +{ TARGET_NR_faccessat, "faccessat" , NULL, print_faccessat, NULL }, #endif #ifdef TARGET_NR_fadvise64 { TARGET_NR_fadvise64, "fadvise64" , NULL, NULL, NULL }, @@ -155,22 +160,22 @@ { TARGET_NR_fchmod, "fchmod" , "%s(%d,%#o)", NULL, NULL }, #endif #ifdef TARGET_NR_fchmodat -{ TARGET_NR_fchmodat, "fchmodat" , "%s(%d,\"%s\",%#o,%#x)", NULL, NULL }, +{ TARGET_NR_fchmodat, "fchmodat" , NULL, print_fchmodat, NULL }, #endif #ifdef TARGET_NR_fchown -{ TARGET_NR_fchown, "fchown" , "%s(\"%s\",%d,%d)", NULL, NULL }, +{ TARGET_NR_fchown, "fchown" , "%s(%d,%d,%d)", NULL, NULL }, #endif #ifdef TARGET_NR_fchown32 { TARGET_NR_fchown32, "fchown32" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_fchownat -{ TARGET_NR_fchownat, "fchownat" , "%s(%d,\"%s\",%d,%d,%#x)", NULL, NULL }, +{ TARGET_NR_fchownat, "fchownat" , NULL, print_fchownat, NULL }, #endif #ifdef TARGET_NR_fcntl -{ TARGET_NR_fcntl, "fcntl" , NULL, NULL, NULL }, +{ TARGET_NR_fcntl, "fcntl" , NULL, print_fcntl, NULL }, #endif #ifdef TARGET_NR_fcntl64 -{ TARGET_NR_fcntl64, "fcntl64" , NULL, NULL, NULL }, +{ TARGET_NR_fcntl64, "fcntl64" , NULL, print_fcntl64, NULL }, #endif #ifdef TARGET_NR_fdatasync { TARGET_NR_fdatasync, "fdatasync" , NULL, NULL, NULL }, @@ -194,10 +199,10 @@ { TARGET_NR_fsetxattr, "fsetxattr" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_fstat -{ TARGET_NR_fstat, "fstat" , "%s(%d,%p)", NULL, NULL }, +{ TARGET_NR_fstat, "fstat" , NULL, print_fstat, NULL }, #endif #ifdef TARGET_NR_fstat64 -{ TARGET_NR_fstat64, "fstat64" , "%s(%d,%p)", NULL, NULL }, +{ TARGET_NR_fstat64, "fstat64" , NULL, print_fstat64, NULL }, #endif #ifdef TARGET_NR_fstatfs { TARGET_NR_fstatfs, "fstatfs" , "%s(%d,%p)", NULL, NULL }, @@ -218,10 +223,10 @@ { TARGET_NR_ftruncate64, "ftruncate64" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_futex -{ TARGET_NR_futex, "futex" , NULL, NULL, NULL }, +{ TARGET_NR_futex, "futex" , NULL, print_futex, NULL }, #endif #ifdef TARGET_NR_futimesat -{ TARGET_NR_futimesat, "futimesat" , "%s(%d,\"%s\",%p)", NULL, NULL }, +{ TARGET_NR_futimesat, "futimesat" , NULL, print_futimesat, NULL }, #endif #ifdef TARGET_NR_getcwd { TARGET_NR_getcwd, "getcwd" , "%s(%p,%d)", NULL, NULL }, @@ -425,10 +430,10 @@ { TARGET_NR_lgetxattr, "lgetxattr" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_link -{ TARGET_NR_link, "link" , "%s(\"%s\",\"%s\")", NULL, NULL }, +{ TARGET_NR_link, "link" , NULL, print_link, NULL }, #endif #ifdef TARGET_NR_linkat -{ TARGET_NR_linkat, "linkat" , "%s(%d,\"%s\",%d,\"%s\",%#x)", NULL, NULL }, +{ TARGET_NR_linkat, "linkat" , NULL, print_linkat, NULL }, #endif #ifdef TARGET_NR_Linux { TARGET_NR_Linux, "Linux" , NULL, NULL, NULL }, @@ -461,10 +466,10 @@ { TARGET_NR_lsetxattr, "lsetxattr" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_lstat -{ TARGET_NR_lstat, "lstat" , "%s(\"%s\",%p)", NULL, NULL }, +{ TARGET_NR_lstat, "lstat" , NULL, print_lstat, NULL }, #endif #ifdef TARGET_NR_lstat64 -{ TARGET_NR_lstat64, "lstat64" , "%s(\"%s\",%p)", NULL, NULL }, +{ TARGET_NR_lstat64, "lstat64" , NULL, print_lstat64, NULL }, #endif #ifdef TARGET_NR_madvise { TARGET_NR_madvise, "madvise" , NULL, NULL, NULL }, @@ -485,16 +490,16 @@ { TARGET_NR_mincore, "mincore" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_mkdir -{ TARGET_NR_mkdir, "mkdir" , "%s(\"%s\",%#o)", NULL, NULL }, +{ TARGET_NR_mkdir, "mkdir" , NULL, print_mkdir, NULL }, #endif #ifdef TARGET_NR_mkdirat -{ TARGET_NR_mkdirat, "mkdirat" , "%s(%d,\"%s\",%#o)", NULL, NULL }, +{ TARGET_NR_mkdirat, "mkdirat" , NULL, print_mkdirat, NULL }, #endif #ifdef TARGET_NR_mknod -{ TARGET_NR_mknod, "mknod" , "%s(\"%s\",%#o,%#x)", NULL, NULL }, +{ TARGET_NR_mknod, "mknod" , NULL, print_mknod, NULL }, #endif #ifdef TARGET_NR_mknodat -{ TARGET_NR_mknodat, "mknodat" , "%s(%d,\"%s\",%#o,%#x)", NULL, NULL }, +{ TARGET_NR_mknodat, "mknodat" , NULL, print_mknodat, NULL }, #endif #ifdef TARGET_NR_mlock { TARGET_NR_mlock, "mlock" , NULL, NULL, NULL }, @@ -503,22 +508,22 @@ { TARGET_NR_mlockall, "mlockall" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_mmap -{ TARGET_NR_mmap, "mmap" , NULL, NULL, print_syscall_ret_addr }, +{ TARGET_NR_mmap, "mmap" , NULL, print_mmap, print_syscall_ret_addr }, #endif #ifdef TARGET_NR_mmap2 -{ TARGET_NR_mmap2, "mmap2" , NULL, NULL, print_syscall_ret_addr }, +{ TARGET_NR_mmap2, "mmap2" , NULL, print_mmap2, print_syscall_ret_addr }, #endif #ifdef TARGET_NR_modify_ldt { TARGET_NR_modify_ldt, "modify_ldt" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_mount -{ TARGET_NR_mount, "mount" , NULL, NULL, NULL }, +{ TARGET_NR_mount, "mount" , NULL, print_mount, NULL }, #endif #ifdef TARGET_NR_move_pages { TARGET_NR_move_pages, "move_pages" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_mprotect -{ TARGET_NR_mprotect, "mprotect" , NULL, NULL, NULL }, +{ TARGET_NR_mprotect, "mprotect" , NULL, print_mprotect, NULL }, #endif #ifdef TARGET_NR_mpx { TARGET_NR_mpx, "mpx" , NULL, NULL, NULL }, @@ -530,7 +535,7 @@ { TARGET_NR_mq_notify, "mq_notify" , "%s(%d,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_mq_open -{ TARGET_NR_mq_open, "mq_open" , "%s(\"/%s\",%#x,%#o,%p)", NULL, NULL }, +{ TARGET_NR_mq_open, "mq_open" , NULL, print_mq_open, NULL }, #endif #ifdef TARGET_NR_mq_timedreceive { TARGET_NR_mq_timedreceive, "mq_timedreceive" , "%s(%d,%p,%d,%u,%p)", NULL, NULL }, @@ -539,7 +544,7 @@ { TARGET_NR_mq_timedsend, "mq_timedsend" , "%s(%d,%p,%d,%u,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_mq_unlink -{ TARGET_NR_mq_unlink, "mq_unlink" , "%s(%s)", NULL, NULL }, +{ TARGET_NR_mq_unlink, "mq_unlink" , NULL, print_mq_unlink, NULL }, #endif #ifdef TARGET_NR_mremap { TARGET_NR_mremap, "mremap" , NULL, NULL, NULL }, @@ -569,16 +574,16 @@ { TARGET_NR_munlockall, "munlockall" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_munmap -{ TARGET_NR_munmap, "munmap" , "%s(%p,%d)", NULL, NULL }, +{ TARGET_NR_munmap, "munmap" , NULL, print_munmap, NULL }, #endif #ifdef TARGET_NR_nanosleep { TARGET_NR_nanosleep, "nanosleep" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_fstatat64 -{ TARGET_NR_fstatat64, "fstatat64" , "%s(%d,\"%s\",%p,%#x)", NULL, NULL }, +{ TARGET_NR_fstatat64, "fstatat64" , NULL, print_fstatat64, NULL }, #endif #ifdef TARGET_NR_newfstatat -{ TARGET_NR_newfstatat, "newfstatat" , "%s(%d,\"%s\",%p,%#x)", NULL, NULL }, +{ TARGET_NR_newfstatat, "newfstatat" , NULL, print_newfstatat, NULL }, #endif #ifdef TARGET_NR__newselect { TARGET_NR__newselect, "_newselect" , NULL, print_newselect, print_syscall_ret_newselect }, @@ -611,10 +616,10 @@ { TARGET_NR_olduname, "olduname" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_open -{ TARGET_NR_open, "open" , "%s(\"%s\",%#x,%#o)", NULL, NULL }, +{ TARGET_NR_open, "open" , NULL, print_open, NULL }, #endif #ifdef TARGET_NR_openat -{ TARGET_NR_openat, "openat" , "%s(%d,\"%s\",%#x,%#o)", NULL, NULL }, +{ TARGET_NR_openat, "openat" , NULL, print_openat, NULL }, #endif #ifdef TARGET_NR_osf_adjtime { TARGET_NR_osf_adjtime, "osf_adjtime" , NULL, NULL, NULL }, @@ -1007,10 +1012,10 @@ { TARGET_NR_readdir, "readdir" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_readlink -{ TARGET_NR_readlink, "readlink" , "%s(\"%s\",%p,%d)", NULL, NULL }, +{ TARGET_NR_readlink, "readlink" , NULL, print_readlink, NULL }, #endif #ifdef TARGET_NR_readlinkat -{ TARGET_NR_readlinkat, "readlinkat" , "%s(%d,\"%s\",%p,%d)", NULL, NULL }, +{ TARGET_NR_readlinkat, "readlinkat" , NULL, print_readlinkat, NULL }, #endif #ifdef TARGET_NR_readv { TARGET_NR_readv, "readv" , NULL, NULL, NULL }, @@ -1034,10 +1039,10 @@ { TARGET_NR_removexattr, "removexattr" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_rename -{ TARGET_NR_rename, "rename" , "%s(\"%s\",\"%s\")", NULL, NULL }, +{ TARGET_NR_rename, "rename" , NULL, print_rename, NULL }, #endif #ifdef TARGET_NR_renameat -{ TARGET_NR_renameat, "renameat" , "%s(%d,\"%s\",%d,\"%s\")", NULL, NULL }, +{ TARGET_NR_renameat, "renameat" , NULL, print_renameat, NULL }, #endif #ifdef TARGET_NR_request_key { TARGET_NR_request_key, "request_key" , NULL, NULL, NULL }, @@ -1301,16 +1306,16 @@ { TARGET_NR_ssetmask, "ssetmask" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_stat -{ TARGET_NR_stat, "stat" , "%s(\"%s\",%p)", NULL, NULL }, +{ TARGET_NR_stat, "stat" , NULL, print_stat, NULL }, #endif #ifdef TARGET_NR_stat64 -{ TARGET_NR_stat64, "stat64" , "%s(\"%s\",%p)", NULL, NULL }, +{ TARGET_NR_stat64, "stat64" , NULL, print_stat64, NULL }, #endif #ifdef TARGET_NR_statfs -{ TARGET_NR_statfs, "statfs" , "%s(\"%s\",%p)", NULL, NULL }, +{ TARGET_NR_statfs, "statfs" , NULL, print_statfs, NULL }, #endif #ifdef TARGET_NR_statfs64 -{ TARGET_NR_statfs64, "statfs64" , "%s(\"%s\",%p)", NULL, NULL }, +{ TARGET_NR_statfs64, "statfs64" , NULL, print_statfs64, NULL }, #endif #ifdef TARGET_NR_stime { TARGET_NR_stime, "stime" , NULL, NULL, NULL }, @@ -1334,10 +1339,10 @@ { TARGET_NR_swapon, "swapon" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_symlink -{ TARGET_NR_symlink, "symlink" , "%s(\"%s\",\"%s\")", NULL, NULL }, +{ TARGET_NR_symlink, "symlink" , NULL, print_symlink, NULL }, #endif #ifdef TARGET_NR_symlinkat -{ TARGET_NR_symlinkat, "symlinkat" , "%s(\"%s\",%d,\"%s\")", NULL, NULL }, +{ TARGET_NR_symlinkat, "symlinkat", NULL, print_symlinkat, NULL }, #endif #ifdef TARGET_NR_sync { TARGET_NR_sync, "sync" , NULL, NULL, NULL }, @@ -1427,19 +1432,19 @@ { TARGET_NR_umask, "umask" , "%s(%#o)", NULL, NULL }, #endif #ifdef TARGET_NR_umount -{ TARGET_NR_umount, "umount" , "%s(\"%s\",\"%s\",\"%s\",%#x,%p)", NULL, NULL }, +{ TARGET_NR_umount, "umount" , NULL, print_umount, NULL }, #endif #ifdef TARGET_NR_umount2 -{ TARGET_NR_umount2, "umount2" , NULL, NULL, NULL }, +{ TARGET_NR_umount2, "umount2" , NULL, print_umount2, NULL }, #endif #ifdef TARGET_NR_uname { TARGET_NR_uname, "uname" , "%s(%p)", NULL, NULL }, #endif #ifdef TARGET_NR_unlink -{ TARGET_NR_unlink, "unlink" , "%s(\"%s\")", NULL, NULL }, +{ TARGET_NR_unlink, "unlink" , NULL, print_unlink, NULL }, #endif #ifdef TARGET_NR_unlinkat -{ TARGET_NR_unlinkat, "unlinkat" , "%s(%d,\"%s\",%#x)", NULL, NULL }, +{ TARGET_NR_unlinkat, "unlinkat" , NULL, print_unlinkat, NULL }, #endif #ifdef TARGET_NR_unshare { TARGET_NR_unshare, "unshare" , NULL, NULL, NULL }, @@ -1469,10 +1474,10 @@ { TARGET_NR_ustat, "ustat" , "%s(%#x,%p)", NULL, NULL }, #endif #ifdef TARGET_NR_utime -{ TARGET_NR_utime, "utime" , "%s(\"%s\",%p)", NULL, NULL }, +{ TARGET_NR_utime, "utime" , NULL, print_utime, NULL }, #endif #ifdef TARGET_NR_utimes -{ TARGET_NR_utimes, "utimes" , NULL, NULL, NULL }, +{ TARGET_NR_utimes, "utimes" , NULL, print_utimes, NULL }, #endif #ifdef TARGET_NR_utrap_install { TARGET_NR_utrap_install, "utrap_install" , NULL, NULL, NULL }, @@ -1511,5 +1516,5 @@ { TARGET_NR_writev, "writev" , "%s(%d,%p,%#x)", NULL, NULL }, #endif #ifdef TARGET_NR_utimensat -{ TARGET_NR_utimensat, "utimensat", "%s(%d,\"%s\",%p,%#x)", NULL, NULL }, +{ TARGET_NR_utimensat, "utimensat", NULL, print_utimensat, NULL }, #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 59c91f8da..53a11ab87 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, * MA 02110-1301, USA. */ +#define _ATFILE_SOURCE #include <stdlib.h> #include <stdio.h> #include <stdarg.h> @@ -77,6 +78,7 @@ #include <linux/soundcard.h> #include <linux/kd.h> #include <linux/mtio.h> +#include <linux/fs.h> #include "linux_loop.h" #include "qemu.h" @@ -93,12 +95,6 @@ //#define DEBUG -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \ - || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS) -/* 16 bit uid wrappers emulation */ -#define USE_UID16 -#endif - //#include <linux/msdos_fs.h> #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2]) #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2]) @@ -412,13 +408,6 @@ static int sys_unlinkat(int dirfd, const char *pathname, int flags) return (unlinkat(dirfd, pathname, flags)); } #endif -#ifdef TARGET_NR_utimensat -static int sys_utimensat(int dirfd, const char *pathname, - const struct timespec times[2], int flags) -{ - return (utimensat(dirfd, pathname, times, flags)); -} -#endif #else /* !CONFIG_ATFILE */ /* @@ -477,12 +466,24 @@ _syscall3(int,sys_symlinkat,const char *,oldpath, #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat) _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags) #endif + +#endif /* CONFIG_ATFILE */ + +#ifdef CONFIG_UTIMENSAT +static int sys_utimensat(int dirfd, const char *pathname, + const struct timespec times[2], int flags) +{ + if (pathname == NULL) + return futimens(dirfd, times); + else + return utimensat(dirfd, pathname, times, flags); +} +#else #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat) _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname, const struct timespec *,tsp,int,flags) #endif - -#endif /* CONFIG_ATFILE */ +#endif /* CONFIG_UTIMENSAT */ #ifdef CONFIG_INOTIFY #include <sys/inotify.h> @@ -944,6 +945,55 @@ static abi_long do_select(int n, return ret; } +static abi_long do_pipe2(int host_pipe[], int flags) +{ +#ifdef CONFIG_PIPE2 + return pipe2(host_pipe, flags); +#else + return -ENOSYS; +#endif +} + +static abi_long do_pipe(void *cpu_env, int pipedes, int flags) +{ + int host_pipe[2]; + abi_long ret; + ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe); + + if (is_error(ret)) + return get_errno(ret); +#if defined(TARGET_MIPS) + ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1]; + ret = host_pipe[0]; +#elif defined(TARGET_SH4) + ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1]; + ret = host_pipe[0]; +#else + if (put_user_s32(host_pipe[0], pipedes) + || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0]))) + return -TARGET_EFAULT; +#endif + return get_errno(ret); +} + +static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, + abi_ulong target_addr, + socklen_t len) +{ + struct target_ip_mreqn *target_smreqn; + + target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1); + if (!target_smreqn) + return -TARGET_EFAULT; + mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr; + mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr; + if (len == sizeof(struct target_ip_mreqn)) + mreqn->imr_ifindex = tswapl(target_smreqn->imr_ifindex); + unlock_user(target_smreqn, target_addr, 0); + + return 0; +} + static inline abi_long target_to_host_sockaddr(struct sockaddr *addr, abi_ulong target_addr, socklen_t len) @@ -1119,6 +1169,8 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, { abi_long ret; int val; + struct ip_mreqn *ip_mreq; + struct ip_mreq_source *ip_mreq_source; switch(level) { case SOL_TCP: @@ -1157,6 +1209,29 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, } ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); break; + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + if (optlen < sizeof (struct target_ip_mreq) || + optlen > sizeof (struct target_ip_mreqn)) + return -TARGET_EINVAL; + + ip_mreq = (struct ip_mreqn *) alloca(optlen); + target_to_host_ip_mreq(ip_mreq, optval_addr, optlen); + ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen)); + break; + + case IP_BLOCK_SOURCE: + case IP_UNBLOCK_SOURCE: + case IP_ADD_SOURCE_MEMBERSHIP: + case IP_DROP_SOURCE_MEMBERSHIP: + if (optlen != sizeof (struct target_ip_mreq_source)) + return -TARGET_EINVAL; + + ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1); + ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen)); + unlock_user (ip_mreq_source, optval_addr, 0); + break; + default: goto unimplemented; } @@ -1273,7 +1348,6 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); if (ret < 0) return ret; - val = tswap32(val); if (len > lv) len = lv; if (len == 4) { @@ -1924,14 +1998,12 @@ static abi_long do_socketcall(int num, abi_ulong vptr) } #endif -#ifdef TARGET_NR_ipc #define N_SHM_REGIONS 32 static struct shm_region { abi_ulong start; abi_ulong size; } shm_regions[N_SHM_REGIONS]; -#endif struct target_ipc_perm { @@ -2424,6 +2496,224 @@ end: return ret; } +struct target_shmid_ds +{ + struct target_ipc_perm shm_perm; + abi_ulong shm_segsz; + abi_ulong shm_atime; +#if TARGET_ABI_BITS == 32 + abi_ulong __unused1; +#endif + abi_ulong shm_dtime; +#if TARGET_ABI_BITS == 32 + abi_ulong __unused2; +#endif + abi_ulong shm_ctime; +#if TARGET_ABI_BITS == 32 + abi_ulong __unused3; +#endif + int shm_cpid; + int shm_lpid; + abi_ulong shm_nattch; + unsigned long int __unused4; + unsigned long int __unused5; +}; + +static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd, + abi_ulong target_addr) +{ + struct target_shmid_ds *target_sd; + + if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) + return -TARGET_EFAULT; + if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr)) + return -TARGET_EFAULT; + __get_user(host_sd->shm_segsz, &target_sd->shm_segsz); + __get_user(host_sd->shm_atime, &target_sd->shm_atime); + __get_user(host_sd->shm_dtime, &target_sd->shm_dtime); + __get_user(host_sd->shm_ctime, &target_sd->shm_ctime); + __get_user(host_sd->shm_cpid, &target_sd->shm_cpid); + __get_user(host_sd->shm_lpid, &target_sd->shm_lpid); + __get_user(host_sd->shm_nattch, &target_sd->shm_nattch); + unlock_user_struct(target_sd, target_addr, 0); + return 0; +} + +static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr, + struct shmid_ds *host_sd) +{ + struct target_shmid_ds *target_sd; + + if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) + return -TARGET_EFAULT; + if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm))) + return -TARGET_EFAULT; + __put_user(host_sd->shm_segsz, &target_sd->shm_segsz); + __put_user(host_sd->shm_atime, &target_sd->shm_atime); + __put_user(host_sd->shm_dtime, &target_sd->shm_dtime); + __put_user(host_sd->shm_ctime, &target_sd->shm_ctime); + __put_user(host_sd->shm_cpid, &target_sd->shm_cpid); + __put_user(host_sd->shm_lpid, &target_sd->shm_lpid); + __put_user(host_sd->shm_nattch, &target_sd->shm_nattch); + unlock_user_struct(target_sd, target_addr, 1); + return 0; +} + +struct target_shminfo { + abi_ulong shmmax; + abi_ulong shmmin; + abi_ulong shmmni; + abi_ulong shmseg; + abi_ulong shmall; +}; + +static inline abi_long host_to_target_shminfo(abi_ulong target_addr, + struct shminfo *host_shminfo) +{ + struct target_shminfo *target_shminfo; + if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0)) + return -TARGET_EFAULT; + __put_user(host_shminfo->shmmax, &target_shminfo->shmmax); + __put_user(host_shminfo->shmmin, &target_shminfo->shmmin); + __put_user(host_shminfo->shmmni, &target_shminfo->shmmni); + __put_user(host_shminfo->shmseg, &target_shminfo->shmseg); + __put_user(host_shminfo->shmall, &target_shminfo->shmall); + unlock_user_struct(target_shminfo, target_addr, 1); + return 0; +} + +struct target_shm_info { + int used_ids; + abi_ulong shm_tot; + abi_ulong shm_rss; + abi_ulong shm_swp; + abi_ulong swap_attempts; + abi_ulong swap_successes; +}; + +static inline abi_long host_to_target_shm_info(abi_ulong target_addr, + struct shm_info *host_shm_info) +{ + struct target_shm_info *target_shm_info; + if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0)) + return -TARGET_EFAULT; + __put_user(host_shm_info->used_ids, &target_shm_info->used_ids); + __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot); + __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss); + __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp); + __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts); + __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes); + unlock_user_struct(target_shm_info, target_addr, 1); + return 0; +} + +static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf) +{ + struct shmid_ds dsarg; + struct shminfo shminfo; + struct shm_info shm_info; + abi_long ret = -TARGET_EINVAL; + + cmd &= 0xff; + + switch(cmd) { + case IPC_STAT: + case IPC_SET: + case SHM_STAT: + if (target_to_host_shmid_ds(&dsarg, buf)) + return -TARGET_EFAULT; + ret = get_errno(shmctl(shmid, cmd, &dsarg)); + if (host_to_target_shmid_ds(buf, &dsarg)) + return -TARGET_EFAULT; + break; + case IPC_INFO: + ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo)); + if (host_to_target_shminfo(buf, &shminfo)) + return -TARGET_EFAULT; + break; + case SHM_INFO: + ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info)); + if (host_to_target_shm_info(buf, &shm_info)) + return -TARGET_EFAULT; + break; + case IPC_RMID: + case SHM_LOCK: + case SHM_UNLOCK: + ret = get_errno(shmctl(shmid, cmd, NULL)); + break; + } + + return ret; +} + +static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg) +{ + abi_long raddr; + void *host_raddr; + struct shmid_ds shm_info; + int i,ret; + + /* find out the length of the shared memory segment */ + ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info)); + if (is_error(ret)) { + /* can't get length, bail out */ + return ret; + } + + mmap_lock(); + + if (shmaddr) + host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg); + else { + abi_ulong mmap_start; + + mmap_start = mmap_find_vma(0, shm_info.shm_segsz); + + if (mmap_start == -1) { + errno = ENOMEM; + host_raddr = (void *)-1; + } else + host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP); + } + + if (host_raddr == (void *)-1) { + mmap_unlock(); + return get_errno((long)host_raddr); + } + raddr=h2g((unsigned long)host_raddr); + + page_set_flags(raddr, raddr + shm_info.shm_segsz, + PAGE_VALID | PAGE_READ | + ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE)); + + for (i = 0; i < N_SHM_REGIONS; i++) { + if (shm_regions[i].start == 0) { + shm_regions[i].start = raddr; + shm_regions[i].size = shm_info.shm_segsz; + break; + } + } + + mmap_unlock(); + return raddr; + +} + +static inline abi_long do_shmdt(abi_ulong shmaddr) +{ + int i; + + for (i = 0; i < N_SHM_REGIONS; ++i) { + if (shm_regions[i].start == shmaddr) { + shm_regions[i].start = 0; + page_set_flags(shmaddr, shm_regions[i].size, 0); + break; + } + } + + return get_errno(shmdt(g2h(shmaddr))); +} + #ifdef TARGET_NR_ipc /* ??? This only works with linear mappings. */ /* do_ipc() must return target values and target errnos. */ @@ -2433,8 +2723,6 @@ static abi_long do_ipc(unsigned int call, int first, { int version; abi_long ret = 0; - struct shmid_ds shm_info; - int i; version = call >> 16; call &= 0xffff; @@ -2489,48 +2777,24 @@ static abi_long do_ipc(unsigned int call, int first, break; case IPCOP_shmat: + switch (version) { + default: { abi_ulong raddr; - void *host_addr; - /* SHM_* flags are the same on all linux platforms */ - host_addr = shmat(first, (void *)g2h(ptr), second); - if (host_addr == (void *)-1) { - ret = get_errno((long)host_addr); - break; - } - raddr = h2g((unsigned long)host_addr); - /* find out the length of the shared memory segment */ - - ret = get_errno(shmctl(first, IPC_STAT, &shm_info)); - if (is_error(ret)) { - /* can't get length, bail out */ - shmdt(host_addr); - break; - } - page_set_flags(raddr, raddr + shm_info.shm_segsz, - PAGE_VALID | PAGE_READ | - ((second & SHM_RDONLY)? 0: PAGE_WRITE)); - for (i = 0; i < N_SHM_REGIONS; ++i) { - if (shm_regions[i].start == 0) { - shm_regions[i].start = raddr; - shm_regions[i].size = shm_info.shm_segsz; - break; - } - } + raddr = do_shmat(first, ptr, second); + if (is_error(raddr)) + return get_errno(raddr); if (put_user_ual(raddr, third)) return -TARGET_EFAULT; - ret = 0; + break; + } + case 1: + ret = -TARGET_EINVAL; + break; } break; case IPCOP_shmdt: - for (i = 0; i < N_SHM_REGIONS; ++i) { - if (shm_regions[i].start == ptr) { - shm_regions[i].start = 0; - page_set_flags(ptr, shm_regions[i].size, 0); - break; - } - } - ret = get_errno(shmdt((void *)g2h(ptr))); + ret = do_shmdt(ptr); break; case IPCOP_shmget: @@ -2540,18 +2804,9 @@ static abi_long do_ipc(unsigned int call, int first, /* IPC_* and SHM_* command values are the same on all linux platforms */ case IPCOP_shmctl: - switch(second) { - case IPC_RMID: - case SHM_LOCK: - case SHM_UNLOCK: - ret = get_errno(shmctl(first, second, NULL)); - break; - default: - goto unimplemented; - } + ret = do_shmctl(first, second, third); break; default: - unimplemented: gemu_log("Unsupported ipc call: %d (version %d)\n", call, version); ret = -TARGET_ENOSYS; break; @@ -2797,6 +3052,7 @@ static void target_to_host_termios (void *dst, const void *src) target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl); host->c_line = target->c_line; + memset(host->c_cc, 0, sizeof(host->c_cc)); host->c_cc[VINTR] = target->c_cc[TARGET_VINTR]; host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT]; host->c_cc[VERASE] = target->c_cc[TARGET_VERASE]; @@ -2831,6 +3087,7 @@ static void host_to_target_termios (void *dst, const void *src) tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl)); target->c_line = host->c_line; + memset(target->c_cc, 0, sizeof(target->c_cc)); target->c_cc[TARGET_VINTR] = host->c_cc[VINTR]; target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT]; target->c_cc[TARGET_VERASE] = host->c_cc[VERASE]; @@ -3198,11 +3455,14 @@ static void *clone_func(void *arg) { new_thread_info *info = arg; CPUState *env; + TaskState *ts; env = info->env; thread_env = env; + ts = (TaskState *)thread_env->opaque; info->tid = gettid(); env->host_tid = info->tid; + task_settid(ts); if (info->child_tidptr) put_user_u32(info->tid, info->child_tidptr); if (info->parent_tidptr) @@ -3254,6 +3514,7 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp, flags &= ~(CLONE_VFORK | CLONE_VM); if (flags & CLONE_VM) { + TaskState *parent_ts = (TaskState *)env->opaque; #if defined(USE_NPTL) new_thread_info info; pthread_attr_t attr; @@ -3266,6 +3527,8 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp, /* Init regs that differ from the parent. */ cpu_clone_regs(new_env, newsp); new_env->opaque = ts; + ts->bprm = parent_ts->bprm; + ts->info = parent_ts->info; #if defined(USE_NPTL) nptl_flags = flags; flags &= ~CLONE_NPTL_FLAGS2; @@ -3359,6 +3622,44 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp, return ret; } +/* warning : doesn't handle linux specific flags... */ +static int target_to_host_fcntl_cmd(int cmd) +{ + switch(cmd) { + case TARGET_F_DUPFD: + case TARGET_F_GETFD: + case TARGET_F_SETFD: + case TARGET_F_GETFL: + case TARGET_F_SETFL: + return cmd; + case TARGET_F_GETLK: + return F_GETLK; + case TARGET_F_SETLK: + return F_SETLK; + case TARGET_F_SETLKW: + return F_SETLKW; + case TARGET_F_GETOWN: + return F_GETOWN; + case TARGET_F_SETOWN: + return F_SETOWN; + case TARGET_F_GETSIG: + return F_GETSIG; + case TARGET_F_SETSIG: + return F_SETSIG; +#if TARGET_ABI_BITS == 32 + case TARGET_F_GETLK64: + return F_GETLK64; + case TARGET_F_SETLK64: + return F_SETLK64; + case TARGET_F_SETLKW64: + return F_SETLKW64; +#endif + default: + return -TARGET_EINVAL; + } + return -TARGET_EINVAL; +} + static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) { struct flock fl; @@ -3366,6 +3667,10 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) struct flock64 fl64; struct target_flock64 *target_fl64; abi_long ret; + int host_cmd = target_to_host_fcntl_cmd(cmd); + + if (host_cmd == -TARGET_EINVAL) + return host_cmd; switch(cmd) { case TARGET_F_GETLK: @@ -3377,7 +3682,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) fl.l_len = tswapl(target_fl->l_len); fl.l_pid = tswapl(target_fl->l_pid); unlock_user_struct(target_fl, arg, 0); - ret = get_errno(fcntl(fd, cmd, &fl)); + ret = get_errno(fcntl(fd, host_cmd, &fl)); if (ret == 0) { if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0)) return -TARGET_EFAULT; @@ -3400,7 +3705,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) fl.l_len = tswapl(target_fl->l_len); fl.l_pid = tswapl(target_fl->l_pid); unlock_user_struct(target_fl, arg, 0); - ret = get_errno(fcntl(fd, cmd, &fl)); + ret = get_errno(fcntl(fd, host_cmd, &fl)); break; case TARGET_F_GETLK64: @@ -3412,7 +3717,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) fl64.l_len = tswapl(target_fl64->l_len); fl64.l_pid = tswap16(target_fl64->l_pid); unlock_user_struct(target_fl64, arg, 0); - ret = get_errno(fcntl(fd, cmd >> 1, &fl64)); + ret = get_errno(fcntl(fd, host_cmd, &fl64)); if (ret == 0) { if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0)) return -TARGET_EFAULT; @@ -3434,18 +3739,25 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) fl64.l_len = tswapl(target_fl64->l_len); fl64.l_pid = tswap16(target_fl64->l_pid); unlock_user_struct(target_fl64, arg, 0); - ret = get_errno(fcntl(fd, cmd >> 1, &fl64)); + ret = get_errno(fcntl(fd, host_cmd, &fl64)); break; - case F_GETFL: - ret = get_errno(fcntl(fd, cmd, arg)); + case TARGET_F_GETFL: + ret = get_errno(fcntl(fd, host_cmd, arg)); if (ret >= 0) { ret = host_to_target_bitmask(ret, fcntl_flags_tbl); } break; - case F_SETFL: - ret = get_errno(fcntl(fd, cmd, target_to_host_bitmask(arg, fcntl_flags_tbl))); + case TARGET_F_SETFL: + ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl))); + break; + + case TARGET_F_SETOWN: + case TARGET_F_GETOWN: + case TARGET_F_SETSIG: + case TARGET_F_GETSIG: + ret = get_errno(fcntl(fd, host_cmd, arg)); break; default: @@ -3694,7 +4006,11 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout, /* ??? We assume FUTEX_* constants are the same on both host and target. */ +#ifdef FUTEX_CMD_MASK + switch ((op&FUTEX_CMD_MASK)) { +#else switch (op) { +#endif case FUTEX_WAIT: if (timeout) { pts = &ts; @@ -3702,17 +4018,19 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout, } else { pts = NULL; } - return get_errno(sys_futex(g2h(uaddr), FUTEX_WAIT, tswap32(val), + return get_errno(sys_futex(g2h(uaddr), op, tswap32(val), pts, NULL, 0)); case FUTEX_WAKE: - return get_errno(sys_futex(g2h(uaddr), FUTEX_WAKE, val, NULL, NULL, 0)); + return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0)); + case FUTEX_WAKE_OP: + return get_errno(sys_futex(g2h(uaddr), op, val, NULL, g2h(uaddr2), val3 )); case FUTEX_FD: - return get_errno(sys_futex(g2h(uaddr), FUTEX_FD, val, NULL, NULL, 0)); + return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0)); case FUTEX_REQUEUE: - return get_errno(sys_futex(g2h(uaddr), FUTEX_REQUEUE, val, + return get_errno(sys_futex(g2h(uaddr), op, val, NULL, g2h(uaddr2), 0)); case FUTEX_CMP_REQUEUE: - return get_errno(sys_futex(g2h(uaddr), FUTEX_CMP_REQUEUE, val, + return get_errno(sys_futex(g2h(uaddr), op, val, NULL, g2h(uaddr2), tswap32(val3))); default: return -TARGET_ENOSYS; @@ -4291,25 +4609,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(dup(arg1)); break; case TARGET_NR_pipe: - { - int host_pipe[2]; - ret = get_errno(pipe(host_pipe)); - if (!is_error(ret)) { -#if defined(TARGET_MIPS) - CPUMIPSState *env = (CPUMIPSState*)cpu_env; - env->active_tc.gpr[3] = host_pipe[1]; - ret = host_pipe[0]; -#elif defined(TARGET_SH4) - ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1]; - ret = host_pipe[0]; -#else - if (put_user_s32(host_pipe[0], arg1) - || put_user_s32(host_pipe[1], arg1 + sizeof(host_pipe[0]))) - goto efault; -#endif - } - } + ret = do_pipe(cpu_env, arg1, 0); break; +#ifdef TARGET_NR_pipe2 + case TARGET_NR_pipe2: + ret = do_pipe(cpu_env, arg1, arg2); + break; +#endif case TARGET_NR_times: { struct target_tms *tmsp; @@ -5312,6 +5618,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = do_msgsnd(arg1, arg2, arg3, arg4); break; #endif +#ifdef TARGET_NR_shmget + case TARGET_NR_shmget: + ret = get_errno(shmget(arg1, arg2, arg3)); + break; +#endif +#ifdef TARGET_NR_shmctl + case TARGET_NR_shmctl: + ret = do_shmctl(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_shmat + case TARGET_NR_shmat: + ret = do_shmat(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_shmdt + case TARGET_NR_shmdt: + ret = do_shmdt(arg1); + break; +#endif case TARGET_NR_fsync: ret = get_errno(fsync(arg1)); break; @@ -6224,20 +6550,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct target_eabi_flock64 *target_efl; #endif - switch(arg2){ - case TARGET_F_GETLK64: - cmd = F_GETLK64; - break; - case TARGET_F_SETLK64: - cmd = F_SETLK64; - break; - case TARGET_F_SETLKW64: - cmd = F_SETLK64; - break; - default: - cmd = arg2; - break; - } + cmd = target_to_host_fcntl_cmd(arg2); + if (cmd == -TARGET_EINVAL) + return cmd; switch(arg2) { case TARGET_F_GETLK64: @@ -6317,7 +6632,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(fcntl(arg1, cmd, &fl)); break; default: - ret = do_fcntl(arg1, cmd, arg3); + ret = do_fcntl(arg1, arg2, arg3); break; } break; @@ -6371,7 +6686,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_removexattr: case TARGET_NR_lremovexattr: case TARGET_NR_fremovexattr: - goto unimplemented_nowarn; + ret = -TARGET_EOPNOTSUPP; + break; #endif #ifdef TARGET_NR_set_thread_area case TARGET_NR_set_thread_area: @@ -6468,17 +6784,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat) case TARGET_NR_utimensat: { - struct timespec ts[2]; - target_to_host_timespec(ts, arg3); - target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec)); + struct timespec *tsp, ts[2]; + if (!arg3) { + tsp = NULL; + } else { + target_to_host_timespec(ts, arg3); + target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec)); + tsp = ts; + } if (!arg2) - ret = get_errno(sys_utimensat(arg1, NULL, ts, arg4)); + ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4)); else { if (!(p = lock_user_string(arg2))) { ret = -TARGET_EFAULT; goto fail; } - ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4)); + ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4)); unlock_user(p, arg2, 0); } } @@ -6582,6 +6903,46 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif +#ifdef CONFIG_SPLICE +#ifdef TARGET_NR_tee + case TARGET_NR_tee: + { + ret = get_errno(tee(arg1,arg2,arg3,arg4)); + } + break; +#endif +#ifdef TARGET_NR_splice + case TARGET_NR_splice: + { + loff_t loff_in, loff_out; + loff_t *ploff_in = NULL, *ploff_out = NULL; + if(arg2) { + get_user_u64(loff_in, arg2); + ploff_in = &loff_in; + } + if(arg4) { + get_user_u64(loff_out, arg2); + ploff_out = &loff_out; + } + ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6)); + } + break; +#endif +#ifdef TARGET_NR_vmsplice + case TARGET_NR_vmsplice: + { + int count = arg3; + struct iovec *vec; + + vec = alloca(count * sizeof(struct iovec)); + if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) + goto efault; + ret = get_errno(vmsplice(arg1, vec, count, arg4)); + unlock_iovec(vec, arg2, count, 0); + } + break; +#endif +#endif /* CONFIG_SPLICE */ default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index e2ba0bbc1..24217e40c 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -48,6 +48,12 @@ #define TARGET_IOC_NRBITS 8 #define TARGET_IOC_TYPEBITS 8 +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \ + || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS) + /* 16 bit uid wrappers emulation */ +#define USE_UID16 +#endif + #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \ || defined(TARGET_M68K) || defined(TARGET_CRIS) @@ -105,6 +111,28 @@ struct target_sockaddr { uint8_t sa_data[14]; }; +struct target_in_addr { + uint32_t s_addr; /* big endian */ +}; + +struct target_ip_mreq { + struct target_in_addr imr_multiaddr; + struct target_in_addr imr_address; +}; + +struct target_ip_mreqn { + struct target_in_addr imr_multiaddr; + struct target_in_addr imr_address; + abi_long imr_ifindex; +}; + +struct target_ip_mreq_source { + /* big endian */ + uint32_t imr_multiaddr; + uint32_t imr_interface; + uint32_t imr_sourceaddr; +}; + struct target_timeval { abi_long tv_sec; abi_long tv_usec; @@ -1717,6 +1745,12 @@ struct target_statfs64 { #define TARGET_F_SETLKW 9 #define TARGET_F_SETOWN 5 /* for sockets. */ #define TARGET_F_GETOWN 6 /* for sockets. */ +#elif defined(TARGET_MIPS) +#define TARGET_F_GETLK 14 +#define TARGET_F_SETLK 6 +#define TARGET_F_SETLKW 7 +#define TARGET_F_SETOWN 24 /* for sockets. */ +#define TARGET_F_GETOWN 25 /* for sockets. */ #else #define TARGET_F_GETLK 5 #define TARGET_F_SETLK 6 @@ -1728,10 +1762,15 @@ struct target_statfs64 { #define TARGET_F_SETSIG 10 /* for sockets. */ #define TARGET_F_GETSIG 11 /* for sockets. */ +#if defined(TARGET_MIPS) +#define TARGET_F_GETLK64 33 /* using 'struct flock64' */ +#define TARGET_F_SETLK64 34 +#define TARGET_F_SETLKW64 35 +#else #define TARGET_F_GETLK64 12 /* using 'struct flock64' */ #define TARGET_F_SETLK64 13 #define TARGET_F_SETLKW64 14 - +#endif #if defined (TARGET_ARM) #define TARGET_O_ACCMODE 0003 #define TARGET_O_RDONLY 00 diff --git a/linux-user/x86_64/syscall_nr.h b/linux-user/x86_64/syscall_nr.h index e6a4c27ea..568a901d7 100644 --- a/linux-user/x86_64/syscall_nr.h +++ b/linux-user/x86_64/syscall_nr.h @@ -284,3 +284,12 @@ #define TARGET_NR_timerfd 283 #define TARGET_NR_eventfd 284 #define TARGET_NR_fallocate 285 +#define TARGET_NR_timerfd_settime 286 +#define TARGET_NR_timerfd_gettime 287 +#define TARGET_NR_accept4 288 +#define TARGET_NR_signalfd4 289 +#define TARGET_NR_eventfd2 290 +#define TARGET_NR_epoll_create1 291 +#define TARGET_NR_dup3 292 +#define TARGET_NR_pipe2 293 +#define TARGET_NR_inotify_init1 294 diff --git a/migration.c b/migration.c index 57f2a5293..190b37e55 100644 --- a/migration.c +++ b/migration.c @@ -107,6 +107,36 @@ void do_migrate_set_speed(Monitor *mon, const char *value) } +/* amount of nanoseconds we are willing to wait for migration to be down. + * the choice of nanoseconds is because it is the maximum resolution that + * get_clock() can achieve. It is an internal measure. All user-visible + * units must be in seconds */ +static uint64_t max_downtime = 30000000; + +uint64_t migrate_max_downtime(void) +{ + return max_downtime; +} + +void do_migrate_set_downtime(Monitor *mon, const char *value) +{ + char *ptr; + double d; + + d = strtod(value, &ptr); + if (!strcmp(ptr,"ms")) { + d *= 1000000; + } else if (!strcmp(ptr,"us")) { + d *= 1000; + } else if (!strcmp(ptr,"ns")) { + } else { + /* all else considered to be seconds */ + d *= 1000000000; + } + + max_downtime = (uint64_t)d; +} + void do_info_migrate(Monitor *mon) { MigrationState *s = current_migration; diff --git a/migration.h b/migration.h index 696618da0..37c7f8e15 100644 --- a/migration.h +++ b/migration.h @@ -55,6 +55,10 @@ void do_migrate_cancel(Monitor *mon); void do_migrate_set_speed(Monitor *mon, const char *value); +uint64_t migrate_max_downtime(void); + +void do_migrate_set_downtime(Monitor *mon, const char *value); + void do_info_migrate(Monitor *mon); int exec_start_incoming_migration(const char *host_port); diff --git a/qemu-char.c b/qemu-char.c index a8afe94fa..287e0cd32 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -219,8 +219,6 @@ static CharDriverState *qemu_chr_open_null(void) } /* MUX driver for serial I/O splitting */ -static int term_timestamps; -static int64_t term_timestamps_start; #define MAX_MUX 4 #define MUX_BUFFER_SIZE 32 /* Must be a power of 2. */ #define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1) @@ -239,6 +237,9 @@ typedef struct { unsigned char buffer[MAX_MUX][MUX_BUFFER_SIZE]; int prod[MAX_MUX]; int cons[MAX_MUX]; + int timestamps; + int linestart; + int64_t timestamps_start; } MuxDriver; @@ -246,23 +247,22 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { MuxDriver *d = chr->opaque; int ret; - if (!term_timestamps) { + if (!d->timestamps) { ret = d->drv->chr_write(d->drv, buf, len); } else { int i; ret = 0; - for(i = 0; i < len; i++) { - ret += d->drv->chr_write(d->drv, buf+i, 1); - if (buf[i] == '\n') { + for (i = 0; i < len; i++) { + if (d->linestart) { char buf1[64]; int64_t ti; int secs; ti = qemu_get_clock(rt_clock); - if (term_timestamps_start == -1) - term_timestamps_start = ti; - ti -= term_timestamps_start; + if (d->timestamps_start == -1) + d->timestamps_start = ti; + ti -= d->timestamps_start; secs = ti / 1000; snprintf(buf1, sizeof(buf1), "[%02d:%02d:%02d.%03d] ", @@ -271,6 +271,11 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len) secs % 60, (int)(ti % 1000)); d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1)); + d->linestart = 0; + } + ret += d->drv->chr_write(d->drv, buf+i, 1); + if (buf[i] == '\n') { + d->linestart = 1; } } } @@ -357,10 +362,11 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) chr->focus = 0; mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_IN); break; - case 't': - term_timestamps = !term_timestamps; - term_timestamps_start = -1; - break; + case 't': + d->timestamps = !d->timestamps; + d->timestamps_start = -1; + d->linestart = 0; + break; } } else if (ch == term_escape_char) { d->term_got_escape = 1; diff --git a/qemu-monitor.hx b/qemu-monitor.hx index 1e7210ecc..dea0704f8 100644 --- a/qemu-monitor.hx +++ b/qemu-monitor.hx @@ -484,6 +484,14 @@ STEXI Set maximum speed to @var{value} (in bytes) for migrations. ETEXI + { "migrate_set_downtime", "s", do_migrate_set_downtime, + "value", "set maximum tolerated downtime (in seconds) for migrations" }, + +STEXI +@item migrate_set_downtime @var{second} +Set maximum tolerated downtime (in seconds) for migration. +ETEXI + #if defined(TARGET_I386) { "drive_add", "ss", drive_hot_add, "pci_addr=[[<domain>:]<bus>:]<slot>\n" "[file=file][,if=type][,bus=n]\n" diff --git a/readline.c b/readline.c index 9c500f1fe..7834af0f6 100644 --- a/readline.c +++ b/readline.c @@ -467,9 +467,6 @@ ReadLineState *readline_init(Monitor *mon, { ReadLineState *rs = qemu_mallocz(sizeof(*rs)); - if (!rs) - return NULL; - rs->hist_entry = -1; rs->mon = mon; rs->completion_finder = completion_finder; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index d7b32d431..3cd391a01 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -655,6 +655,7 @@ typedef struct CPUX86State { uint32_t cpuid_ext2_features; uint32_t cpuid_ext3_features; uint32_t cpuid_apic_id; + int cpuid_vendor_override; /* MTRRs */ uint64_t mtrr_fixed[11]; diff --git a/target-i386/helper.c b/target-i386/helper.c index 6dc011111..2c5af3c00 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -104,6 +104,7 @@ typedef struct x86_def_t { uint32_t features, ext_features, ext2_features, ext3_features; uint32_t xlevel; char model_id[48]; + int vendor_override; } x86_def_t; #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE) @@ -364,6 +365,7 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) x86_cpu_def->vendor2 |= ((uint8_t)val[i + 4]) << (8 * i); x86_cpu_def->vendor3 |= ((uint8_t)val[i + 8]) << (8 * i); } + x86_cpu_def->vendor_override = 1; } else if (!strcmp(featurestr, "model_id")) { pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id), val); @@ -416,6 +418,7 @@ static int cpu_x86_register (CPUX86State *env, const char *cpu_model) env->cpuid_vendor2 = CPUID_VENDOR_INTEL_2; env->cpuid_vendor3 = CPUID_VENDOR_INTEL_3; } + env->cpuid_vendor_override = def->vendor_override; env->cpuid_level = def->level; if (def->family > 0x0f) env->cpuid_version = 0xf00 | ((def->family - 0x0f) << 20); @@ -481,17 +484,23 @@ void cpu_reset(CPUX86State *env) env->tr.flags = DESC_P_MASK | (11 << DESC_TYPE_SHIFT); cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff, - DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK | DESC_R_MASK); + DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK | + DESC_R_MASK | DESC_A_MASK); cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff, - DESC_P_MASK | DESC_S_MASK | DESC_W_MASK); + DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | + DESC_A_MASK); cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff, - DESC_P_MASK | DESC_S_MASK | DESC_W_MASK); + DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | + DESC_A_MASK); cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff, - DESC_P_MASK | DESC_S_MASK | DESC_W_MASK); + DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | + DESC_A_MASK); cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff, - DESC_P_MASK | DESC_S_MASK | DESC_W_MASK); + DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | + DESC_A_MASK); cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff, - DESC_P_MASK | DESC_S_MASK | DESC_W_MASK); + DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | + DESC_A_MASK); env->eip = 0xfff0; env->regs[R_EDX] = env->cpuid_version; @@ -1494,7 +1503,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, * isn't supported in compatibility mode on Intel. so advertise the * actuall cpu, and say goodbye to migration between different vendors * is you use compatibility mode. */ - if (kvm_enabled()) + if (kvm_enabled() && !env->cpuid_vendor_override) host_cpuid(0, 0, NULL, ebx, ecx, edx); break; case 1: @@ -3243,7 +3243,6 @@ static int ram_save_block(QEMUFile *f) return found; } -static ram_addr_t ram_save_threshold = 10; static uint64_t bytes_transferred = 0; static ram_addr_t ram_save_remaining(void) @@ -3277,6 +3276,9 @@ uint64_t ram_bytes_total(void) static int ram_save_live(QEMUFile *f, int stage, void *opaque) { ram_addr_t addr; + uint64_t bytes_transferred_last; + double bwidth = 0; + uint64_t expected_time = 0; if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) { qemu_file_set_error(f); @@ -3296,6 +3298,9 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque) qemu_put_be64(f, last_ram_offset | RAM_SAVE_FLAG_MEM_SIZE); } + bytes_transferred_last = bytes_transferred; + bwidth = get_clock(); + while (!qemu_file_rate_limit(f)) { int ret; @@ -3305,6 +3310,14 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque) break; } + bwidth = get_clock() - bwidth; + bwidth = (bytes_transferred - bytes_transferred_last) / bwidth; + + /* if we haven't transferred anything this round, force expected_time to a + * a very high value, but without crashing */ + if (bwidth == 0) + bwidth = 0.000001; + /* try transferring iterative blocks of memory */ if (stage == 3) { @@ -3318,7 +3331,9 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque) qemu_put_be64(f, RAM_SAVE_FLAG_EOS); - return (stage == 2) && (ram_save_remaining() < ram_save_threshold); + expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; + + return (stage == 2) && (expected_time <= migrate_max_downtime()); } static int ram_load_dead(QEMUFile *f, void *opaque) @@ -6304,8 +6319,6 @@ int main(int argc, char **argv, char **envp) for(i = 0; i < MAX_SERIAL_PORTS; i++) { const char *devname = serial_devices[i]; if (devname && strcmp(devname, "none")) { - char label[32]; - snprintf(label, sizeof(label), "serial%d", i); if (strstart(devname, "vc", 0)) qemu_chr_printf(serial_hds[i], "serial%d console\r\n", i); } @@ -6314,8 +6327,6 @@ int main(int argc, char **argv, char **envp) for(i = 0; i < MAX_PARALLEL_PORTS; i++) { const char *devname = parallel_devices[i]; if (devname && strcmp(devname, "none")) { - char label[32]; - snprintf(label, sizeof(label), "parallel%d", i); if (strstart(devname, "vc", 0)) qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i); } @@ -6324,8 +6335,6 @@ int main(int argc, char **argv, char **envp) for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) { const char *devname = virtio_consoles[i]; if (virtcon_hds[i] && devname) { - char label[32]; - snprintf(label, sizeof(label), "virtcon%d", i); if (strstart(devname, "vc", 0)) qemu_chr_printf(virtcon_hds[i], "virtio console%d\r\n", i); } @@ -216,6 +216,8 @@ static inline uint32_t vnc_has_feature(VncState *vs, int feature) { */ static void vnc_update_client(void *opaque); +static void vnc_disconnect_start(VncState *vs); +static void vnc_disconnect_finish(VncState *vs); static void vnc_colordepth(VncState *vs); @@ -652,9 +654,6 @@ static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h) static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h) { - vs->force_update = 1; - vnc_update_client(vs); - vnc_write_u8(vs, 0); /* msg id */ vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); /* number of rects */ @@ -667,13 +666,22 @@ static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, i static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h) { VncDisplay *vd = ds->opaque; - VncState *vs = vd->clients; - while (vs != NULL) { + VncState *vs, *vn; + + for (vs = vd->clients; vs != NULL; vs = vn) { + vn = vs->next; + if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) { + vs->force_update = 1; + vnc_update_client(vs); + /* vs might be free()ed here */ + } + } + + for (vs = vd->clients; vs != NULL; vs = vs->next) { if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h); else /* TODO */ vnc_update(vs, dst_x, dst_y, w, h); - vs = vs->next; } } @@ -798,6 +806,8 @@ static void vnc_update_client(void *opaque) if (vs->csock != -1) { qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL); + } else { + vnc_disconnect_finish(vs); } } @@ -868,6 +878,48 @@ static void audio_del(VncState *vs) } } +static void vnc_disconnect_start(VncState *vs) +{ + if (vs->csock == -1) + return; + qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); + closesocket(vs->csock); + vs->csock = -1; +} + +static void vnc_disconnect_finish(VncState *vs) +{ + qemu_del_timer(vs->timer); + qemu_free_timer(vs->timer); + if (vs->input.buffer) qemu_free(vs->input.buffer); + if (vs->output.buffer) qemu_free(vs->output.buffer); +#ifdef CONFIG_VNC_TLS + vnc_tls_client_cleanup(vs); +#endif /* CONFIG_VNC_TLS */ +#ifdef CONFIG_VNC_SASL + vnc_sasl_client_cleanup(vs); +#endif /* CONFIG_VNC_SASL */ + audio_del(vs); + + VncState *p, *parent = NULL; + for (p = vs->vd->clients; p != NULL; p = p->next) { + if (p == vs) { + if (parent) + parent->next = p->next; + else + vs->vd->clients = p->next; + break; + } + parent = p; + } + if (!vs->vd->clients) + dcl->idle = 1; + + qemu_free(vs->server.ds->data); + qemu_free(vs->server.ds); + qemu_free(vs->guest.ds); + qemu_free(vs); +} int vnc_client_io_error(VncState *vs, int ret, int last_errno) { @@ -885,39 +937,9 @@ int vnc_client_io_error(VncState *vs, int ret, int last_errno) } } - VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0); - qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); - closesocket(vs->csock); - qemu_del_timer(vs->timer); - qemu_free_timer(vs->timer); - if (vs->input.buffer) qemu_free(vs->input.buffer); - if (vs->output.buffer) qemu_free(vs->output.buffer); -#ifdef CONFIG_VNC_TLS - vnc_tls_client_cleanup(vs); -#endif /* CONFIG_VNC_TLS */ -#ifdef CONFIG_VNC_SASL - vnc_sasl_client_cleanup(vs); -#endif /* CONFIG_VNC_SASL */ - audio_del(vs); - - VncState *p, *parent = NULL; - for (p = vs->vd->clients; p != NULL; p = p->next) { - if (p == vs) { - if (parent) - parent->next = p->next; - else - vs->vd->clients = p->next; - break; - } - parent = p; - } - if (!vs->vd->clients) - dcl->idle = 1; - - qemu_free(vs->server.ds->data); - qemu_free(vs->server.ds); - qemu_free(vs->guest.ds); - qemu_free(vs); + VNC_DEBUG("Closing down client sock: ret %d, errno %d\n", + ret, ret < 0 ? last_errno : 0); + vnc_disconnect_start(vs); return 0; } @@ -927,7 +949,8 @@ int vnc_client_io_error(VncState *vs, int ret, int last_errno) void vnc_client_error(VncState *vs) { - vnc_client_io_error(vs, -1, EINVAL); + VNC_DEBUG("Closing down client sock: protocol error\n"); + vnc_disconnect_start(vs); } @@ -1110,16 +1133,21 @@ void vnc_client_read(void *opaque) else #endif /* CONFIG_VNC_SASL */ ret = vnc_client_read_plain(vs); - if (!ret) + if (!ret) { + if (vs->csock == -1) + vnc_disconnect_finish(vs); return; + } while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) { size_t len = vs->read_handler_expect; int ret; ret = vs->read_handler(vs, vs->input.buffer, len); - if (vs->csock == -1) + if (vs->csock == -1) { + vnc_disconnect_finish(vs); return; + } if (!ret) { memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len)); @@ -1134,7 +1162,7 @@ void vnc_write(VncState *vs, const void *data, size_t len) { buffer_reserve(&vs->output, len); - if (buffer_empty(&vs->output)) { + if (vs->csock != -1 && buffer_empty(&vs->output)) { qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs); } @@ -1175,7 +1203,7 @@ void vnc_write_u8(VncState *vs, uint8_t value) void vnc_flush(VncState *vs) { - if (vs->output.offset) + if (vs->csock != -1 && vs->output.offset) vnc_client_write(vs); } @@ -1333,6 +1361,7 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym) } else { /* QEMU console emulation */ if (down) { + int numlock = vs->modifiers_state[0x45]; switch (keycode) { case 0x2a: /* Left Shift */ case 0x36: /* Right Shift */ @@ -1342,41 +1371,83 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym) case 0xb8: /* Right ALT */ break; case 0xc8: - case 0x48: kbd_put_keysym(QEMU_KEY_UP); break; case 0xd0: - case 0x50: kbd_put_keysym(QEMU_KEY_DOWN); break; case 0xcb: - case 0x4b: kbd_put_keysym(QEMU_KEY_LEFT); break; case 0xcd: - case 0x4d: kbd_put_keysym(QEMU_KEY_RIGHT); break; case 0xd3: - case 0x53: kbd_put_keysym(QEMU_KEY_DELETE); break; case 0xc7: - case 0x47: kbd_put_keysym(QEMU_KEY_HOME); break; case 0xcf: - case 0x4f: kbd_put_keysym(QEMU_KEY_END); break; case 0xc9: - case 0x49: kbd_put_keysym(QEMU_KEY_PAGEUP); break; case 0xd1: - case 0x51: kbd_put_keysym(QEMU_KEY_PAGEDOWN); break; + + case 0x47: + kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME); + break; + case 0x48: + kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP); + break; + case 0x49: + kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP); + break; + case 0x4b: + kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT); + break; + case 0x4c: + kbd_put_keysym('5'); + break; + case 0x4d: + kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT); + break; + case 0x4f: + kbd_put_keysym(numlock ? '1' : QEMU_KEY_END); + break; + case 0x50: + kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN); + break; + case 0x51: + kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN); + break; + case 0x52: + kbd_put_keysym('0'); + break; + case 0x53: + kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE); + break; + + case 0xb5: + kbd_put_keysym('/'); + break; + case 0x37: + kbd_put_keysym('*'); + break; + case 0x4a: + kbd_put_keysym('-'); + break; + case 0x4e: + kbd_put_keysym('+'); + break; + case 0x9c: + kbd_put_keysym('\n'); + break; + default: kbd_put_keysym(sym); break; @@ -2009,11 +2080,13 @@ static void vnc_connect(VncDisplay *vd, int csock) vnc_write(vs, "RFB 003.008\n", 12); vnc_flush(vs); vnc_read_when(vs, protocol_version, 12); - vnc_update_client(vs); reset_keys(vs); vs->next = vd->clients; vd->clients = vs; + + vnc_update_client(vs); + /* vs might be free()ed here */ } static void vnc_listen_read(void *opaque) |