aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2009-06-17 09:39:04 +0300
committerAvi Kivity <avi@redhat.com>2009-06-17 09:39:04 +0300
commit1407fe807a5d5bbbdaafd4a48cb406a9d78aa18a (patch)
tree21d4c06538a193bf0503aea7cb0e5eb0ec932165
parenta5b526135da17b56a7be85fd51a76a1d5a917617 (diff)
parentcfde4bd93100c58c0bfaed76deefb144caac488f (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>
-rw-r--r--Makefile6
-rw-r--r--Makefile.target2
-rw-r--r--block.c13
-rw-r--r--block.h2
-rw-r--r--block/qcow2-cluster.c800
-rw-r--r--block/qcow2-refcount.c854
-rw-r--r--block/qcow2-snapshot.c405
-rw-r--r--block/qcow2.c2083
-rw-r--r--block/qcow2.h203
-rw-r--r--block/raw-posix.c3
-rwxr-xr-xconfigure72
-rw-r--r--cpu-all.h3
-rw-r--r--cpu-common.h3
-rw-r--r--elf.h19
-rw-r--r--exec.c241
-rw-r--r--hw/ac97.c4
-rw-r--r--hw/apb_pci.c8
-rw-r--r--hw/apic.c2
-rw-r--r--hw/arm_gic.c2
-rw-r--r--hw/arm_sysctl.c2
-rw-r--r--hw/arm_timer.c4
-rw-r--r--hw/armv7m.c2
-rw-r--r--hw/axis_dev88.c4
-rw-r--r--hw/cirrus_vga.c12
-rw-r--r--hw/cs4231.c2
-rw-r--r--hw/cuda.c2
-rw-r--r--hw/device-assignment.c14
-rw-r--r--hw/dp8393x.c2
-rw-r--r--hw/ds1225y.c4
-rw-r--r--hw/e1000.c6
-rw-r--r--hw/eccmemctl.c4
-rw-r--r--hw/eepro100.c8
-rw-r--r--hw/es1370.c2
-rw-r--r--hw/escc.c4
-rw-r--r--hw/esp.c2
-rw-r--r--hw/etraxfs_dma.c2
-rw-r--r--hw/etraxfs_eth.c2
-rw-r--r--hw/etraxfs_pic.c2
-rw-r--r--hw/etraxfs_ser.c2
-rw-r--r--hw/etraxfs_timer.c2
-rw-r--r--hw/fdc.c4
-rw-r--r--hw/fw_cfg.c4
-rw-r--r--hw/g364fb.c2
-rw-r--r--hw/grackle_pci.c4
-rw-r--r--hw/gt64xxx.c2
-rw-r--r--hw/heathrow_pic.c2
-rw-r--r--hw/hpet.c2
-rw-r--r--hw/ide.c46
-rw-r--r--hw/integratorcp.c6
-rw-r--r--hw/ioapic.c2
-rw-r--r--hw/iommu.c2
-rw-r--r--hw/isa_mmio.c2
-rw-r--r--hw/jazz_led.c2
-rw-r--r--hw/lsi53c895a.c26
-rw-r--r--hw/m48t59.c2
-rw-r--r--hw/mac_dbdma.c2
-rw-r--r--hw/mac_nvram.c2
-rw-r--r--hw/macio.c2
-rw-r--r--hw/mc146818rtc.c2
-rw-r--r--hw/mcf5206.c2
-rw-r--r--hw/mcf5208.c4
-rw-r--r--hw/mcf_fec.c2
-rw-r--r--hw/mcf_intc.c2
-rw-r--r--hw/mcf_uart.c2
-rw-r--r--hw/mips_jazz.c4
-rw-r--r--hw/mips_malta.c2
-rw-r--r--hw/mips_r4k.c2
-rw-r--r--hw/mpcore.c2
-rw-r--r--hw/mst_fpga.c2
-rw-r--r--hw/musicpal.c18
-rw-r--r--hw/ne2000.c2
-rw-r--r--hw/omap.h6
-rw-r--r--hw/omap1.c48
-rw-r--r--hw/omap2.c32
-rw-r--r--hw/omap_dma.c4
-rw-r--r--hw/omap_dss.c10
-rw-r--r--hw/omap_i2c.c4
-rw-r--r--hw/omap_lcdc.c2
-rw-r--r--hw/omap_mmc.c4
-rw-r--r--hw/omap_sx1.c10
-rw-r--r--hw/onenand.c2
-rw-r--r--hw/openpic.c8
-rw-r--r--hw/palm.c8
-rw-r--r--hw/parallel.c2
-rw-r--r--hw/pci-hotplug.c1
-rw-r--r--hw/pci.c2
-rw-r--r--hw/pci.h2
-rw-r--r--hw/pci_ids.h2
-rw-r--r--hw/pckbd.c2
-rw-r--r--hw/pcnet.c8
-rw-r--r--hw/pflash_cfi01.c2
-rw-r--r--hw/pflash_cfi02.c2
-rw-r--r--hw/pl011.c2
-rw-r--r--hw/pl022.c2
-rw-r--r--hw/pl031.c2
-rw-r--r--hw/pl050.c2
-rw-r--r--hw/pl061.c2
-rw-r--r--hw/pl080.c2
-rw-r--r--hw/pl110.c2
-rw-r--r--hw/pl181.c2
-rw-r--r--hw/pl190.c2
-rw-r--r--hw/ppc405_boards.c4
-rw-r--r--hw/ppc4xx_devs.c2
-rw-r--r--hw/ppc4xx_pci.c6
-rw-r--r--hw/ppc_newworld.c2
-rw-r--r--hw/ppc_prep.c6
-rw-r--r--hw/ppce500_pci.c6
-rw-r--r--hw/prep_pci.c2
-rw-r--r--hw/pxa2xx.c24
-rw-r--r--hw/pxa2xx_dma.c2
-rw-r--r--hw/pxa2xx_gpio.c2
-rw-r--r--hw/pxa2xx_keypad.c2
-rw-r--r--hw/pxa2xx_lcd.c2
-rw-r--r--hw/pxa2xx_mmci.c2
-rw-r--r--hw/pxa2xx_pcmcia.c6
-rw-r--r--hw/pxa2xx_pic.c2
-rw-r--r--hw/pxa2xx_timer.c2
-rw-r--r--hw/r2d.c2
-rw-r--r--hw/rc4030.c4
-rw-r--r--hw/realview_gic.c2
-rw-r--r--hw/rtl8139.c6
-rw-r--r--hw/sbi.c2
-rw-r--r--hw/serial.c2
-rw-r--r--hw/sh7750.c6
-rw-r--r--hw/sh_intc.c2
-rw-r--r--hw/sh_pci.c6
-rw-r--r--hw/sh_serial.c2
-rw-r--r--hw/sh_timer.c2
-rw-r--r--hw/slavio_intctl.c6
-rw-r--r--hw/slavio_misc.c16
-rw-r--r--hw/slavio_timer.c2
-rw-r--r--hw/sm501.c4
-rw-r--r--hw/smc91c111.c2
-rw-r--r--hw/sparc32_dma.c2
-rw-r--r--hw/spitz.c2
-rw-r--r--hw/stellaris.c8
-rw-r--r--hw/stellaris_enet.c2
-rw-r--r--hw/sun4c_intctl.c2
-rw-r--r--hw/sun4u.c4
-rw-r--r--hw/syborg_fb.c2
-rw-r--r--hw/syborg_interrupt.c2
-rw-r--r--hw/syborg_keyboard.c2
-rw-r--r--hw/syborg_pointer.c2
-rw-r--r--hw/syborg_rtc.c2
-rw-r--r--hw/syborg_serial.c2
-rw-r--r--hw/syborg_timer.c2
-rw-r--r--hw/syborg_virtio.c2
-rw-r--r--hw/tc6393xb.c2
-rw-r--r--hw/tcx.c4
-rw-r--r--hw/tusb6010.c2
-rw-r--r--hw/unin_pci.c12
-rw-r--r--hw/usb-ohci.c4
-rw-r--r--hw/usb-uhci.c4
-rw-r--r--hw/versatile_pci.c2
-rw-r--r--hw/versatilepb.c2
-rw-r--r--hw/vga.c15
-rw-r--r--hw/virtio-blk.c1
-rw-r--r--hw/virtio-pci.c2
-rw-r--r--hw/vmware_vga.c6
-rw-r--r--hw/wdt_i6300esb.c4
-rw-r--r--hw/xilinx_ethlite.c2
-rw-r--r--hw/xilinx_intc.c2
-rw-r--r--hw/xilinx_timer.c2
-rw-r--r--hw/xilinx_uartlite.c2
-rw-r--r--hw/zaurus.c2
-rw-r--r--kqemu.c2
-rw-r--r--kvm-all.c3
-rw-r--r--linux-user/arm/syscall_nr.h9
-rw-r--r--linux-user/elfload.c1009
-rw-r--r--linux-user/i386/syscall_nr.h8
-rw-r--r--linux-user/linuxload.c50
-rw-r--r--linux-user/m68k/syscall_nr.h8
-rw-r--r--linux-user/main.c42
-rw-r--r--linux-user/mips/syscall_nr.h9
-rw-r--r--linux-user/mips64/syscall_nr.h9
-rw-r--r--linux-user/mipsn32/syscall_nr.h9
-rw-r--r--linux-user/mmap.c4
-rw-r--r--linux-user/ppc/syscall_nr.h9
-rw-r--r--linux-user/qemu.h14
-rw-r--r--linux-user/sh4/syscall_nr.h8
-rw-r--r--linux-user/signal.c40
-rw-r--r--linux-user/sparc/syscall_nr.h9
-rw-r--r--linux-user/sparc64/syscall_nr.h9
-rw-r--r--linux-user/strace.c1072
-rw-r--r--linux-user/strace.list111
-rw-r--r--linux-user/syscall.c595
-rw-r--r--linux-user/syscall_defs.h41
-rw-r--r--linux-user/x86_64/syscall_nr.h9
-rw-r--r--migration.c30
-rw-r--r--migration.h4
-rw-r--r--qemu-char.c32
-rw-r--r--qemu-monitor.hx8
-rw-r--r--readline.c3
-rw-r--r--target-i386/cpu.h1
-rw-r--r--target-i386/helper.c23
-rw-r--r--vl.c25
-rw-r--r--vnc.c181
197 files changed, 5938 insertions, 2840 deletions
diff --git a/Makefile b/Makefile
index 42fe55b3c..035bbbc67 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/block.c b/block.c
index c7e0dcbc5..aca5a6d28 100644
--- a/block.c
+++ b/block.c
@@ -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)
diff --git a/block.h b/block.h
index 0acac63b8..71e87fc9e 100644
--- a/block.h
+++ b/block.h
@@ -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;
diff --git a/configure b/configure
index 7616e98a9..cab39bcd6 100755
--- a/configure
+++ b/configure
@@ -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
diff --git a/cpu-all.h b/cpu-all.h
index 6254af958..88c871e2b 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -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);
diff --git a/elf.h b/elf.h
index 182cad92d..b0420029d 100644
--- a/elf.h
+++ b/elf.h
@@ -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 */
diff --git a/exec.c b/exec.c
index b8ffaf100..299d7ff42 100644
--- a/exec.c
+++ b/exec.c
@@ -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) */
diff --git a/hw/ac97.c b/hw/ac97.c
index 288f42813..a70bb9074 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -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);
diff --git a/hw/apic.c b/hw/apic.c
index 5680cb01e..d8f78616c 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -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);
diff --git a/hw/cuda.c b/hw/cuda.c
index 828ccf722..edc3d4ad2 100644
--- a/hw/cuda.c
+++ b/hw/cuda.c
@@ -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);
diff --git a/hw/escc.c b/hw/escc.c
index 3d982b579..1911e7d10 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -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,
diff --git a/hw/esp.c b/hw/esp.c
index ffb222525..5fa910c8b 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -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(&eth->phy);
mdio_attach(&eth->mdio_bus, &eth->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);
diff --git a/hw/fdc.c b/hw/fdc.c
index 4c6284ceb..aa89db381 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -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);
diff --git a/hw/hpet.c b/hw/hpet.c
index 29db325ee..e0be48612 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -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);
}
diff --git a/hw/ide.c b/hw/ide.c
index f8da7c9b1..f3787f256 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -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];
diff --git a/hw/omap.h b/hw/omap.h
index 231049dc7..e25904c8b 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -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;
}
diff --git a/hw/palm.c b/hw/palm.c
index e9be05821..8b3a2ba04 100644
--- a/hw/palm.c
+++ b/hw/palm.c
@@ -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;
}
diff --git a/hw/pci.c b/hw/pci.c
index 2fd258a9d..1dcdb011d 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -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)
{
diff --git a/hw/pci.h b/hw/pci.h
index 7051263c2..d835b6dac 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -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);
diff --git a/hw/r2d.c b/hw/r2d.c
index 5b69c4f5d..a529ab4a8 100644
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -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;
diff --git a/hw/sbi.c b/hw/sbi.c
index a601a59eb..4350b6ef9 100644
--- a/hw/sbi.c
+++ b/hw/sbi.c
@@ -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);
diff --git a/hw/tcx.c b/hw/tcx.c
index 450ff9dd8..217a2a6c1 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -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. */
diff --git a/hw/vga.c b/hw/vga.c
index 241d3520d..024e38d45 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -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);
diff --git a/kqemu.c b/kqemu.c
index 171849886..c27c6ae30 100644
--- a/kqemu.c
+++ b/kqemu.c
@@ -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,
diff --git a/kvm-all.c b/kvm-all.c
index b24d8766f..d843338f3 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -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 = &regs1;
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:
diff --git a/vl.c b/vl.c
index 0b9f7ea20..72789997f 100644
--- a/vl.c
+++ b/vl.c
@@ -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);
}
diff --git a/vnc.c b/vnc.c
index e1ca9f8c7..de0ff872d 100644
--- a/vnc.c
+++ b/vnc.c
@@ -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)