aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--Makefile.target1
-rw-r--r--block-migration.c558
-rw-r--r--block-migration.h29
-rw-r--r--block.c78
-rw-r--r--block.h8
-rw-r--r--block_int.h2
-rw-r--r--buffered_file.c10
-rw-r--r--console.c2
-rw-r--r--disas.c3
-rw-r--r--hw/baum.c2
-rw-r--r--hw/devices.h3
-rw-r--r--hw/hw.h9
-rw-r--r--hw/lan9118.c1093
-rw-r--r--hw/mips_malta.c58
-rw-r--r--hw/mips_r4k.c27
-rw-r--r--hw/openpic.c2
-rw-r--r--hw/pci.c6
-rw-r--r--hw/realview.c108
-rw-r--r--hw/unin_pci.c14
-rw-r--r--kvm-all.c2
-rw-r--r--kvm.h2
-rw-r--r--migration-exec.c9
-rw-r--r--migration-fd.c7
-rw-r--r--migration-tcp.c7
-rw-r--r--migration-unix.c7
-rw-r--r--migration.c23
-rw-r--r--migration.h20
-rw-r--r--monitor.c36
-rw-r--r--qemu-char.c45
-rw-r--r--qemu-char.h3
-rw-r--r--qemu-doc.texi7
-rw-r--r--qemu-kvm-x86.c19
-rw-r--r--qemu-monitor.hx19
-rw-r--r--rules.mak2
-rw-r--r--savevm.c62
-rw-r--r--sh4-dis.c2
-rw-r--r--sysemu.h2
-rw-r--r--target-i386/cpu.h3
-rw-r--r--target-i386/kvm.c29
-rw-r--r--target-i386/machine.c24
-rw-r--r--target-mips/cpu.h5
-rw-r--r--target-mips/op_helper.c2
-rw-r--r--target-mips/translate.c59
-rw-r--r--target-mips/translate_init.c50
-rw-r--r--target-ppc/kvm.c4
-rw-r--r--tcg/i386/tcg-target.c1
-rw-r--r--vl.c10
48 files changed, 2218 insertions, 262 deletions
diff --git a/Makefile b/Makefile
index 93efc9bb2..973f97a97 100644
--- a/Makefile
+++ b/Makefile
@@ -151,6 +151,7 @@ obj-y += qemu-char.o aio.o savevm.o
obj-y += msmouse.o ps2.o
obj-y += qdev.o qdev-properties.o
obj-y += qint.o qstring.o qdict.o qlist.o qemu-config.o
+obj-y += block-migration.o
obj-$(CONFIG_BRLAPI) += baum.o
obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
@@ -250,12 +251,13 @@ clean:
rm -f qemu-img-cmds.h
$(MAKE) -C tests clean
for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser; do \
- $(MAKE) -C $$d $@ || exit 1 ; \
+ if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
done
distclean: clean
- rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi
+ rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi
rm -f config-all-devices.mak config-all-devices.h*
+ rm -f roms/seabios/config.mak roms/vgabios/config.mak
rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr}
for d in $(TARGET_DIRS) libhw32 libhw64 libuser; do \
rm -rf $$d || exit 1 ; \
diff --git a/Makefile.target b/Makefile.target
index 26eb1fb07..8ee5b23ac 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -317,6 +317,7 @@ obj-arm-y += framebuffer.o
obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
obj-arm-y += syborg_virtio.o
+obj-arm-y += lan9118.o
obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o serial.o
diff --git a/block-migration.c b/block-migration.c
new file mode 100644
index 000000000..4b4eddf62
--- /dev/null
+++ b/block-migration.c
@@ -0,0 +1,558 @@
+/*
+ * QEMU live block migration
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ * Liran Schour <lirans@il.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "block_int.h"
+#include "hw/hw.h"
+#include "block-migration.h"
+#include <assert.h>
+#include <pthread.h>
+
+#define SECTOR_BITS 9
+#define SECTOR_SIZE (1 << SECTOR_BITS)
+#define SECTOR_MASK ~(SECTOR_SIZE - 1);
+
+#define BLOCK_SIZE (block_mig_state->sectors_per_block << SECTOR_BITS)
+
+#define BLK_MIG_FLAG_DEVICE_BLOCK 0x01
+#define BLK_MIG_FLAG_EOS 0x02
+
+#define MAX_IS_ALLOCATED_SEARCH 65536
+#define MAX_BLOCKS_READ 10000
+#define BLOCKS_READ_CHANGE 100
+#define INITIAL_BLOCKS_READ 100
+
+//#define DEBUG_BLK_MIGRATION
+
+#ifdef DEBUG_BLK_MIGRATION
+#define dprintf(fmt, ...) \
+ do { printf("blk_migration: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+ do { } while (0)
+#endif
+
+typedef struct BlkMigBlock {
+ uint8_t *buf;
+ BlkMigDevState *bmds;
+ int64_t sector;
+ struct iovec iov;
+ QEMUIOVector qiov;
+ BlockDriverAIOCB *aiocb;
+ int ret;
+ struct BlkMigBlock *next;
+} BlkMigBlock;
+
+typedef struct BlkMigState {
+ int bulk_completed;
+ int blk_enable;
+ int shared_base;
+ int no_dirty;
+ QEMUFile *load_file;
+ BlkMigDevState *bmds_first;
+ int sectors_per_block;
+ BlkMigBlock *first_blk;
+ BlkMigBlock *last_blk;
+ int submitted;
+ int read_done;
+ int transferred;
+ int64_t print_completion;
+} BlkMigState;
+
+static BlkMigState *block_mig_state = NULL;
+
+static void blk_mig_read_cb(void *opaque, int ret)
+{
+ BlkMigBlock *blk = opaque;
+
+ blk->ret = ret;
+
+ /* insert at the end */
+ if(block_mig_state->last_blk == NULL) {
+ block_mig_state->first_blk = blk;
+ block_mig_state->last_blk = blk;
+ } else {
+ block_mig_state->last_blk->next = blk;
+ block_mig_state->last_blk = blk;
+ }
+
+ block_mig_state->submitted--;
+ block_mig_state->read_done++;
+ assert(block_mig_state->submitted >= 0);
+
+ return;
+}
+
+static int mig_read_device_bulk(QEMUFile *f, BlkMigDevState *bms)
+{
+ int nr_sectors;
+ int64_t total_sectors, cur_sector = 0;
+ BlockDriverState *bs = bms->bs;
+ BlkMigBlock *blk;
+
+ blk = qemu_malloc(sizeof(BlkMigBlock));
+ blk->buf = qemu_malloc(BLOCK_SIZE);
+
+ cur_sector = bms->cur_sector;
+ total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
+
+ if(bms->shared_base) {
+ while(cur_sector < bms->total_sectors &&
+ !bdrv_is_allocated(bms->bs, cur_sector,
+ MAX_IS_ALLOCATED_SEARCH, &nr_sectors)) {
+ cur_sector += nr_sectors;
+ }
+ }
+
+ if(cur_sector >= total_sectors) {
+ bms->cur_sector = total_sectors;
+ qemu_free(blk->buf);
+ qemu_free(blk);
+ return 1;
+ }
+
+ if(cur_sector >= block_mig_state->print_completion) {
+ printf("Completed %" PRId64 " %%\r", cur_sector * 100 / total_sectors);
+ fflush(stdout);
+ block_mig_state->print_completion +=
+ (block_mig_state->sectors_per_block * 10000);
+ }
+
+ /* we going to transfder BLOCK_SIZE any way even if it is not allocated */
+ nr_sectors = block_mig_state->sectors_per_block;
+
+ cur_sector &= ~((int64_t)block_mig_state->sectors_per_block -1);
+
+ if(total_sectors - cur_sector < block_mig_state->sectors_per_block) {
+ nr_sectors = (total_sectors - cur_sector);
+ }
+
+ bms->cur_sector = cur_sector + nr_sectors;
+ blk->sector = cur_sector;
+ blk->bmds = bms;
+ blk->next = NULL;
+
+ blk->iov.iov_base = blk->buf;
+ blk->iov.iov_len = nr_sectors * SECTOR_SIZE;
+ qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
+
+ blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
+ nr_sectors, blk_mig_read_cb, blk);
+
+ if(!blk->aiocb) {
+ printf("Error reading sector %" PRId64 "\n", cur_sector);
+ qemu_free(blk->buf);
+ qemu_free(blk);
+ return 0;
+ }
+
+ bdrv_reset_dirty(bms->bs, cur_sector, nr_sectors);
+ block_mig_state->submitted++;
+
+ return (bms->cur_sector >= total_sectors);
+}
+
+static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
+{
+ int len, nr_sectors;
+ int64_t total_sectors = bmds->total_sectors, cur_sector = 0;
+ uint8_t *tmp_buf = NULL;
+ BlockDriverState *bs = bmds->bs;
+
+ tmp_buf = qemu_malloc(BLOCK_SIZE);
+
+ cur_sector = bmds->cur_sector;
+
+ if(bmds->shared_base) {
+ while(cur_sector < bmds->total_sectors &&
+ !bdrv_is_allocated(bmds->bs, cur_sector,
+ MAX_IS_ALLOCATED_SEARCH, &nr_sectors)) {
+ cur_sector += nr_sectors;
+ }
+ }
+
+ if(cur_sector >= total_sectors) {
+ bmds->cur_sector = total_sectors;
+ qemu_free(tmp_buf);
+ return 1;
+ }
+
+ if(cur_sector >= block_mig_state->print_completion) {
+ printf("Completed %" PRId64 " %%\r", cur_sector * 100 / total_sectors);
+ fflush(stdout);
+ block_mig_state->print_completion +=
+ (block_mig_state->sectors_per_block * 10000);
+ }
+
+ cur_sector &= ~((int64_t)block_mig_state->sectors_per_block -1);
+
+ /* we going to transfer
+ BLOCK_SIZE
+ any way even if it is not allocated */
+ nr_sectors = block_mig_state->sectors_per_block;
+
+ if(total_sectors - cur_sector < block_mig_state->sectors_per_block) {
+ nr_sectors = (total_sectors - cur_sector);
+ }
+
+ if(bdrv_read(bs, cur_sector, tmp_buf, nr_sectors) < 0) {
+ printf("Error reading sector %" PRId64 "\n", cur_sector);
+ }
+
+ bdrv_reset_dirty(bs, cur_sector, nr_sectors);
+
+ /* Device name */
+ qemu_put_be64(f,(cur_sector << SECTOR_BITS) | BLK_MIG_FLAG_DEVICE_BLOCK);
+
+ len = strlen(bs->device_name);
+ qemu_put_byte(f, len);
+ qemu_put_buffer(f, (uint8_t *)bs->device_name, len);
+
+ qemu_put_buffer(f, tmp_buf,
+ BLOCK_SIZE);
+
+ bmds->cur_sector = cur_sector + block_mig_state->sectors_per_block;
+
+ qemu_free(tmp_buf);
+
+ return (bmds->cur_sector >= total_sectors);
+}
+
+static void send_blk(QEMUFile *f, BlkMigBlock * blk)
+{
+ int len;
+
+ /* Device name */
+ qemu_put_be64(f,(blk->sector << SECTOR_BITS) | BLK_MIG_FLAG_DEVICE_BLOCK);
+
+ len = strlen(blk->bmds->bs->device_name);
+ qemu_put_byte(f, len);
+ qemu_put_buffer(f, (uint8_t *)blk->bmds->bs->device_name, len);
+
+ qemu_put_buffer(f, blk->buf,
+ BLOCK_SIZE);
+
+ return;
+}
+
+static void blk_mig_save_dev_info(QEMUFile *f, BlkMigDevState *bmds)
+{
+}
+
+static void set_dirty_tracking(int enable)
+{
+ BlkMigDevState *bmds;
+ for(bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) {
+ bdrv_set_dirty_tracking(bmds->bs,enable);
+ }
+
+ return;
+}
+
+static void init_blk_migration(QEMUFile *f)
+{
+ BlkMigDevState **pbmds, *bmds;
+ BlockDriverState *bs;
+
+ for (bs = bdrv_first; bs != NULL; bs = bs->next) {
+ if(bs->type == BDRV_TYPE_HD) {
+ bmds = qemu_mallocz(sizeof(BlkMigDevState));
+ bmds->bs = bs;
+ bmds->bulk_completed = 0;
+ bmds->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
+ bmds->shared_base = block_mig_state->shared_base;
+
+ if(bmds->shared_base) {
+ printf("Start migration for %s with shared base image\n",
+ bs->device_name);
+ } else {
+ printf("Start full migration for %s\n", bs->device_name);
+ }
+
+ /* insert at the end */
+ pbmds = &block_mig_state->bmds_first;
+ while (*pbmds != NULL)
+ pbmds = &(*pbmds)->next;
+ *pbmds = bmds;
+
+ blk_mig_save_dev_info(f, bmds);
+
+ }
+ }
+
+ block_mig_state->sectors_per_block = bdrv_get_sectors_per_chunk();
+
+ return;
+}
+
+static int blk_mig_save_bulked_block(QEMUFile *f, int is_async)
+{
+ BlkMigDevState *bmds;
+
+ for (bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) {
+ if(bmds->bulk_completed == 0) {
+ if(is_async) {
+ if(mig_read_device_bulk(f, bmds) == 1) {
+ /* completed bulk section for this device */
+ bmds->bulk_completed = 1;
+ }
+ } else {
+ if(mig_save_device_bulk(f,bmds) == 1) {
+ /* completed bulk section for this device */
+ bmds->bulk_completed = 1;
+ }
+ }
+ return 1;
+ }
+ }
+
+ /* we reached here means bulk is completed */
+ block_mig_state->bulk_completed = 1;
+
+ return 0;
+
+}
+
+#define MAX_NUM_BLOCKS 4
+
+static void blk_mig_save_dirty_blocks(QEMUFile *f)
+{
+ BlkMigDevState *bmds;
+ uint8_t buf[BLOCK_SIZE];
+ int64_t sector;
+ int len;
+
+ for(bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) {
+ for(sector = 0; sector < bmds->cur_sector;) {
+
+ if(bdrv_get_dirty(bmds->bs,sector)) {
+
+ if(bdrv_read(bmds->bs, sector, buf,
+ block_mig_state->sectors_per_block) < 0) {
+ }
+
+ /* device name */
+ qemu_put_be64(f,(sector << SECTOR_BITS)
+ | BLK_MIG_FLAG_DEVICE_BLOCK);
+
+ len = strlen(bmds->bs->device_name);
+
+ qemu_put_byte(f, len);
+ qemu_put_buffer(f, (uint8_t *)bmds->bs->device_name, len);
+
+ qemu_put_buffer(f, buf,
+ (block_mig_state->sectors_per_block *
+ SECTOR_SIZE));
+
+ bdrv_reset_dirty(bmds->bs, sector,
+ block_mig_state->sectors_per_block);
+
+ sector += block_mig_state->sectors_per_block;
+ } else {
+ /* sector is clean */
+ sector += block_mig_state->sectors_per_block;
+ }
+ }
+ }
+
+ return;
+}
+
+static void flush_blks(QEMUFile* f)
+{
+ BlkMigBlock *blk, *tmp;
+
+ dprintf("%s Enter submitted %d read_done %d transfered\n", __FUNCTION__,
+ submitted, read_done, transfered);
+
+ for(blk = block_mig_state->first_blk;
+ blk != NULL && !qemu_file_rate_limit(f); blk = tmp) {
+ send_blk(f, blk);
+
+ tmp = blk->next;
+ qemu_free(blk->buf);
+ qemu_free(blk);
+
+ block_mig_state->read_done--;
+ block_mig_state->transferred++;
+ assert(block_mig_state->read_done >= 0);
+ }
+ block_mig_state->first_blk = blk;
+
+ if(block_mig_state->first_blk == NULL) {
+ block_mig_state->last_blk = NULL;
+ }
+
+ dprintf("%s Exit submitted %d read_done %d transferred%d\n", __FUNCTION__,
+ block_mig_state->submitted, block_mig_state->read_done,
+ block_mig_state->transferred);
+
+ return;
+}
+
+static int is_stage2_completed(void)
+{
+ BlkMigDevState *bmds;
+
+ if(block_mig_state->submitted > 0) {
+ return 0;
+ }
+
+ for (bmds = block_mig_state->bmds_first; bmds != NULL; bmds = bmds->next) {
+ if(bmds->bulk_completed == 0) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int block_save_live(QEMUFile *f, int stage, void *opaque)
+{
+ int ret = 1;
+
+ dprintf("Enter save live stage %d submitted %d transferred %d\n", stage,
+ submitted, transferred);
+
+ if(block_mig_state->blk_enable != 1) {
+ /* no need to migrate storage */
+
+ qemu_put_be64(f,BLK_MIG_FLAG_EOS);
+ return 1;
+ }
+
+ if(stage == 1) {
+ init_blk_migration(f);
+
+ /* start track dirty blocks */
+ set_dirty_tracking(1);
+
+ }
+
+ flush_blks(f);
+
+ /* control the rate of transfer */
+ while ((block_mig_state->submitted + block_mig_state->read_done) *
+ (BLOCK_SIZE) <
+ (qemu_file_get_rate_limit(f))) {
+
+ ret = blk_mig_save_bulked_block(f, 1);
+
+ if (ret == 0) /* no more bulk blocks for now*/
+ break;
+ }
+
+ flush_blks(f);
+
+ if(stage == 3) {
+
+ while(blk_mig_save_bulked_block(f, 0) != 0);
+
+ blk_mig_save_dirty_blocks(f);
+
+ /* stop track dirty blocks */
+ set_dirty_tracking(0);;
+
+ printf("\nBlock migration completed\n");
+ }
+
+ qemu_put_be64(f,BLK_MIG_FLAG_EOS);
+
+ return ((stage == 2) && is_stage2_completed());
+}
+
+static int block_load(QEMUFile *f, void *opaque, int version_id)
+{
+ int len, flags;
+ char device_name[256];
+ int64_t addr;
+ BlockDriverState *bs;
+ uint8_t *buf;
+
+ block_mig_state->sectors_per_block = bdrv_get_sectors_per_chunk();
+ buf = qemu_malloc(BLOCK_SIZE);
+
+ do {
+
+ addr = qemu_get_be64(f);
+
+ flags = addr & ~SECTOR_MASK;
+ addr &= SECTOR_MASK;
+
+ if(flags & BLK_MIG_FLAG_DEVICE_BLOCK) {
+
+ /* get device name */
+ len = qemu_get_byte(f);
+
+ qemu_get_buffer(f, (uint8_t *)device_name, len);
+ device_name[len] = '\0';
+
+ bs = bdrv_find(device_name);
+
+ qemu_get_buffer(f, buf,
+ BLOCK_SIZE);
+ if(bs != NULL) {
+
+ bdrv_write(bs, (addr >> SECTOR_BITS),
+ buf, block_mig_state->sectors_per_block);
+ } else {
+ printf("Error unknown block device %s\n", device_name);
+ }
+ } else if(flags & BLK_MIG_FLAG_EOS) {
+
+ } else {
+ printf("Unknown flags\n");
+ }
+ } while(!(flags & BLK_MIG_FLAG_EOS));
+
+ qemu_free(buf);
+
+ return 0;
+}
+
+static void block_set_params(int blk_enable, int shared_base, void *opaque)
+{
+ assert(opaque == block_mig_state);
+
+ block_mig_state->blk_enable = blk_enable;
+ block_mig_state->shared_base = shared_base;
+
+ /* shared base means that blk_enable = 1 */
+ block_mig_state->blk_enable |= shared_base;
+
+ return;
+}
+
+void blk_mig_info(void)
+{
+ BlockDriverState *bs;
+
+ for (bs = bdrv_first; bs != NULL; bs = bs->next) {
+ printf("Device %s\n", bs->device_name);
+ if(bs->type == BDRV_TYPE_HD) {
+ printf("device %s format %s\n",
+ bs->device_name, bs->drv->format_name);
+ }
+ }
+}
+
+void blk_mig_init(void)
+{
+
+ block_mig_state = qemu_mallocz(sizeof(BlkMigState));
+
+ register_savevm_live("block", 0, 1, block_set_params, block_save_live,
+ NULL, block_load, block_mig_state);
+
+
+}
diff --git a/block-migration.h b/block-migration.h
new file mode 100644
index 000000000..c33d3cbf0
--- /dev/null
+++ b/block-migration.h
@@ -0,0 +1,29 @@
+/*
+ * QEMU live block migration
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ * Liran Schour <lirans@il.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef BLOCK_MIGRATION_H
+#define BLOCK_MIGRATION_H
+
+typedef struct BlkMigDevState {
+ BlockDriverState *bs;
+ int bulk_completed;
+ int shared_base;
+ struct BlkMigDevState *next;
+ int64_t cur_sector;
+ int64_t total_sectors;
+ int64_t dirty;
+} BlkMigDevState;
+
+void blk_mig_init(void);
+void blk_mig_info(void);
+#endif /* BLOCK_MIGRATION_H */
diff --git a/block.c b/block.c
index 1e49bc05c..6fdabff12 100644
--- a/block.c
+++ b/block.c
@@ -43,6 +43,7 @@
#define SECTOR_BITS 9
#define SECTOR_SIZE (1 << SECTOR_BITS)
+#define SECTORS_PER_DIRTY_CHUNK 8
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
@@ -641,6 +642,18 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
return drv->bdrv_read(bs, sector_num, buf, nb_sectors);
}
+static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
+ int nb_sectors, int dirty)
+{
+ int64_t start, end;
+ start = sector_num / SECTORS_PER_DIRTY_CHUNK;
+ end = (sector_num + nb_sectors) / SECTORS_PER_DIRTY_CHUNK;
+
+ for(; start <= end; start++) {
+ bs->dirty_bitmap[start] = dirty;
+ }
+}
+
/* Return < 0 if error. Important errors are:
-EIO generic I/O error (may happen for all errors)
-ENOMEDIUM No media inserted.
@@ -657,7 +670,11 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
return -EACCES;
if (bdrv_check_request(bs, sector_num, nb_sectors))
return -EIO;
-
+
+ if(bs->dirty_tracking) {
+ set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
+ }
+
return drv->bdrv_write(bs, sector_num, buf, nb_sectors);
}
@@ -1203,6 +1220,11 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
return -ENOTSUP;
if (bdrv_check_request(bs, sector_num, nb_sectors))
return -EIO;
+
+ if(bs->dirty_tracking) {
+ set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
+ }
+
return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
}
@@ -1400,6 +1422,10 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
if (bdrv_check_request(bs, sector_num, nb_sectors))
return NULL;
+ if(bs->dirty_tracking) {
+ set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
+ }
+
ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
cb, opaque);
@@ -1930,7 +1956,57 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
return NULL;
}
+
+
void *qemu_blockalign(BlockDriverState *bs, size_t size)
{
return qemu_memalign((bs && bs->buffer_alignment) ? bs->buffer_alignment : 512, size);
}
+
+void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable)
+{
+ int64_t bitmap_size;
+ if(enable) {
+ if(bs->dirty_tracking == 0) {
+ int64_t i;
+ uint8_t test;
+ bitmap_size = (bdrv_getlength(bs) >> SECTOR_BITS);
+ bitmap_size /= SECTORS_PER_DIRTY_CHUNK;
+ bitmap_size++;
+
+ bs->dirty_bitmap = qemu_mallocz(bitmap_size);
+
+ bs->dirty_tracking = enable;
+ for(i = 0; i < bitmap_size; i++) test = bs->dirty_bitmap[i];
+ }
+ } else {
+ if(bs->dirty_tracking != 0) {
+ qemu_free(bs->dirty_bitmap);
+ bs->dirty_tracking = enable;
+ }
+ }
+}
+
+int bdrv_get_dirty(BlockDriverState *bs, int64_t sector)
+{
+ int64_t chunk = sector / (int64_t)SECTORS_PER_DIRTY_CHUNK;
+
+ if(bs->dirty_bitmap != NULL &&
+ (sector << SECTOR_BITS) <= bdrv_getlength(bs)) {
+ return bs->dirty_bitmap[chunk];
+ } else {
+ return 0;
+ }
+}
+
+void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
+ int nr_sectors)
+{
+ set_dirty_bitmap(bs, cur_sector, nr_sectors, 0);
+}
+
+int bdrv_get_sectors_per_chunk(void)
+{
+ /* size must be 2^x */
+ return SECTORS_PER_DIRTY_CHUNK;
+}
diff --git a/block.h b/block.h
index 6b0146f7c..2d4f06690 100644
--- a/block.h
+++ b/block.h
@@ -80,7 +80,8 @@ void bdrv_register(BlockDriver *bdrv);
/* async block I/O */
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
typedef void BlockDriverCompletionFunc(void *opaque, int ret);
-
+typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,
+ int sector_num);
BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
@@ -187,4 +188,9 @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
int64_t pos, int size);
+void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
+int bdrv_get_dirty(BlockDriverState *bs, int64_t sector);
+void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
+ int nr_sectors);
+int bdrv_get_sectors_per_chunk(void);
#endif
diff --git a/block_int.h b/block_int.h
index 8e72abee0..7ebe926f5 100644
--- a/block_int.h
+++ b/block_int.h
@@ -168,6 +168,8 @@ struct BlockDriverState {
int cyls, heads, secs, translation;
int type;
char device_name[32];
+ int dirty_tracking;
+ uint8_t *dirty_bitmap;
BlockDriverState *next;
void *private;
};
diff --git a/buffered_file.c b/buffered_file.c
index 56b4418ed..217f75e60 100644
--- a/buffered_file.c
+++ b/buffered_file.c
@@ -211,6 +211,13 @@ out:
return s->xfer_limit;
}
+static size_t buffered_get_rate_limit(void *opaque)
+{
+ QEMUFileBuffered *s = opaque;
+
+ return s->xfer_limit;
+}
+
static void buffered_rate_tick(void *opaque)
{
QEMUFileBuffered *s = opaque;
@@ -251,7 +258,8 @@ QEMUFile *qemu_fopen_ops_buffered(void *opaque,
s->file = qemu_fopen_ops(s, buffered_put_buffer, NULL,
buffered_close, buffered_rate_limit,
- buffered_set_rate_limit);
+ buffered_set_rate_limit,
+ buffered_get_rate_limit);
s->timer = qemu_new_timer(rt_clock, buffered_rate_tick, s);
diff --git a/console.c b/console.c
index 9bbef593b..82ddbe4d9 100644
--- a/console.c
+++ b/console.c
@@ -1384,7 +1384,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpt
s->t_attrib = s->t_attrib_default;
text_console_resize(s);
- qemu_chr_reset(chr);
+ qemu_chr_generic_open(chr);
if (chr->init)
chr->init(chr);
}
diff --git a/disas.c b/disas.c
index ce342bc8e..f7bcce748 100644
--- a/disas.c
+++ b/disas.c
@@ -393,6 +393,9 @@ void monitor_disas(Monitor *mon, CPUState *env,
#else
print_insn = print_insn_little_mips;
#endif
+#elif defined(TARGET_SH4)
+ disasm_info.mach = bfd_mach_sh4;
+ print_insn = print_insn_sh;
#else
monitor_printf(mon, "0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", pc);
diff --git a/hw/baum.c b/hw/baum.c
index 8a1298505..fa356ec48 100644
--- a/hw/baum.c
+++ b/hw/baum.c
@@ -614,7 +614,7 @@ CharDriverState *chr_baum_init(QemuOpts *opts)
qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum);
- qemu_chr_reset(chr);
+ qemu_chr_generic_open(chr);
return chr;
diff --git a/hw/devices.h b/hw/devices.h
index 156bde2a2..0ac561d91 100644
--- a/hw/devices.h
+++ b/hw/devices.h
@@ -6,6 +6,9 @@
/* smc91c111.c */
void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
+/* lan9118.c */
+void lan9118_init(NICInfo *, uint32_t, qemu_irq);
+
/* tsc210x.c */
uWireSlave *tsc2102_init(qemu_irq pint);
uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav);
diff --git a/hw/hw.h b/hw/hw.h
index 3969b015b..af54b5cb3 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -43,12 +43,14 @@ typedef int (QEMUFileRateLimit)(void *opaque);
* the old rate otherwise
*/
typedef size_t (QEMUFileSetRateLimit)(void *opaque, size_t new_rate);
+typedef size_t (QEMUFileGetRateLimit)(void *opaque);
QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
QEMUFileGetBufferFunc *get_buffer,
QEMUFileCloseFunc *close,
QEMUFileRateLimit *rate_limit,
- QEMUFileSetRateLimit *set_rate_limit);
+ QEMUFileSetRateLimit *set_rate_limit,
+ QEMUFileGetRateLimit *get_rate_limit);
QEMUFile *qemu_fopen(const char *filename, const char *mode);
QEMUFile *qemu_fdopen(int fd, const char *mode);
QEMUFile *qemu_fopen_socket(int fd);
@@ -85,6 +87,7 @@ unsigned int qemu_get_be32(QEMUFile *f);
uint64_t qemu_get_be64(QEMUFile *f);
int qemu_file_rate_limit(QEMUFile *f);
size_t qemu_file_set_rate_limit(QEMUFile *f, size_t new_rate);
+size_t qemu_file_get_rate_limit(QEMUFile *f);
int qemu_file_has_error(QEMUFile *f);
void qemu_file_set_error(QEMUFile *f);
@@ -239,6 +242,7 @@ static inline void qemu_get_sbe64s(QEMUFile *f, int64_t *pv)
int64_t qemu_ftell(QEMUFile *f);
int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence);
+typedef void SaveSetParamsHandler(int blk_enable, int shared, void * opaque);
typedef void SaveStateHandler(QEMUFile *f, void *opaque);
typedef int SaveLiveStateHandler(QEMUFile *f, int stage, void *opaque);
typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
@@ -253,7 +257,8 @@ int register_savevm(const char *idstr,
int register_savevm_live(const char *idstr,
int instance_id,
int version_id,
- SaveLiveStateHandler *save_live_state,
+ SaveSetParamsHandler *set_params,
+ SaveLiveStateHandler *save_live_state,
SaveStateHandler *save_state,
LoadStateHandler *load_state,
void *opaque);
diff --git a/hw/lan9118.c b/hw/lan9118.c
new file mode 100644
index 000000000..6394f3a73
--- /dev/null
+++ b/hw/lan9118.c
@@ -0,0 +1,1093 @@
+/*
+ * SMSC LAN9118 Ethernet interface emulation
+ *
+ * Copyright (c) 2009 CodeSourcery, LLC.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the GNU GPL v2
+ */
+
+#include "sysbus.h"
+#include "net.h"
+#include "devices.h"
+/* For crc32 */
+#include <zlib.h>
+
+//#define DEBUG_LAN9118
+
+#ifdef DEBUG_LAN9118
+#define DPRINTF(fmt, ...) \
+do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+#define CSR_ID_REV 0x50
+#define CSR_IRQ_CFG 0x54
+#define CSR_INT_STS 0x58
+#define CSR_INT_EN 0x5c
+#define CSR_BYTE_TEST 0x64
+#define CSR_FIFO_INT 0x68
+#define CSR_RX_CFG 0x6c
+#define CSR_TX_CFG 0x70
+#define CSR_HW_CFG 0x74
+#define CSR_RX_DP_CTRL 0x78
+#define CSR_RX_FIFO_INF 0x7c
+#define CSR_TX_FIFO_INF 0x80
+#define CSR_PMT_CTRL 0x84
+#define CSR_GPIO_CFG 0x88
+#define CSR_GPT_CFG 0x8c /* TODO */
+#define CSR_GPT_CNT 0x90 /* TODO */
+#define CSR_WORD_SWAP 0x98
+#define CSR_FREE_RUN 0x9c
+#define CSR_RX_DROP 0xa0
+#define CSR_MAC_CSR_CMD 0xa4
+#define CSR_MAC_CSR_DATA 0xa8
+#define CSR_AFC_CFG 0xac
+#define CSR_E2P_CMD 0xb0
+#define CSR_E2P_DATA 0xb4
+
+/* IRQ_CFG */
+#define IRQ_EN 0x00000100
+#define IRQ_POL 0x00000010
+#define IRQ_TYPE 0x00000001
+
+/* INT_STS/INT_EN */
+#define SW_INT 0x80000000
+#define TXSTOP_INT 0x02000000
+#define RXSTOP_INT 0x01000000
+#define RXDFH_INT 0x00800000
+#define TX_IOC_INT 0x00200000
+#define RXD_INT 0x00100000
+#define GPT_INT 0x00080000
+#define PHY_INT 0x00040000
+#define PME_INT 0x00020000
+#define TXSO_INT 0x00010000
+#define RWT_INT 0x00008000
+#define RXE_INT 0x00004000
+#define TXE_INT 0x00002000
+#define TDFU_INT 0x00000800
+#define TDFO_INT 0x00000400
+#define TDFA_INT 0x00000200
+#define TSFF_INT 0x00000100
+#define TSFL_INT 0x00000080
+#define RXDF_INT 0x00000040
+#define RDFL_INT 0x00000020
+#define RSFF_INT 0x00000010
+#define RSFL_INT 0x00000008
+#define GPIO2_INT 0x00000004
+#define GPIO1_INT 0x00000002
+#define GPIO0_INT 0x00000001
+#define RESERVED_INT 0x7c001000
+
+#define MAC_CR 1
+#define MAC_ADDRH 2
+#define MAC_ADDRL 3
+#define MAC_HASHH 4
+#define MAC_HASHL 5
+#define MAC_MII_ACC 6
+#define MAC_MII_DATA 7
+#define MAC_FLOW 8
+#define MAC_VLAN1 9 /* TODO */
+#define MAC_VLAN2 10 /* TODO */
+#define MAC_WUFF 11 /* TODO */
+#define MAC_WUCSR 12 /* TODO */
+
+#define MAC_CR_RXALL 0x80000000
+#define MAC_CR_RCVOWN 0x00800000
+#define MAC_CR_LOOPBK 0x00200000
+#define MAC_CR_FDPX 0x00100000
+#define MAC_CR_MCPAS 0x00080000
+#define MAC_CR_PRMS 0x00040000
+#define MAC_CR_INVFILT 0x00020000
+#define MAC_CR_PASSBAD 0x00010000
+#define MAC_CR_HO 0x00008000
+#define MAC_CR_HPFILT 0x00002000
+#define MAC_CR_LCOLL 0x00001000
+#define MAC_CR_BCAST 0x00000800
+#define MAC_CR_DISRTY 0x00000400
+#define MAC_CR_PADSTR 0x00000100
+#define MAC_CR_BOLMT 0x000000c0
+#define MAC_CR_DFCHK 0x00000020
+#define MAC_CR_TXEN 0x00000008
+#define MAC_CR_RXEN 0x00000004
+#define MAC_CR_RESERVED 0x7f404213
+
+enum tx_state {
+ TX_IDLE,
+ TX_B,
+ TX_DATA
+};
+
+typedef struct {
+ enum tx_state state;
+ uint32_t cmd_a;
+ uint32_t cmd_b;
+ int buffer_size;
+ int offset;
+ int pad;
+ int fifo_used;
+ int len;
+ uint8_t data[2048];
+} LAN9118Packet;
+
+typedef struct {
+ SysBusDevice busdev;
+ VLANClientState *vc;
+ NICConf conf;
+ qemu_irq irq;
+ int mmio_index;
+
+ uint32_t irq_cfg;
+ uint32_t int_sts;
+ uint32_t int_en;
+ uint32_t fifo_int;
+ uint32_t rx_cfg;
+ uint32_t tx_cfg;
+ uint32_t hw_cfg;
+ uint32_t pmt_ctrl;
+ uint32_t gpio_cfg;
+ uint32_t word_swap;
+ uint32_t free_timer_start;
+ uint32_t mac_cmd;
+ uint32_t mac_data;
+ uint32_t afc_cfg;
+ uint32_t e2p_cmd;
+ uint32_t e2p_data;
+
+ uint32_t mac_cr;
+ uint32_t mac_hashh;
+ uint32_t mac_hashl;
+ uint32_t mac_mii_acc;
+ uint32_t mac_mii_data;
+ uint32_t mac_flow;
+
+ uint32_t phy_status;
+ uint32_t phy_control;
+ uint32_t phy_advertise;
+
+ int eeprom_writable;
+ uint8_t eeprom[8];
+
+ int tx_fifo_size;
+ LAN9118Packet *txp;
+ LAN9118Packet tx_packet;
+
+ int tx_status_fifo_used;
+ int tx_status_fifo_head;
+ uint32_t tx_status_fifo[512];
+
+ int rx_status_fifo_size;
+ int rx_status_fifo_used;
+ int rx_status_fifo_head;
+ uint32_t rx_status_fifo[896];
+ int rx_fifo_size;
+ int rx_fifo_used;
+ int rx_fifo_head;
+ uint32_t rx_fifo[3360];
+ int rx_packet_size_head;
+ int rx_packet_size_tail;
+ int rx_packet_size[1024];
+
+ int rxp_offset;
+ int rxp_size;
+ int rxp_pad;
+} lan9118_state;
+
+static void lan9118_update(lan9118_state *s)
+{
+ int level;
+
+ /* TODO: Implement FIFO level IRQs. */
+ level = (s->int_sts & s->int_en) != 0;
+ if ((s->irq_cfg & IRQ_EN) == 0) {
+ level = 0;
+ }
+ qemu_set_irq(s->irq, level);
+}
+
+static void lan9118_mac_changed(lan9118_state *s)
+{
+ qemu_format_nic_info_str(s->vc, s->conf.macaddr.a);
+}
+
+static void lan9118_reload_eeprom(lan9118_state *s)
+{
+ int i;
+ if (s->eeprom[0] != 0xa5) {
+ s->e2p_cmd &= ~0x10;
+ DPRINTF("MACADDR load failed\n");
+ return;
+ }
+ for (i = 0; i < 6; i++) {
+ s->conf.macaddr.a[i] = s->eeprom[i + 1];
+ }
+ s->e2p_cmd |= 0x10;
+ DPRINTF("MACADDR loaded from eeprom\n");
+ lan9118_mac_changed(s);
+}
+
+static void phy_update_link(lan9118_state *s)
+{
+ /* Autonegotiation status mirrors link status. */
+ if (s->vc->link_down) {
+ s->phy_status &= ~0x0024;
+ } else {
+ s->phy_status |= 0x0024;
+ }
+}
+
+static void lan9118_set_link(VLANClientState *vc)
+{
+ phy_update_link(vc->opaque);
+}
+
+static void phy_reset(lan9118_state *s)
+{
+ s->phy_status = 0x7805;
+ s->phy_control = 0x3000;
+ s->phy_advertise = 0x01e1;
+ phy_update_link(s);
+}
+
+static void lan9118_reset(DeviceState *d)
+{
+ lan9118_state *s = FROM_SYSBUS(lan9118_state, sysbus_from_qdev(d));
+
+ s->irq_cfg &= ~(IRQ_TYPE | IRQ_POL);
+ s->int_sts = 0;
+ s->int_en = 0;
+ s->fifo_int = 0x48000000;
+ s->rx_cfg = 0;
+ s->tx_cfg = 0;
+ s->hw_cfg = 0x00050000;
+ s->pmt_ctrl &= 0x45;
+ s->gpio_cfg = 0;
+ s->txp->fifo_used = 0;
+ s->txp->state = TX_IDLE;
+ s->txp->cmd_a = 0xffffffffu;
+ s->txp->cmd_b = 0xffffffffu;
+ s->txp->len = 0;
+ s->txp->fifo_used = 0;
+ s->tx_fifo_size = 4608;
+ s->tx_status_fifo_used = 0;
+ s->rx_status_fifo_size = 704;
+ s->rx_fifo_size = 2640;
+ s->rx_fifo_used = 0;
+ s->rx_status_fifo_size = 176;
+ s->rx_status_fifo_used = 0;
+ s->rxp_offset = 0;
+ s->rxp_size = 0;
+ s->rxp_pad = 0;
+ s->rx_packet_size_tail = s->rx_packet_size_head;
+ s->rx_packet_size[s->rx_packet_size_head] = 0;
+ s->mac_cmd = 0;
+ s->mac_data = 0;
+ s->afc_cfg = 0;
+ s->e2p_cmd = 0;
+ s->e2p_data = 0;
+ s->free_timer_start = qemu_get_clock(vm_clock) / 40;
+
+ s->mac_cr = MAC_CR_PRMS;
+ s->mac_hashh = 0;
+ s->mac_hashl = 0;
+ s->mac_mii_acc = 0;
+ s->mac_mii_data = 0;
+ s->mac_flow = 0;
+
+ phy_reset(s);
+
+ s->eeprom_writable = 0;
+ lan9118_reload_eeprom(s);
+}
+
+static int lan9118_can_receive(VLANClientState *vc)
+{
+ return 1;
+}
+
+static void rx_fifo_push(lan9118_state *s, uint32_t val)
+{
+ int fifo_pos;
+ fifo_pos = s->rx_fifo_head + s->rx_fifo_used;
+ if (fifo_pos >= s->rx_fifo_size)
+ fifo_pos -= s->rx_fifo_size;
+ s->rx_fifo[fifo_pos] = val;
+ s->rx_fifo_used++;
+}
+
+/* Return nonzero if the packet is accepted by the filter. */
+static int lan9118_filter(lan9118_state *s, const uint8_t *addr)
+{
+ int multicast;
+ uint32_t hash;
+
+ if (s->mac_cr & MAC_CR_PRMS) {
+ return 1;
+ }
+ if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff &&
+ addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) {
+ return (s->mac_cr & MAC_CR_BCAST) == 0;
+ }
+
+ multicast = addr[0] & 1;
+ if (multicast &&s->mac_cr & MAC_CR_MCPAS) {
+ return 1;
+ }
+ if (multicast ? (s->mac_cr & MAC_CR_HPFILT) == 0
+ : (s->mac_cr & MAC_CR_HO) == 0) {
+ /* Exact matching. */
+ hash = memcmp(addr, s->conf.macaddr.a, 6);
+ if (s->mac_cr & MAC_CR_INVFILT) {
+ return hash != 0;
+ } else {
+ return hash == 0;
+ }
+ } else {
+ /* Hash matching */
+ hash = (crc32(~0, addr, 6) >> 26);
+ if (hash & 0x20) {
+ return (s->mac_hashh >> (hash & 0x1f)) & 1;
+ } else {
+ return (s->mac_hashl >> (hash & 0x1f)) & 1;
+ }
+ }
+}
+
+static ssize_t lan9118_receive(VLANClientState *vc, const uint8_t *buf,
+ size_t size)
+{
+ lan9118_state *s = vc->opaque;
+ int fifo_len;
+ int offset;
+ int src_pos;
+ int n;
+ int filter;
+ uint32_t val;
+ uint32_t crc;
+ uint32_t status;
+
+ if ((s->mac_cr & MAC_CR_RXEN) == 0) {
+ return -1;
+ }
+
+ if (size >= 2048 || size < 14) {
+ return -1;
+ }
+
+ /* TODO: Implement FIFO overflow notification. */
+ if (s->rx_status_fifo_used == s->rx_status_fifo_size) {
+ return -1;
+ }
+
+ filter = lan9118_filter(s, buf);
+ if (!filter && (s->mac_cr & MAC_CR_RXALL) == 0) {
+ return size;
+ }
+
+ offset = (s->rx_cfg >> 8) & 0x1f;
+ n = offset & 3;
+ fifo_len = (size + n + 3) >> 2;
+ /* Add a word for the CRC. */
+ fifo_len++;
+ if (s->rx_fifo_size - s->rx_fifo_used < fifo_len) {
+ return -1;
+ }
+
+ DPRINTF("Got packet len:%d fifo:%d filter:%s\n",
+ (int)size, fifo_len, filter ? "pass" : "fail");
+ val = 0;
+ crc = bswap32(crc32(~0, buf, size));
+ for (src_pos = 0; src_pos < size; src_pos++) {
+ val = (val >> 8) | ((uint32_t)buf[src_pos] << 24);
+ n++;
+ if (n == 4) {
+ n = 0;
+ rx_fifo_push(s, val);
+ val = 0;
+ }
+ }
+ if (n) {
+ val >>= ((4 - n) * 8);
+ val |= crc << (n * 8);
+ rx_fifo_push(s, val);
+ val = crc >> ((4 - n) * 8);
+ rx_fifo_push(s, val);
+ } else {
+ rx_fifo_push(s, crc);
+ }
+ n = s->rx_status_fifo_head + s->rx_status_fifo_used;
+ if (n >= s->rx_status_fifo_size) {
+ n -= s->rx_status_fifo_size;
+ }
+ s->rx_packet_size[s->rx_packet_size_tail] = fifo_len;
+ s->rx_packet_size_tail = (s->rx_packet_size_tail + 1023) & 1023;
+ s->rx_status_fifo_used++;
+
+ status = (size + 4) << 16;
+ if (buf[0] == 0xff && buf[1] == 0xff && buf[2] == 0xff &&
+ buf[3] == 0xff && buf[4] == 0xff && buf[5] == 0xff) {
+ status |= 0x00002000;
+ } else if (buf[0] & 1) {
+ status |= 0x00000400;
+ }
+ if (!filter) {
+ status |= 0x40000000;
+ }
+ s->rx_status_fifo[n] = status;
+
+ if (s->rx_status_fifo_used > (s->fifo_int & 0xff)) {
+ s->int_sts |= RSFL_INT;
+ }
+ lan9118_update(s);
+
+ return size;
+}
+
+static uint32_t rx_fifo_pop(lan9118_state *s)
+{
+ int n;
+ uint32_t val;
+
+ if (s->rxp_size == 0 && s->rxp_pad == 0) {
+ s->rxp_size = s->rx_packet_size[s->rx_packet_size_head];
+ s->rx_packet_size[s->rx_packet_size_head] = 0;
+ if (s->rxp_size != 0) {
+ s->rx_packet_size_head = (s->rx_packet_size_head + 1023) & 1023;
+ s->rxp_offset = (s->rx_cfg >> 10) & 7;
+ n = s->rxp_offset + s->rxp_size;
+ switch (s->rx_cfg >> 30) {
+ case 1:
+ n = (-n) & 3;
+ break;
+ case 2:
+ n = (-n) & 7;
+ break;
+ default:
+ n = 0;
+ break;
+ }
+ s->rxp_pad = n;
+ DPRINTF("Pop packet size:%d offset:%d pad: %d\n",
+ s->rxp_size, s->rxp_offset, s->rxp_pad);
+ }
+ }
+ if (s->rxp_offset > 0) {
+ s->rxp_offset--;
+ val = 0;
+ } else if (s->rxp_size > 0) {
+ s->rxp_size--;
+ val = s->rx_fifo[s->rx_fifo_head++];
+ if (s->rx_fifo_head >= s->rx_fifo_size) {
+ s->rx_fifo_head -= s->rx_fifo_size;
+ }
+ s->rx_fifo_used--;
+ } else if (s->rxp_pad > 0) {
+ s->rxp_pad--;
+ val = 0;
+ } else {
+ DPRINTF("RX underflow\n");
+ s->int_sts |= RXE_INT;
+ val = 0;
+ }
+ lan9118_update(s);
+ return val;
+}
+
+static void do_tx_packet(lan9118_state *s)
+{
+ int n;
+ uint32_t status;
+
+ /* FIXME: Honor TX disable, and allow queueing of packets. */
+ if (s->phy_control & 0x4000) {
+ /* This assumes the receive routine doesn't touch the VLANClient. */
+ lan9118_receive(s->vc, s->txp->data, s->txp->len);
+ } else {
+ qemu_send_packet(s->vc, s->txp->data, s->txp->len);
+ }
+ s->txp->fifo_used = 0;
+
+ if (s->tx_status_fifo_used == 512) {
+ /* Status FIFO full */
+ return;
+ }
+ /* Add entry to status FIFO. */
+ status = s->txp->cmd_b & 0xffff0000u;
+ DPRINTF("Sent packet tag:%04x len %d\n", status >> 16, s->txp->len);
+ n = (s->tx_status_fifo_head + s->tx_status_fifo_used) & 511;
+ s->tx_status_fifo[n] = status;
+ s->tx_status_fifo_used++;
+ if (s->tx_status_fifo_used == 512) {
+ s->int_sts |= TSFF_INT;
+ /* TODO: Stop transmission. */
+ }
+}
+
+static uint32_t rx_status_fifo_pop(lan9118_state *s)
+{
+ uint32_t val;
+
+ val = s->rx_status_fifo[s->rx_status_fifo_head];
+ if (s->rx_status_fifo_used != 0) {
+ s->rx_status_fifo_used--;
+ s->rx_status_fifo_head++;
+ if (s->rx_status_fifo_head >= s->rx_status_fifo_size) {
+ s->rx_status_fifo_head -= s->rx_status_fifo_size;
+ }
+ /* ??? What value should be returned when the FIFO is empty? */
+ DPRINTF("RX status pop 0x%08x\n", val);
+ }
+ return val;
+}
+
+static uint32_t tx_status_fifo_pop(lan9118_state *s)
+{
+ uint32_t val;
+
+ val = s->tx_status_fifo[s->tx_status_fifo_head];
+ if (s->tx_status_fifo_used != 0) {
+ s->tx_status_fifo_used--;
+ s->tx_status_fifo_head = (s->tx_status_fifo_head + 1) & 511;
+ /* ??? What value should be returned when the FIFO is empty? */
+ }
+ return val;
+}
+
+static void tx_fifo_push(lan9118_state *s, uint32_t val)
+{
+ int n;
+
+ if (s->txp->fifo_used == s->tx_fifo_size) {
+ s->int_sts |= TDFO_INT;
+ return;
+ }
+ switch (s->txp->state) {
+ case TX_IDLE:
+ s->txp->cmd_a = val & 0x831f37ff;
+ s->txp->fifo_used++;
+ s->txp->state = TX_B;
+ break;
+ case TX_B:
+ if (s->txp->cmd_a & 0x2000) {
+ /* First segment */
+ s->txp->cmd_b = val;
+ s->txp->fifo_used++;
+ s->txp->buffer_size = s->txp->cmd_a & 0x7ff;
+ s->txp->offset = (s->txp->cmd_a >> 16) & 0x1f;
+ /* End alignment does not include command words. */
+ n = (s->txp->buffer_size + s->txp->offset + 3) >> 2;
+ switch ((n >> 24) & 3) {
+ case 1:
+ n = (-n) & 3;
+ break;
+ case 2:
+ n = (-n) & 7;
+ break;
+ default:
+ n = 0;
+ }
+ s->txp->pad = n;
+ s->txp->len = 0;
+ }
+ DPRINTF("Block len:%d offset:%d pad:%d cmd %08x\n",
+ s->txp->buffer_size, s->txp->offset, s->txp->pad,
+ s->txp->cmd_a);
+ s->txp->state = TX_DATA;
+ break;
+ case TX_DATA:
+ if (s->txp->offset >= 4) {
+ s->txp->offset -= 4;
+ break;
+ }
+ if (s->txp->buffer_size <= 0 && s->txp->pad != 0) {
+ s->txp->pad--;
+ } else {
+ n = 4;
+ while (s->txp->offset) {
+ val >>= 8;
+ n--;
+ s->txp->offset--;
+ }
+ /* Documentation is somewhat unclear on the ordering of bytes
+ in FIFO words. Empirical results show it to be little-endian.
+ */
+ /* TODO: FIFO overflow checking. */
+ while (n--) {
+ s->txp->data[s->txp->len] = val & 0xff;
+ s->txp->len++;
+ val >>= 8;
+ s->txp->buffer_size--;
+ }
+ s->txp->fifo_used++;
+ }
+ if (s->txp->buffer_size <= 0 && s->txp->pad == 0) {
+ if (s->txp->cmd_a & 0x1000) {
+ do_tx_packet(s);
+ }
+ if (s->txp->cmd_a & 0x80000000) {
+ s->int_sts |= TX_IOC_INT;
+ }
+ s->txp->state = TX_IDLE;
+ }
+ break;
+ }
+}
+
+static uint32_t do_phy_read(lan9118_state *s, int reg)
+{
+ switch (reg) {
+ case 0: /* Basic Control */
+ return s->phy_control;
+ case 1: /* Basic Status */
+ return s->phy_status;
+ case 2: /* ID1 */
+ return 0x0007;
+ case 3: /* ID2 */
+ return 0xc0d1;
+ case 4: /* Auto-neg advertisment */
+ return s->phy_advertise;
+ case 5: /* Auto-neg Link Partner Ability */
+ return 0x0f71;
+ case 6: /* Auto-neg Expansion */
+ return 1;
+ /* TODO 17, 18, 27, 29, 30, 31 */
+ default:
+ BADF("PHY read reg %d\n", reg);
+ return 0;
+ }
+}
+
+static void do_phy_write(lan9118_state *s, int reg, uint32_t val)
+{
+ switch (reg) {
+ case 0: /* Basic Control */
+ if (val & 0x8000) {
+ phy_reset(s);
+ break;
+ }
+ s->phy_control = val & 0x7980;
+ /* Complete autonegotiation imediately. */
+ if (val & 0x1000) {
+ s->phy_status |= 0x0020;
+ }
+ break;
+ case 4: /* Auto-neg advertisment */
+ s->phy_advertise = (val & 0x2d7f) | 0x80;
+ break;
+ /* TODO 17, 18, 27, 29, 30, 31 */
+ default:
+ BADF("PHY write reg %d = 0x%04x\n", reg, val);
+ }
+}
+
+static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
+{
+ switch (reg) {
+ case MAC_CR:
+ if ((s->mac_cr & MAC_CR_RXEN) != 0 && (val & MAC_CR_RXEN) == 0) {
+ s->int_sts |= RXSTOP_INT;
+ }
+ s->mac_cr = val & ~MAC_CR_RESERVED;
+ DPRINTF("MAC_CR: %08x\n", val);
+ break;
+ case MAC_ADDRH:
+ s->conf.macaddr.a[4] = val & 0xff;
+ s->conf.macaddr.a[5] = (val >> 8) & 0xff;
+ lan9118_mac_changed(s);
+ break;
+ case MAC_ADDRL:
+ s->conf.macaddr.a[0] = val & 0xff;
+ s->conf.macaddr.a[1] = (val >> 8) & 0xff;
+ s->conf.macaddr.a[2] = (val >> 16) & 0xff;
+ s->conf.macaddr.a[3] = (val >> 24) & 0xff;
+ lan9118_mac_changed(s);
+ break;
+ case MAC_HASHH:
+ s->mac_hashh = val;
+ break;
+ case MAC_HASHL:
+ s->mac_hashl = val;
+ break;
+ case MAC_MII_ACC:
+ s->mac_mii_acc = val & 0xffc2;
+ if (val & 2) {
+ DPRINTF("PHY write %d = 0x%04x\n",
+ (val >> 6) & 0x1f, s->mac_mii_data);
+ do_phy_write(s, (val >> 6) & 0x1f, s->mac_mii_data);
+ } else {
+ s->mac_mii_data = do_phy_read(s, (val >> 6) & 0x1f);
+ DPRINTF("PHY read %d = 0x%04x\n",
+ (val >> 6) & 0x1f, s->mac_mii_data);
+ }
+ break;
+ case MAC_MII_DATA:
+ s->mac_mii_data = val & 0xffff;
+ break;
+ case MAC_FLOW:
+ s->mac_flow = val & 0xffff0000;
+ break;
+ default:
+ hw_error("lan9118: Unimplemented MAC register write: %d = 0x%x\n",
+ s->mac_cmd & 0xf, val);
+ }
+}
+
+static uint32_t do_mac_read(lan9118_state *s, int reg)
+{
+ switch (reg) {
+ case MAC_CR:
+ return s->mac_cr;
+ case MAC_ADDRH:
+ return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8);
+ case MAC_ADDRL:
+ return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8)
+ | (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[3] << 24);
+ case MAC_HASHH:
+ return s->mac_hashh;
+ break;
+ case MAC_HASHL:
+ return s->mac_hashl;
+ break;
+ case MAC_MII_ACC:
+ return s->mac_mii_acc;
+ case MAC_MII_DATA:
+ return s->mac_mii_data;
+ case MAC_FLOW:
+ return s->mac_flow;
+ default:
+ hw_error("lan9118: Unimplemented MAC register read: %d\n",
+ s->mac_cmd & 0xf);
+ }
+}
+
+static void lan9118_eeprom_cmd(lan9118_state *s, int cmd, int addr)
+{
+ s->e2p_cmd = (s->e2p_cmd & 0x10) | (cmd << 28) | addr;
+ switch (cmd) {
+ case 0:
+ s->e2p_data = s->eeprom[addr];
+ DPRINTF("EEPROM Read %d = 0x%02x\n", addr, s->e2p_data);
+ break;
+ case 1:
+ s->eeprom_writable = 0;
+ DPRINTF("EEPROM Write Disable\n");
+ break;
+ case 2: /* EWEN */
+ s->eeprom_writable = 1;
+ DPRINTF("EEPROM Write Enable\n");
+ break;
+ case 3: /* WRITE */
+ if (s->eeprom_writable) {
+ s->eeprom[addr] &= s->e2p_data;
+ DPRINTF("EEPROM Write %d = 0x%02x\n", addr, s->e2p_data);
+ } else {
+ DPRINTF("EEPROM Write %d (ignored)\n", addr);
+ }
+ break;
+ case 4: /* WRAL */
+ if (s->eeprom_writable) {
+ for (addr = 0; addr < 128; addr++) {
+ s->eeprom[addr] &= s->e2p_data;
+ }
+ DPRINTF("EEPROM Write All 0x%02x\n", s->e2p_data);
+ } else {
+ DPRINTF("EEPROM Write All (ignored)\n");
+ }
+ case 5: /* ERASE */
+ if (s->eeprom_writable) {
+ s->eeprom[addr] = 0xff;
+ DPRINTF("EEPROM Erase %d\n", addr);
+ } else {
+ DPRINTF("EEPROM Erase %d (ignored)\n", addr);
+ }
+ break;
+ case 6: /* ERAL */
+ if (s->eeprom_writable) {
+ memset(s->eeprom, 0xff, 128);
+ DPRINTF("EEPROM Erase All\n");
+ } else {
+ DPRINTF("EEPROM Erase All (ignored)\n");
+ }
+ break;
+ case 7: /* RELOAD */
+ lan9118_reload_eeprom(s);
+ break;
+ }
+}
+
+static void lan9118_writel(void *opaque, target_phys_addr_t offset,
+ uint32_t val)
+{
+ lan9118_state *s = (lan9118_state *)opaque;
+ offset &= 0xff;
+
+ //DPRINTF("Write reg 0x%02x = 0x%08x\n", (int)offset, val);
+ if (offset >= 0x20 && offset < 0x40) {
+ /* TX FIFO */
+ tx_fifo_push(s, val);
+ return;
+ }
+ switch (offset) {
+ case CSR_IRQ_CFG:
+ /* TODO: Implement interrupt deassertion intervals. */
+ s->irq_cfg = (val & IRQ_EN);
+ break;
+ case CSR_INT_STS:
+ s->int_sts &= ~val;
+ break;
+ case CSR_INT_EN:
+ s->int_en = val & ~RESERVED_INT;
+ s->int_sts |= val & SW_INT;
+ break;
+ case CSR_FIFO_INT:
+ DPRINTF("FIFO INT levels %08x\n", val);
+ s->fifo_int = val;
+ break;
+ case CSR_RX_CFG:
+ if (val & 0x8000) {
+ /* RX_DUMP */
+ s->rx_fifo_used = 0;
+ s->rx_status_fifo_used = 0;
+ s->rx_packet_size_tail = s->rx_packet_size_head;
+ s->rx_packet_size[s->rx_packet_size_head] = 0;
+ }
+ s->rx_cfg = val & 0xcfff1ff0;
+ break;
+ case CSR_TX_CFG:
+ if (val & 0x8000) {
+ s->tx_status_fifo_used = 0;
+ }
+ if (val & 0x4000) {
+ s->txp->state = TX_IDLE;
+ s->txp->fifo_used = 0;
+ s->txp->cmd_a = 0xffffffff;
+ }
+ s->tx_cfg = val & 6;
+ break;
+ case CSR_HW_CFG:
+ if (val & 1) {
+ /* SRST */
+ lan9118_reset(&s->busdev.qdev);
+ } else {
+ s->hw_cfg = val & 0x003f300;
+ }
+ break;
+ case CSR_RX_DP_CTRL:
+ if (val & 0x80000000) {
+ /* Skip forward to next packet. */
+ s->rxp_pad = 0;
+ s->rxp_offset = 0;
+ if (s->rxp_size == 0) {
+ /* Pop a word to start the next packet. */
+ rx_fifo_pop(s);
+ s->rxp_pad = 0;
+ s->rxp_offset = 0;
+ }
+ s->rx_fifo_head += s->rxp_size;
+ if (s->rx_fifo_head >= s->rx_fifo_size) {
+ s->rx_fifo_head -= s->rx_fifo_size;
+ }
+ }
+ break;
+ case CSR_PMT_CTRL:
+ if (val & 0x400) {
+ phy_reset(s);
+ }
+ s->pmt_ctrl &= ~0x34e;
+ s->pmt_ctrl |= (val & 0x34e);
+ break;
+ case CSR_GPIO_CFG:
+ /* Probably just enabling LEDs. */
+ s->gpio_cfg = val & 0x7777071f;
+ break;
+ case CSR_WORD_SWAP:
+ /* Ignored because we're in 32-bit mode. */
+ s->word_swap = val;
+ break;
+ case CSR_MAC_CSR_CMD:
+ s->mac_cmd = val & 0x4000000f;
+ if (val & 0x80000000) {
+ if (val & 0x40000000) {
+ s->mac_data = do_mac_read(s, val & 0xf);
+ DPRINTF("MAC read %d = 0x%08x\n", val & 0xf, s->mac_data);
+ } else {
+ DPRINTF("MAC write %d = 0x%08x\n", val & 0xf, s->mac_data);
+ do_mac_write(s, val & 0xf, s->mac_data);
+ }
+ }
+ break;
+ case CSR_MAC_CSR_DATA:
+ s->mac_data = val;
+ break;
+ case CSR_AFC_CFG:
+ s->afc_cfg = val & 0x00ffffff;
+ break;
+ case CSR_E2P_CMD:
+ lan9118_eeprom_cmd(s, (val >> 28) & 7, val & 0xff);
+ break;
+ case CSR_E2P_DATA:
+ s->e2p_data = val & 0xff;
+ break;
+
+ default:
+ hw_error("lan9118_write: Bad reg 0x%x = %x\n", (int)offset, val);
+ break;
+ }
+ lan9118_update(s);
+}
+
+static uint32_t lan9118_readl(void *opaque, target_phys_addr_t offset)
+{
+ lan9118_state *s = (lan9118_state *)opaque;
+
+ //DPRINTF("Read reg 0x%02x\n", (int)offset);
+ if (offset < 0x20) {
+ /* RX FIFO */
+ return rx_fifo_pop(s);
+ }
+ switch (offset) {
+ case 0x40:
+ return rx_status_fifo_pop(s);
+ case 0x44:
+ return s->rx_status_fifo[s->tx_status_fifo_head];
+ case 0x48:
+ return tx_status_fifo_pop(s);
+ case 0x4c:
+ return s->tx_status_fifo[s->tx_status_fifo_head];
+ case CSR_ID_REV:
+ return 0x01180001;
+ case CSR_IRQ_CFG:
+ return s->irq_cfg;
+ case CSR_INT_STS:
+ return s->int_sts;
+ case CSR_INT_EN:
+ return s->int_en;
+ case CSR_BYTE_TEST:
+ return 0x87654321;
+ case CSR_FIFO_INT:
+ return s->fifo_int;
+ case CSR_RX_CFG:
+ return s->rx_cfg;
+ case CSR_TX_CFG:
+ return s->tx_cfg;
+ case CSR_HW_CFG:
+ return s->hw_cfg | 0x4;
+ case CSR_RX_DP_CTRL:
+ return 0;
+ case CSR_RX_FIFO_INF:
+ return (s->rx_status_fifo_used << 16) | (s->rx_fifo_used << 2);
+ case CSR_TX_FIFO_INF:
+ return (s->tx_status_fifo_used << 16)
+ | (s->tx_fifo_size - s->txp->fifo_used);
+ case CSR_PMT_CTRL:
+ return s->pmt_ctrl;
+ case CSR_GPIO_CFG:
+ return s->gpio_cfg;
+ case CSR_WORD_SWAP:
+ return s->word_swap;
+ case CSR_FREE_RUN:
+ return (qemu_get_clock(vm_clock) / 40) - s->free_timer_start;
+ case CSR_RX_DROP:
+ /* TODO: Implement dropped frames counter. */
+ return 0;
+ case CSR_MAC_CSR_CMD:
+ return s->mac_cmd;
+ case CSR_MAC_CSR_DATA:
+ return s->mac_data;
+ case CSR_AFC_CFG:
+ return s->afc_cfg;
+ case CSR_E2P_CMD:
+ return s->e2p_cmd;
+ case CSR_E2P_DATA:
+ return s->e2p_data;
+ }
+ hw_error("lan9118_read: Bad reg 0x%x\n", (int)offset);
+ return 0;
+}
+
+static CPUReadMemoryFunc * const lan9118_readfn[] = {
+ lan9118_readl,
+ lan9118_readl,
+ lan9118_readl
+};
+
+static CPUWriteMemoryFunc * const lan9118_writefn[] = {
+ lan9118_writel,
+ lan9118_writel,
+ lan9118_writel
+};
+
+static void lan9118_cleanup(VLANClientState *vc)
+{
+ lan9118_state *s = vc->opaque;
+
+ s->vc = NULL;
+}
+
+static int lan9118_init1(SysBusDevice *dev)
+{
+ lan9118_state *s = FROM_SYSBUS(lan9118_state, dev);
+ int i;
+
+ s->mmio_index = cpu_register_io_memory(lan9118_readfn,
+ lan9118_writefn, s);
+ sysbus_init_mmio(dev, 0x100, s->mmio_index);
+ sysbus_init_irq(dev, &s->irq);
+ qemu_macaddr_default_if_unset(&s->conf.macaddr);
+
+ s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC,
+ s->conf.vlan, s->conf.peer,
+ dev->qdev.info->name, dev->qdev.id,
+ lan9118_can_receive, lan9118_receive, NULL,
+ NULL, lan9118_cleanup, s);
+ s->vc->link_status_changed = lan9118_set_link;
+ qemu_format_nic_info_str(s->vc, s->conf.macaddr.a);
+ s->eeprom[0] = 0xa5;
+ for (i = 0; i < 6; i++) {
+ s->eeprom[i + 1] = s->conf.macaddr.a[i];
+ }
+ s->pmt_ctrl = 1;
+ s->txp = &s->tx_packet;
+
+ /* ??? Save/restore. */
+ return 0;
+}
+
+static SysBusDeviceInfo lan9118_info = {
+ .init = lan9118_init1,
+ .qdev.name = "lan9118",
+ .qdev.size = sizeof(lan9118_state),
+ .qdev.reset = lan9118_reset,
+ .qdev.props = (Property[]) {
+ DEFINE_NIC_PROPERTIES(lan9118_state, conf),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void lan9118_register_devices(void)
+{
+ sysbus_register_withprop(&lan9118_info);
+}
+
+/* Legacy helper function. Should go away when machine config files are
+ implemented. */
+void lan9118_init(NICInfo *nd, uint32_t base, qemu_irq irq)
+{
+ DeviceState *dev;
+ SysBusDevice *s;
+
+ qemu_check_nic_model(nd, "lan9118");
+ dev = qdev_create(NULL, "lan9118");
+ qdev_set_nic_properties(dev, nd);
+ qdev_init_nofail(dev);
+ s = sysbus_from_qdev(dev);
+ sysbus_mmio_map(s, 0, base);
+ sysbus_connect_irq(s, 0, irq);
+}
+
+device_init(lan9118_register_devices)
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index a9b2c74d9..76884570f 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -230,7 +230,7 @@ static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
/* SWITCH Register */
case 0x00200:
val = 0x00000000; /* All switches closed */
- break;
+ break;
/* STATUS Register */
case 0x00208:
@@ -297,7 +297,7 @@ static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
default:
#if 0
printf ("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n",
- addr);
+ addr);
#endif
break;
}
@@ -384,7 +384,7 @@ static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
default:
#if 0
printf ("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n",
- addr);
+ addr);
#endif
break;
}
@@ -655,41 +655,37 @@ static void write_bootloader (CPUState *env, uint8_t *base,
}
-static void prom_set(int index, const char *string, ...)
+static void prom_set(uint32_t* prom_buf, int index, const char *string, ...)
{
- char buf[ENVP_ENTRY_SIZE];
- target_phys_addr_t p;
va_list ap;
int32_t table_addr;
if (index >= ENVP_NB_ENTRIES)
return;
- p = ENVP_ADDR + VIRT_TO_PHYS_ADDEND + index * 4;
-
if (string == NULL) {
- stl_phys(p, 0);
+ prom_buf[index] = 0;
return;
}
- table_addr = ENVP_ADDR + sizeof(int32_t) * ENVP_NB_ENTRIES
- + index * ENVP_ENTRY_SIZE;
- stl_phys(p, table_addr);
+ table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
+ prom_buf[index] = tswap32(ENVP_ADDR + table_addr);
va_start(ap, string);
- vsnprintf(buf, ENVP_ENTRY_SIZE, string, ap);
+ vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap);
va_end(ap);
- pstrcpy_targphys("prom", table_addr + VIRT_TO_PHYS_ADDEND, ENVP_ENTRY_SIZE, buf);
}
/* Kernel */
static int64_t load_kernel (void)
{
int64_t kernel_entry, kernel_low, kernel_high;
- int index = 0;
long initrd_size;
ram_addr_t initrd_offset;
int big_endian;
+ uint32_t *prom_buf;
+ long prom_size;
+ int prom_index = 0;
#ifdef TARGET_WORDS_BIGENDIAN
big_endian = 1;
@@ -729,21 +725,27 @@ static int64_t load_kernel (void)
}
}
- /* Store command line. */
- prom_set(index++, loaderparams.kernel_filename);
- if (initrd_size > 0)
- prom_set(index++, "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
+ /* Setup prom parameters. */
+ prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
+ prom_buf = qemu_malloc(prom_size);
+
+ prom_set(prom_buf, prom_index++, loaderparams.kernel_filename);
+ if (initrd_size > 0) {
+ prom_set(prom_buf, prom_index++, "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
PHYS_TO_VIRT(initrd_offset), initrd_size,
loaderparams.kernel_cmdline);
- else
- prom_set(index++, loaderparams.kernel_cmdline);
-
- /* Setup minimum environment variables */
- prom_set(index++, "memsize");
- prom_set(index++, "%i", loaderparams.ram_size);
- prom_set(index++, "modetty0");
- prom_set(index++, "38400n8r");
- prom_set(index++, NULL);
+ } else {
+ prom_set(prom_buf, prom_index++, loaderparams.kernel_cmdline);
+ }
+
+ prom_set(prom_buf, prom_index++, "memsize");
+ prom_set(prom_buf, prom_index++, "%i", loaderparams.ram_size);
+ prom_set(prom_buf, prom_index++, "modetty0");
+ prom_set(prom_buf, prom_index++, "38400n8r");
+ prom_set(prom_buf, prom_index++, NULL);
+
+ rom_add_blob_fixed("prom", prom_buf, prom_size,
+ ENVP_ADDR + VIRT_TO_PHYS_ADDEND);
return kernel_entry;
}
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index 497885bb3..b69d7c3e9 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -78,9 +78,9 @@ typedef struct ResetData {
static int64_t load_kernel(void)
{
int64_t entry, kernel_low, kernel_high;
- long kernel_size, initrd_size;
+ long kernel_size, initrd_size, params_size;
ram_addr_t initrd_offset;
- int ret;
+ uint32_t *params_buf;
int big_endian;
#ifdef TARGET_WORDS_BIGENDIAN
@@ -125,20 +125,23 @@ static int64_t load_kernel(void)
}
/* Store command line. */
+ params_size = 264;
+ params_buf = qemu_malloc(params_size);
+
+ params_buf[0] = tswap32(ram_size);
+ params_buf[1] = tswap32(0x12345678);
+
if (initrd_size > 0) {
- char buf[64];
- ret = snprintf(buf, 64, "rd_start=0x" TARGET_FMT_lx " rd_size=%li ",
- PHYS_TO_VIRT((uint32_t)initrd_offset),
- initrd_size);
- cpu_physical_memory_write((16 << 20) - 256, (void *)buf, 64);
+ snprintf((char *)params_buf + 8, 256, "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
+ PHYS_TO_VIRT((uint32_t)initrd_offset),
+ initrd_size, loaderparams.kernel_cmdline);
} else {
- ret = 0;
+ snprintf((char *)params_buf + 8, 256, "%s", loaderparams.kernel_cmdline);
}
- pstrcpy_targphys("cmdline", (16 << 20) - 256 + ret, 256,
- loaderparams.kernel_cmdline);
- stl_phys((16 << 20) - 260, 0x12345678);
- stl_phys((16 << 20) - 264, ram_size);
+ rom_add_blob_fixed("params", params_buf, params_size,
+ (16 << 20) - 264);
+
return entry;
}
diff --git a/hw/openpic.c b/hw/openpic.c
index 68af9c1de..42db59daa 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -1202,8 +1202,6 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
if (bus) {
opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t),
-1, NULL, NULL);
- if (opp == NULL)
- return NULL;
pci_conf = opp->pci_dev.config;
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_OPENPIC2);
diff --git a/hw/pci.c b/hw/pci.c
index 22a844199..f4fdc1e8c 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -552,10 +552,11 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
if (!bus->devices[devfn])
goto found;
}
- return NULL;
+ hw_error("PCI: no devfn available for %s, all in use\n", name);
found: ;
} else if (bus->devices[devfn]) {
- return NULL;
+ hw_error("PCI: devfn %d not available for %s, in use by %s\n", devfn,
+ name, bus->devices[devfn]->name);
}
pci_dev->bus = bus;
pci_dev->devfn = devfn;
@@ -1389,7 +1390,6 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
pci_dev = do_pci_register_device(pci_dev, bus, base->name, devfn,
info->config_read, info->config_write,
info->header_type);
- assert(pci_dev);
rc = info->init(pci_dev);
if (rc != 0)
return rc;
diff --git a/hw/realview.c b/hw/realview.c
index 0e57b5085..50386f8e0 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -16,12 +16,11 @@
#include "sysemu.h"
#include "boards.h"
+#define SMP_BOOT_ADDR 0xe0000000
/* Board init. */
static struct arm_boot_info realview_binfo = {
- .loader_start = 0x0,
- .smp_loader_start = 0x80000000,
- .board_id = 0x33b,
+ .smp_loader_start = SMP_BOOT_ADDR,
};
static void secondary_cpu_reset(void *opaque)
@@ -32,12 +31,13 @@ static void secondary_cpu_reset(void *opaque)
/* Set entry point for secondary CPUs. This assumes we're using
the init code from arm_boot.c. Real hardware resets all CPUs
the same. */
- env->regs[15] = 0x80000000;
+ env->regs[15] = SMP_BOOT_ADDR;
}
enum realview_board_type {
BOARD_EB,
- BOARD_EB_MPCORE
+ BOARD_EB_MPCORE,
+ BOARD_PB_A8
};
static void realview_init(ram_addr_t ram_size,
@@ -55,10 +55,13 @@ static void realview_init(ram_addr_t ram_size,
PCIBus *pci_bus;
NICInfo *nd;
int n;
- int done_smc = 0;
+ int done_nic = 0;
qemu_irq cpu_irq[4];
int is_mpcore = (board_type == BOARD_EB_MPCORE);
+ int is_pb = (board_type == BOARD_PB_A8);
uint32_t proc_id = 0;
+ uint32_t sys_id;
+ ram_addr_t low_ram_size;
for (n = 0; n < smp_cpus; n++) {
env = cpu_init(cpu_model);
@@ -83,11 +86,22 @@ static void realview_init(ram_addr_t ram_size,
}
ram_offset = qemu_ram_alloc(ram_size);
+ low_ram_size = ram_size;
+ if (low_ram_size > 0x10000000)
+ low_ram_size = 0x10000000;
/* ??? RAM should repeat to fill physical memory space. */
/* SDRAM at address zero. */
- cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+ cpu_register_physical_memory(0, low_ram_size, ram_offset | IO_MEM_RAM);
+ if (is_pb) {
+ /* And again at a high address. */
+ cpu_register_physical_memory(0x70000000, ram_size,
+ ram_offset | IO_MEM_RAM);
+ } else {
+ ram_size = low_ram_size;
+ }
- arm_sysctl_init(0x10000000, 0xc1400400, proc_id);
+ sys_id = is_pb ? 0x01780500 : 0xc1400400;
+ arm_sysctl_init(0x10000000, sys_id, proc_id);
if (is_mpcore) {
dev = qdev_create(NULL, "realview_mpcore");
@@ -98,7 +112,9 @@ static void realview_init(ram_addr_t ram_size,
sysbus_connect_irq(busdev, n, cpu_irq[n]);
}
} else {
- dev = sysbus_create_simple("realview_gic", 0x10040000, cpu_irq[0]);
+ uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000;
+ /* For now just create the nIRQ GIC, and ignore the others. */
+ dev = sysbus_create_simple("realview_gic", gic_addr, cpu_irq[0]);
}
for (n = 0; n < 64; n++) {
pic[n] = qdev_get_gpio_in(dev, n);
@@ -124,23 +140,30 @@ static void realview_init(ram_addr_t ram_size,
sysbus_create_simple("pl031", 0x10017000, pic[10]);
- dev = sysbus_create_varargs("realview_pci", 0x60000000,
- pic[48], pic[49], pic[50], pic[51], NULL);
- pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
- if (usb_enabled) {
- usb_ohci_init_pci(pci_bus, -1);
- }
- n = drive_get_max_bus(IF_SCSI);
- while (n >= 0) {
- pci_create_simple(pci_bus, -1, "lsi53c895a");
- n--;
+ if (!is_pb) {
+ dev = sysbus_create_varargs("realview_pci", 0x60000000,
+ pic[48], pic[49], pic[50], pic[51], NULL);
+ pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
+ if (usb_enabled) {
+ usb_ohci_init_pci(pci_bus, -1);
+ }
+ n = drive_get_max_bus(IF_SCSI);
+ while (n >= 0) {
+ pci_create_simple(pci_bus, -1, "lsi53c895a");
+ n--;
+ }
}
for(n = 0; n < nb_nics; n++) {
nd = &nd_table[n];
- if ((!nd->model && !done_smc) || strcmp(nd->model, "smc91c111") == 0) {
- smc91c111_init(nd, 0x4e000000, pic[28]);
- done_smc = 1;
+ if ((!nd->model && !done_nic)
+ || strcmp(nd->model, is_pb ? "lan9118" : "smc91c111") == 0) {
+ if (is_pb) {
+ lan9118_init(nd, 0x4e000000, pic[28]);
+ } else {
+ smc91c111_init(nd, 0x4e000000, pic[28]);
+ }
+ done_nic = 1;
} else {
pci_nic_init_nofail(nd, "rtl8139", NULL);
}
@@ -155,7 +178,7 @@ static void realview_init(ram_addr_t ram_size,
/* 0x10005000 MCI. */
/* 0x10006000 KMI0. */
/* 0x10007000 KMI1. */
- /* 0x10008000 Character LCD. */
+ /* 0x10008000 Character LCD. (EB) */
/* 0x10009000 UART0. */
/* 0x1000a000 UART1. */
/* 0x1000b000 UART2. */
@@ -169,17 +192,21 @@ static void realview_init(ram_addr_t ram_size,
/* 0x10013000 GPIO 0. */
/* 0x10014000 GPIO 1. */
/* 0x10015000 GPIO 2. */
- /* 0x10016000 Reserved. */
+ /* 0x10002000 Two-Wire Serial Bus - DVI. (PB) */
/* 0x10017000 RTC. */
/* 0x10018000 DMC. */
/* 0x10019000 PCI controller config. */
/* 0x10020000 CLCD. */
/* 0x10030000 DMA Controller. */
- /* 0x10040000 GIC1. */
- /* 0x10050000 GIC2. */
- /* 0x10060000 GIC3. */
- /* 0x10070000 GIC4. */
+ /* 0x10040000 GIC1. (EB) */
+ /* 0x10050000 GIC2. (EB) */
+ /* 0x10060000 GIC3. (EB) */
+ /* 0x10070000 GIC4. (EB) */
/* 0x10080000 SMC. */
+ /* 0x1e000000 GIC1. (PB) */
+ /* 0x1e001000 GIC2. (PB) */
+ /* 0x1e002000 GIC3. (PB) */
+ /* 0x1e003000 GIC4. (PB) */
/* 0x40000000 NOR flash. */
/* 0x44000000 DoC flash. */
/* 0x48000000 SRAM. */
@@ -203,13 +230,16 @@ static void realview_init(ram_addr_t ram_size,
BootROM happens to be in ROM/flash or in memory that isn't clobbered
until after Linux boots the secondary CPUs. */
ram_offset = qemu_ram_alloc(0x1000);
- cpu_register_physical_memory(0x80000000, 0x1000, ram_offset | IO_MEM_RAM);
+ cpu_register_physical_memory(SMP_BOOT_ADDR, 0x1000,
+ ram_offset | IO_MEM_RAM);
realview_binfo.ram_size = ram_size;
realview_binfo.kernel_filename = kernel_filename;
realview_binfo.kernel_cmdline = kernel_cmdline;
realview_binfo.initrd_filename = initrd_filename;
realview_binfo.nb_cpus = smp_cpus;
+ realview_binfo.board_id = is_pb ? 0x769 : 0x33b;
+ realview_binfo.loader_start = is_pb ? 0x70000000 : 0;
arm_load_kernel(first_cpu, &realview_binfo);
}
@@ -237,6 +267,18 @@ static void realview_eb_mpcore_init(ram_addr_t ram_size,
initrd_filename, cpu_model, BOARD_EB_MPCORE);
}
+static void realview_pb_a8_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ if (!cpu_model) {
+ cpu_model = "cortex-a8";
+ }
+ realview_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+ initrd_filename, cpu_model, BOARD_PB_A8);
+}
+
static QEMUMachine realview_eb_machine = {
.name = "realview-eb",
.desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)",
@@ -252,10 +294,18 @@ static QEMUMachine realview_eb_mpcore_machine = {
.max_cpus = 4,
};
+static QEMUMachine realview_pb_a8_machine = {
+ .name = "realview-pb-a8",
+ .desc = "ARM RealView Platform Baseboard for Cortex-A8",
+ .init = realview_pb_a8_init,
+ .use_scsi = 1,
+};
+
static void realview_machine_init(void)
{
qemu_register_machine(&realview_eb_machine);
qemu_register_machine(&realview_eb_mpcore_machine);
+ qemu_register_machine(&realview_pb_a8_machine);
}
machine_init(realview_machine_init);
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index f089cbd07..fe13e7b3e 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -156,7 +156,9 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
pci_unin_set_irq, pci_unin_map_irq,
pic, 11 << 3, 4);
+#if 0
pci_create_simple(d->host_state.bus, 11 << 3, "Uni-north main");
+#endif
sysbus_mmio_map(s, 0, 0xf2800000);
sysbus_mmio_map(s, 1, 0xf2c00000);
@@ -168,12 +170,22 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
#endif
/* Uninorth AGP bus */
- pci_create_simple(d->host_state.bus, 13 << 3, "Uni-north AGP");
+ pci_create_simple(d->host_state.bus, 11 << 3, "Uni-north AGP");
+ dev = qdev_create(NULL, "Uni-north AGP");
+ qdev_init_nofail(dev);
+ s = sysbus_from_qdev(dev);
+ sysbus_mmio_map(s, 0, 0xf0800000);
+ sysbus_mmio_map(s, 1, 0xf0c00000);
/* Uninorth internal bus */
#if 0
/* XXX: not needed for now */
pci_create_simple(d->host_state.bus, 14 << 3, "Uni-north internal");
+ dev = qdev_create(NULL, "Uni-north internal");
+ qdev_init_nofail(dev);
+ s = sysbus_from_qdev(dev);
+ sysbus_mmio_map(s, 0, 0xf4800000);
+ sysbus_mmio_map(s, 1, 0xf4c00000);
#endif
return d->host_state.bus;
diff --git a/kvm-all.c b/kvm-all.c
index f331dbefc..8de370a58 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -150,6 +150,7 @@ static void kvm_reset_vcpu(void *opaque)
{
CPUState *env = opaque;
+ kvm_arch_reset_vcpu(env);
if (kvm_arch_put_registers(env)) {
fprintf(stderr, "Fatal: kvm vcpu reset failed\n");
abort();
@@ -203,6 +204,7 @@ int kvm_init_vcpu(CPUState *env)
ret = kvm_arch_init_vcpu(env);
if (ret == 0) {
qemu_register_reset(kvm_reset_vcpu, env);
+ kvm_arch_reset_vcpu(env);
ret = kvm_arch_put_registers(env);
}
err:
diff --git a/kvm.h b/kvm.h
index 35c8e85f0..7174a6bf9 100644
--- a/kvm.h
+++ b/kvm.h
@@ -93,6 +93,8 @@ int kvm_arch_init(KVMState *s, int smp_cpus);
int kvm_arch_init_vcpu(CPUState *env);
+void kvm_arch_reset_vcpu(CPUState *env);
+
struct kvm_guest_debug;
struct kvm_debug_exit_arch;
diff --git a/migration-exec.c b/migration-exec.c
index b45c83385..c83066959 100644
--- a/migration-exec.c
+++ b/migration-exec.c
@@ -53,8 +53,10 @@ static int exec_close(FdMigrationState *s)
}
MigrationState *exec_start_outgoing_migration(const char *command,
- int64_t bandwidth_limit,
- int detach)
+ int64_t bandwidth_limit,
+ int detach,
+ int blk,
+ int inc)
{
FdMigrationState *s;
FILE *f;
@@ -84,6 +86,9 @@ MigrationState *exec_start_outgoing_migration(const char *command,
s->mig_state.get_status = migrate_fd_get_status;
s->mig_state.release = migrate_fd_release;
+ s->mig_state.blk = blk;
+ s->mig_state.shared = inc;
+
s->state = MIG_STATE_ACTIVE;
s->mon_resume = NULL;
s->bandwidth_limit = bandwidth_limit;
diff --git a/migration-fd.c b/migration-fd.c
index 15b44158f..587f9d8e8 100644
--- a/migration-fd.c
+++ b/migration-fd.c
@@ -54,7 +54,9 @@ static int fd_close(FdMigrationState *s)
MigrationState *fd_start_outgoing_migration(Monitor *mon,
const char *fdname,
int64_t bandwidth_limit,
- int detach)
+ int detach,
+ int blk,
+ int inc)
{
FdMigrationState *s;
@@ -78,6 +80,9 @@ MigrationState *fd_start_outgoing_migration(Monitor *mon,
s->mig_state.get_status = migrate_fd_get_status;
s->mig_state.release = migrate_fd_release;
+ s->mig_state.blk = blk;
+ s->mig_state.shared = inc;
+
s->state = MIG_STATE_ACTIVE;
s->mon_resume = NULL;
s->bandwidth_limit = bandwidth_limit;
diff --git a/migration-tcp.c b/migration-tcp.c
index 9ed92b442..efa7c74c6 100644
--- a/migration-tcp.c
+++ b/migration-tcp.c
@@ -78,7 +78,9 @@ static void tcp_wait_for_connect(void *opaque)
MigrationState *tcp_start_outgoing_migration(const char *host_port,
int64_t bandwidth_limit,
- int detach)
+ int detach,
+ int blk,
+ int inc)
{
struct sockaddr_in addr;
FdMigrationState *s;
@@ -96,6 +98,9 @@ MigrationState *tcp_start_outgoing_migration(const char *host_port,
s->mig_state.get_status = migrate_fd_get_status;
s->mig_state.release = migrate_fd_release;
+ s->mig_state.blk = blk;
+ s->mig_state.shared = inc;
+
s->state = MIG_STATE_ACTIVE;
s->mon_resume = NULL;
s->bandwidth_limit = bandwidth_limit;
diff --git a/migration-unix.c b/migration-unix.c
index a26587a3e..25cd6d3d2 100644
--- a/migration-unix.c
+++ b/migration-unix.c
@@ -77,7 +77,9 @@ static void unix_wait_for_connect(void *opaque)
MigrationState *unix_start_outgoing_migration(const char *path,
int64_t bandwidth_limit,
- int detach)
+ int detach,
+ int blk,
+ int inc)
{
FdMigrationState *s;
struct sockaddr_un addr;
@@ -95,6 +97,9 @@ MigrationState *unix_start_outgoing_migration(const char *path,
s->mig_state.get_status = migrate_fd_get_status;
s->mig_state.release = migrate_fd_release;
+ s->mig_state.blk = blk;
+ s->mig_state.shared = inc;
+
s->state = MIG_STATE_ACTIVE;
s->mon_resume = NULL;
s->bandwidth_limit = bandwidth_limit;
diff --git a/migration.c b/migration.c
index b20beb730..3ae0be86c 100644
--- a/migration.c
+++ b/migration.c
@@ -58,16 +58,24 @@ void do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
const char *p;
int detach = qdict_get_int(qdict, "detach");
const char *uri = qdict_get_str(qdict, "uri");
-
+
if (strstart(uri, "tcp:", &p))
- s = tcp_start_outgoing_migration(p, max_throttle, detach);
+ s = tcp_start_outgoing_migration(p, max_throttle, detach,
+ (int)qdict_get_int(qdict, "blk"),
+ (int)qdict_get_int(qdict, "inc"));
#if !defined(WIN32)
else if (strstart(uri, "exec:", &p))
- s = exec_start_outgoing_migration(p, max_throttle, detach);
+ s = exec_start_outgoing_migration(p, max_throttle, detach,
+ (int)qdict_get_int(qdict, "blk"),
+ (int)qdict_get_int(qdict, "inc"));
else if (strstart(uri, "unix:", &p))
- s = unix_start_outgoing_migration(p, max_throttle, detach);
+ s = unix_start_outgoing_migration(p, max_throttle, detach,
+ (int)qdict_get_int(qdict, "blk"),
+ (int)qdict_get_int(qdict, "inc"));
else if (strstart(uri, "fd:", &p))
- s = fd_start_outgoing_migration(mon, p, max_throttle, detach);
+ s = fd_start_outgoing_migration(mon, p, max_throttle, detach,
+ (int)qdict_get_int(qdict, "blk"),
+ (int)qdict_get_int(qdict, "inc"));
#endif
else
monitor_printf(mon, "unknown migration protocol: %s\n", uri);
@@ -251,13 +259,14 @@ void migrate_fd_connect(FdMigrationState *s)
migrate_fd_close);
dprintf("beginning savevm\n");
- ret = qemu_savevm_state_begin(s->file);
+ ret = qemu_savevm_state_begin(s->file, s->mig_state.blk,
+ s->mig_state.shared);
if (ret < 0) {
dprintf("failed, %d\n", ret);
migrate_fd_error(s);
return;
}
-
+
migrate_fd_put_ready(s);
}
diff --git a/migration.h b/migration.h
index 2d28b8f39..56adf05e6 100644
--- a/migration.h
+++ b/migration.h
@@ -30,6 +30,8 @@ struct MigrationState
void (*cancel)(MigrationState *s);
int (*get_status)(MigrationState *s);
void (*release)(MigrationState *s);
+ int blk;
+ int shared;
};
typedef struct FdMigrationState FdMigrationState;
@@ -65,27 +67,35 @@ void do_info_migrate(Monitor *mon);
int exec_start_incoming_migration(const char *host_port);
MigrationState *exec_start_outgoing_migration(const char *host_port,
- int64_t bandwidth_limit,
- int detach);
+ int64_t bandwidth_limit,
+ int detach,
+ int blk,
+ int inc);
int tcp_start_incoming_migration(const char *host_port);
MigrationState *tcp_start_outgoing_migration(const char *host_port,
int64_t bandwidth_limit,
- int detach);
+ int detach,
+ int blk,
+ int inc);
int unix_start_incoming_migration(const char *path);
MigrationState *unix_start_outgoing_migration(const char *path,
int64_t bandwidth_limit,
- int detach);
+ int detach,
+ int blk,
+ int inc);
int fd_start_incoming_migration(const char *path);
MigrationState *fd_start_outgoing_migration(Monitor *mon,
const char *fdname,
int64_t bandwidth_limit,
- int detach);
+ int detach,
+ int blk,
+ int inc);
void migrate_fd_monitor_suspend(FdMigrationState *s);
diff --git a/monitor.c b/monitor.c
index 58fb78edf..e161f7d17 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2940,6 +2940,18 @@ static int default_fmt_size = 4;
#define MAX_ARGS 16
+static int is_valid_option(const char *c, const char *typestr)
+{
+ char option[3];
+
+ option[0] = '-';
+ option[1] = *c;
+ option[2] = '\0';
+
+ typestr = strstr(typestr, option);
+ return (typestr != NULL);
+}
+
static const mon_cmd_t *monitor_parse_command(Monitor *mon,
const char *cmdline,
QDict *qdict)
@@ -3132,7 +3144,8 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
break;
case '-':
{
- int has_option;
+ const char *tmp = p;
+ int has_option, skip_key = 0;
/* option */
c = *typestr++;
@@ -3143,13 +3156,22 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
has_option = 0;
if (*p == '-') {
p++;
- if (*p != c) {
- monitor_printf(mon, "%s: unsupported option -%c\n",
- cmdname, *p);
- goto fail;
+ if(c != *p) {
+ if(!is_valid_option(p, typestr)) {
+
+ monitor_printf(mon, "%s: unsupported option -%c\n",
+ cmdname, *p);
+ goto fail;
+ } else {
+ skip_key = 1;
+ }
+ }
+ if(skip_key) {
+ p = tmp;
+ } else {
+ p++;
+ has_option = 1;
}
- p++;
- has_option = 1;
}
qdict_put(qdict, key, qint_from_int(has_option));
}
diff --git a/qemu-char.c b/qemu-char.c
index 40bd7e8a6..5a81e8f5f 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -97,6 +97,8 @@
#include "qemu_socket.h"
+#define READ_BUF_LEN 4096
+
/***********************************************************/
/* character device */
@@ -110,7 +112,7 @@ static void qemu_chr_event(CharDriverState *s, int event)
s->chr_event(s->handler_opaque, event);
}
-static void qemu_chr_reset_bh(void *opaque)
+static void qemu_chr_generic_open_bh(void *opaque)
{
CharDriverState *s = opaque;
qemu_chr_event(s, CHR_EVENT_OPENED);
@@ -118,23 +120,14 @@ static void qemu_chr_reset_bh(void *opaque)
s->bh = NULL;
}
-void qemu_chr_reset(CharDriverState *s)
+void qemu_chr_generic_open(CharDriverState *s)
{
if (s->bh == NULL) {
- s->bh = qemu_bh_new(qemu_chr_reset_bh, s);
+ s->bh = qemu_bh_new(qemu_chr_generic_open_bh, s);
qemu_bh_schedule(s->bh);
}
}
-void qemu_chr_initial_reset(void)
-{
- CharDriverState *chr;
-
- QTAILQ_FOREACH(chr, &chardevs, next) {
- qemu_chr_reset(chr);
- }
-}
-
int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
{
return s->chr_write(s, buf, len);
@@ -172,7 +165,7 @@ void qemu_chr_accept_input(CharDriverState *s)
void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
{
- char buf[4096];
+ char buf[READ_BUF_LEN];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
@@ -555,7 +548,7 @@ static void fd_chr_read(void *opaque)
CharDriverState *chr = opaque;
FDCharDriver *s = chr->opaque;
int size, len;
- uint8_t buf[1024];
+ uint8_t buf[READ_BUF_LEN];
len = sizeof(buf);
if (len > s->max_size)
@@ -617,7 +610,7 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
chr->chr_update_read_handler = fd_chr_update_read_handler;
chr->chr_close = fd_chr_close;
- qemu_chr_reset(chr);
+ qemu_chr_generic_open(chr);
return chr;
}
@@ -866,7 +859,7 @@ static void pty_chr_read(void *opaque)
CharDriverState *chr = opaque;
PtyCharDriver *s = chr->opaque;
int size, len;
- uint8_t buf[1024];
+ uint8_t buf[READ_BUF_LEN];
len = sizeof(buf);
if (len > s->read_bytes)
@@ -917,7 +910,7 @@ static void pty_chr_state(CharDriverState *chr, int connected)
qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
} else {
if (!s->connected)
- qemu_chr_reset(chr);
+ qemu_chr_generic_open(chr);
s->connected = 1;
}
}
@@ -1191,7 +1184,7 @@ static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
return NULL;
}
chr->chr_ioctl = tty_serial_ioctl;
- qemu_chr_reset(chr);
+ qemu_chr_generic_open(chr);
return chr;
}
#else /* ! __linux__ && ! __sun__ */
@@ -1337,7 +1330,7 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
chr->chr_close = pp_close;
chr->opaque = drv;
- qemu_chr_reset(chr);
+ qemu_chr_generic_open(chr);
return chr;
}
@@ -1554,7 +1547,7 @@ static void win_chr_readfile(CharDriverState *chr)
{
WinCharState *s = chr->opaque;
int ret, err;
- uint8_t buf[1024];
+ uint8_t buf[READ_BUF_LEN];
DWORD size;
ZeroMemory(&s->orecv, sizeof(s->orecv));
@@ -1618,7 +1611,7 @@ static CharDriverState *qemu_chr_open_win(QemuOpts *opts)
free(chr);
return NULL;
}
- qemu_chr_reset(chr);
+ qemu_chr_generic_open(chr);
return chr;
}
@@ -1718,7 +1711,7 @@ static CharDriverState *qemu_chr_open_win_pipe(QemuOpts *opts)
free(chr);
return NULL;
}
- qemu_chr_reset(chr);
+ qemu_chr_generic_open(chr);
return chr;
}
@@ -1732,7 +1725,7 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
s->hcom = fd_out;
chr->opaque = s;
chr->chr_write = win_chr_write;
- qemu_chr_reset(chr);
+ qemu_chr_generic_open(chr);
return chr;
}
@@ -1760,7 +1753,7 @@ static CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts)
typedef struct {
int fd;
- uint8_t buf[1024];
+ uint8_t buf[READ_BUF_LEN];
int bufcnt;
int bufptr;
int max_size;
@@ -2020,7 +2013,7 @@ static void tcp_chr_read(void *opaque)
{
CharDriverState *chr = opaque;
TCPCharDriver *s = chr->opaque;
- uint8_t buf[1024];
+ uint8_t buf[READ_BUF_LEN];
int len, size;
if (!s->connected || s->max_size <= 0)
@@ -2059,7 +2052,7 @@ static void tcp_chr_connect(void *opaque)
s->connected = 1;
qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
tcp_chr_read, NULL, chr);
- qemu_chr_reset(chr);
+ qemu_chr_generic_open(chr);
}
#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;
diff --git a/qemu-char.h b/qemu-char.h
index 05fe15d8c..9957db1f5 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -82,8 +82,7 @@ void qemu_chr_add_handlers(CharDriverState *s,
IOEventHandler *fd_event,
void *opaque);
int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg);
-void qemu_chr_reset(CharDriverState *s);
-void qemu_chr_initial_reset(void);
+void qemu_chr_generic_open(CharDriverState *s);
int qemu_chr_can_read(CharDriverState *s);
void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len);
int qemu_chr_get_msgfd(CharDriverState *s);
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 38dbda7b2..eca43715b 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -80,7 +80,7 @@ For system emulation, the following hardware targets are supported:
@item MIPS Magnum (64-bit MIPS processor)
@item ARM Integrator/CP (ARM)
@item ARM Versatile baseboard (ARM)
-@item ARM RealView Emulation baseboard (ARM)
+@item ARM RealView Emulation/Platform baseboard (ARM)
@item Spitz, Akita, Borzoi, Terrier and Tosa PDAs (PXA270 processor)
@item Luminary Micro LM3S811EVB (ARM Cortex-M3)
@item Luminary Micro LM3S6965EVB (ARM Cortex-M3)
@@ -1659,7 +1659,8 @@ LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices.
PL181 MultiMedia Card Interface with SD card.
@end itemize
-The ARM RealView Emulation baseboard is emulated with the following devices:
+The ARM RealView Emulation/Platform baseboard is emulated with the following
+devices:
@itemize @minus
@item
@@ -1669,7 +1670,7 @@ ARM AMBA Generic/Distributed Interrupt Controller
@item
Four PL011 UARTs
@item
-SMC 91c111 Ethernet adapter
+SMC 91c111 or SMSC LAN9118 Ethernet adapter
@item
PL110 LCD controller
@item
diff --git a/qemu-kvm-x86.c b/qemu-kvm-x86.c
index 9df0d8339..71a6319e0 100644
--- a/qemu-kvm-x86.c
+++ b/qemu-kvm-x86.c
@@ -946,7 +946,11 @@ void kvm_arch_load_regs(CPUState *env)
fpu.mxcsr = env->mxcsr;
kvm_set_fpu(env, &fpu);
- memcpy(sregs.interrupt_bitmap, env->interrupt_bitmap, sizeof(sregs.interrupt_bitmap));
+ memset(sregs.interrupt_bitmap, 0, sizeof(sregs.interrupt_bitmap));
+ if (env->interrupt_injected >= 0) {
+ sregs.interrupt_bitmap[env->interrupt_injected / 64] |=
+ (uint64_t)1 << (env->interrupt_injected % 64);
+ }
if ((env->eflags & VM_MASK)) {
set_v8086_seg(&sregs.cs, &env->segs[R_CS]);
@@ -1066,7 +1070,7 @@ void kvm_arch_save_regs(CPUState *env)
struct kvm_sregs sregs;
struct kvm_msr_entry msrs[100];
uint32_t hflags;
- uint32_t i, n, rc;
+ uint32_t i, n, rc, bit;
kvm_get_regs(env, &regs);
@@ -1104,7 +1108,16 @@ void kvm_arch_save_regs(CPUState *env)
kvm_get_sregs(env, &sregs);
- memcpy(env->interrupt_bitmap, sregs.interrupt_bitmap, sizeof(env->interrupt_bitmap));
+ /* There can only be one pending IRQ set in the bitmap at a time, so try
+ to find it and save its number instead (-1 for none). */
+ env->interrupt_injected = -1;
+ for (i = 0; i < ARRAY_SIZE(sregs.interrupt_bitmap); i++) {
+ if (sregs.interrupt_bitmap[i]) {
+ bit = ctz64(sregs.interrupt_bitmap[i]);
+ env->interrupt_injected = i * 64 + bit;
+ break;
+ }
+ }
get_seg(&env->segs[R_CS], &sregs.cs);
get_seg(&env->segs[R_DS], &sregs.ds);
diff --git a/qemu-monitor.hx b/qemu-monitor.hx
index 6e0d94ba7..2b14802d7 100644
--- a/qemu-monitor.hx
+++ b/qemu-monitor.hx
@@ -724,16 +724,23 @@ ETEXI
{
.name = "migrate",
- .args_type = "detach:-d,uri:s",
- .params = "[-d] uri",
- .help = "migrate to URI (using -d to not wait for completion)",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_migrate,
+ .args_type = "detach:-d,blk:-b,inc:-i,uri:s",
+ .params = "[-d] [-b] [-i] uri",
+ .help = "migrate to URI (using -d to not wait for completion)"
+ "\n\t\t\t -b for migration without shared storage with"
+ " full copy of disk\n\t\t\t -i for migration without "
+ "shared storage with incremental copy of disk "
+ "(base image shared between src and destination)",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = do_migrate,
},
+
STEXI
-@item migrate [-d] @var{uri}
+@item migrate [-d] [-b] [-i] @var{uri}
Migrate to @var{uri} (using -d to not wait for completion).
+ -b for migration with full copy of disk
+ -i for migration with incremental copy of disk (base image is shared)
ETEXI
{
diff --git a/rules.mak b/rules.mak
index f8e5b04e5..77a801b49 100644
--- a/rules.mak
+++ b/rules.mak
@@ -44,5 +44,5 @@ cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \
@test -f $@ || cp $< $@
%.h-timestamp: %.mak
- $(call quiet-command, $(SRC_PATH)/create_config < $< > $@, " GEN $*.h")
+ $(call quiet-command, sh $(SRC_PATH)/create_config < $< > $@, " GEN $*.h")
@cmp $@ $*.h >/dev/null 2>&1 || cp $@ $*.h
diff --git a/savevm.c b/savevm.c
index d2e3ba1b2..8a63921e0 100644
--- a/savevm.c
+++ b/savevm.c
@@ -169,6 +169,7 @@ struct QEMUFile {
QEMUFileCloseFunc *close;
QEMUFileRateLimit *rate_limit;
QEMUFileSetRateLimit *set_rate_limit;
+ QEMUFileGetRateLimit *get_rate_limit;
void *opaque;
int is_write;
@@ -264,9 +265,11 @@ QEMUFile *qemu_popen(FILE *stdio_file, const char *mode)
s->stdio_file = stdio_file;
if(mode[0] == 'r') {
- s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_pclose, NULL, NULL);
+ s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_pclose,
+ NULL, NULL, NULL);
} else {
- s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_pclose, NULL, NULL);
+ s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_pclose,
+ NULL, NULL, NULL);
}
return s->file;
}
@@ -311,9 +314,11 @@ QEMUFile *qemu_fdopen(int fd, const char *mode)
goto fail;
if(mode[0] == 'r') {
- s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_fclose, NULL, NULL);
+ s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_fclose,
+ NULL, NULL, NULL);
} else {
- s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_fclose, NULL, NULL);
+ s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_fclose,
+ NULL, NULL, NULL);
}
return s->file;
@@ -327,7 +332,8 @@ QEMUFile *qemu_fopen_socket(int fd)
QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));
s->fd = fd;
- s->file = qemu_fopen_ops(s, NULL, socket_get_buffer, socket_close, NULL, NULL);
+ s->file = qemu_fopen_ops(s, NULL, socket_get_buffer, socket_close,
+ NULL, NULL, NULL);
return s->file;
}
@@ -363,11 +369,13 @@ QEMUFile *qemu_fopen(const char *filename, const char *mode)
s->stdio_file = fopen(filename, mode);
if (!s->stdio_file)
goto fail;
-
+
if(mode[0] == 'w') {
- s->file = qemu_fopen_ops(s, file_put_buffer, NULL, stdio_fclose, NULL, NULL);
+ s->file = qemu_fopen_ops(s, file_put_buffer, NULL, stdio_fclose,
+ NULL, NULL, NULL);
} else {
- s->file = qemu_fopen_ops(s, NULL, file_get_buffer, stdio_fclose, NULL, NULL);
+ s->file = qemu_fopen_ops(s, NULL, file_get_buffer, stdio_fclose,
+ NULL, NULL, NULL);
}
return s->file;
fail:
@@ -395,15 +403,17 @@ static int bdrv_fclose(void *opaque)
static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
{
if (is_writable)
- return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose, NULL, NULL);
- return qemu_fopen_ops(bs, NULL, block_get_buffer, bdrv_fclose, NULL, NULL);
+ return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose,
+ NULL, NULL, NULL);
+ return qemu_fopen_ops(bs, NULL, block_get_buffer, bdrv_fclose, NULL, NULL, NULL);
}
QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
QEMUFileGetBufferFunc *get_buffer,
QEMUFileCloseFunc *close,
QEMUFileRateLimit *rate_limit,
- QEMUFileSetRateLimit *set_rate_limit)
+ QEMUFileSetRateLimit *set_rate_limit,
+ QEMUFileGetRateLimit *get_rate_limit)
{
QEMUFile *f;
@@ -415,6 +425,7 @@ QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
f->close = close;
f->rate_limit = rate_limit;
f->set_rate_limit = set_rate_limit;
+ f->get_rate_limit = get_rate_limit;
f->is_write = 0;
return f;
@@ -592,6 +603,14 @@ int qemu_file_rate_limit(QEMUFile *f)
return 0;
}
+size_t qemu_file_get_rate_limit(QEMUFile *f)
+{
+ if (f->get_rate_limit)
+ return f->get_rate_limit(f->opaque);
+
+ return 0;
+}
+
size_t qemu_file_set_rate_limit(QEMUFile *f, size_t new_rate)
{
/* any failed or completed migration keeps its state to allow probing of
@@ -987,6 +1006,7 @@ typedef struct SaveStateEntry {
int instance_id;
int version_id;
int section_id;
+ SaveSetParamsHandler *set_params;
SaveLiveStateHandler *save_live_state;
SaveStateHandler *save_state;
LoadStateHandler *load_state;
@@ -994,6 +1014,7 @@ typedef struct SaveStateEntry {
void *opaque;
} SaveStateEntry;
+
static QTAILQ_HEAD(savevm_handlers, SaveStateEntry) savevm_handlers =
QTAILQ_HEAD_INITIALIZER(savevm_handlers);
static int global_section_id;
@@ -1019,6 +1040,7 @@ static int calculate_new_instance_id(const char *idstr)
int register_savevm_live(const char *idstr,
int instance_id,
int version_id,
+ SaveSetParamsHandler *set_params,
SaveLiveStateHandler *save_live_state,
SaveStateHandler *save_state,
LoadStateHandler *load_state,
@@ -1026,10 +1048,11 @@ int register_savevm_live(const char *idstr,
{
SaveStateEntry *se;
- se = qemu_malloc(sizeof(SaveStateEntry));
+ se = qemu_mallocz(sizeof(SaveStateEntry));
pstrcpy(se->idstr, sizeof(se->idstr), idstr);
se->version_id = version_id;
se->section_id = global_section_id++;
+ se->set_params = set_params;
se->save_live_state = save_live_state;
se->save_state = save_state;
se->load_state = load_state;
@@ -1054,7 +1077,7 @@ int register_savevm(const char *idstr,
void *opaque)
{
return register_savevm_live(idstr, instance_id, version_id,
- NULL, save_state, load_state, opaque);
+ NULL, NULL, save_state, load_state, opaque);
}
void unregister_savevm(const char *idstr, void *opaque)
@@ -1074,7 +1097,7 @@ int vmstate_register(int instance_id, const VMStateDescription *vmsd,
{
SaveStateEntry *se;
- se = qemu_malloc(sizeof(SaveStateEntry));
+ se = qemu_mallocz(sizeof(SaveStateEntry));
pstrcpy(se->idstr, sizeof(se->idstr), vmsd->name);
se->version_id = vmsd->version_id;
se->section_id = global_section_id++;
@@ -1236,10 +1259,17 @@ static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
#define QEMU_VM_SECTION_END 0x03
#define QEMU_VM_SECTION_FULL 0x04
-int qemu_savevm_state_begin(QEMUFile *f)
+int qemu_savevm_state_begin(QEMUFile *f, int blk_enable, int shared)
{
SaveStateEntry *se;
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+ if(se->set_params == NULL) {
+ continue;
+ }
+ se->set_params(blk_enable, shared, se->opaque);
+ }
+
qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
qemu_put_be32(f, QEMU_VM_FILE_VERSION);
@@ -1349,7 +1379,7 @@ int qemu_savevm_state(QEMUFile *f)
bdrv_flush_all();
- ret = qemu_savevm_state_begin(f);
+ ret = qemu_savevm_state_begin(f, 0, 0);
if (ret < 0)
goto out;
diff --git a/sh4-dis.c b/sh4-dis.c
index a502a6188..41fd8667b 100644
--- a/sh4-dis.c
+++ b/sh4-dis.c
@@ -2065,7 +2065,7 @@ print_insn_sh (bfd_vma memaddr, struct disassemble_info *info)
}
if ((*info->symbol_at_address_func) (val, info))
{
- fprintf_fn (stream, "\t! 0x");
+ fprintf_fn (stream, "\t! ");
(*info->print_address_func) (val, info);
}
else
diff --git a/sysemu.h b/sysemu.h
index 74a288c2e..4f662260d 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -62,7 +62,7 @@ void qemu_announce_self(void);
void main_loop_wait(int timeout);
-int qemu_savevm_state_begin(QEMUFile *f);
+int qemu_savevm_state_begin(QEMUFile *f, int blk_enable, int shared);
int qemu_savevm_state_iterate(QEMUFile *f);
int qemu_savevm_state_complete(QEMUFile *f);
int qemu_savevm_state(QEMUFile *f);
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 4605fd280..a638e702b 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -709,8 +709,8 @@ typedef struct CPUX86State {
MTRRVar mtrr_var[8];
/* For KVM */
- uint64_t interrupt_bitmap[256 / 64];
uint32_t mp_state;
+ int32_t interrupt_injected;
/* in order to simplify APIC support, we leave this pointer to the
user */
@@ -727,7 +727,6 @@ typedef struct CPUX86State {
uint16_t fpus_vmstate;
uint16_t fptag_vmstate;
uint16_t fpregs_format_vmstate;
- int32_t pending_irq_vmstate;
} CPUX86State;
CPUX86State *cpu_x86_init(const char *cpu_model);
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 83c83297b..552866563 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -23,6 +23,7 @@
#include "kvm.h"
#include "cpu.h"
#include "gdbstub.h"
+#include "host-utils.h"
#ifdef KVM_UPSTREAM
//#define DEBUG_KVM
@@ -222,6 +223,11 @@ int kvm_arch_init_vcpu(CPUState *env)
return kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data);
}
+void kvm_arch_reset_vcpu(CPUState *env)
+{
+ env->interrupt_injected = -1;
+}
+
static int kvm_has_msr_star(CPUState *env)
{
static int has_msr_star;
@@ -408,9 +414,11 @@ static int kvm_put_sregs(CPUState *env)
{
struct kvm_sregs sregs;
- memcpy(sregs.interrupt_bitmap,
- env->interrupt_bitmap,
- sizeof(sregs.interrupt_bitmap));
+ memset(sregs.interrupt_bitmap, 0, sizeof(sregs.interrupt_bitmap));
+ if (env->interrupt_injected >= 0) {
+ sregs.interrupt_bitmap[env->interrupt_injected / 64] |=
+ (uint64_t)1 << (env->interrupt_injected % 64);
+ }
if ((env->eflags & VM_MASK)) {
set_v8086_seg(&sregs.cs, &env->segs[R_CS]);
@@ -518,15 +526,22 @@ static int kvm_get_sregs(CPUState *env)
{
struct kvm_sregs sregs;
uint32_t hflags;
- int ret;
+ int bit, i, ret;
ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
if (ret < 0)
return ret;
- memcpy(env->interrupt_bitmap,
- sregs.interrupt_bitmap,
- sizeof(sregs.interrupt_bitmap));
+ /* There can only be one pending IRQ set in the bitmap at a time, so try
+ to find it and save its number instead (-1 for none). */
+ env->interrupt_injected = -1;
+ for (i = 0; i < ARRAY_SIZE(sregs.interrupt_bitmap); i++) {
+ if (sregs.interrupt_bitmap[i]) {
+ bit = ctz64(sregs.interrupt_bitmap[i]);
+ env->interrupt_injected = i * 64 + bit;
+ break;
+ }
+ }
get_seg(&env->segs[R_CS], &sregs.cs);
get_seg(&env->segs[R_DS], &sregs.ds);
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 2b88fea63..6bd447fbf 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -2,7 +2,6 @@
#include "hw/boards.h"
#include "hw/pc.h"
#include "hw/isa.h"
-#include "host-utils.h"
#include "exec-all.h"
#include "kvm.h"
@@ -321,7 +320,7 @@ static const VMStateInfo vmstate_hack_uint64_as_uint32 = {
static void cpu_pre_save(void *opaque)
{
CPUState *env = opaque;
- int i, bit;
+ int i;
cpu_synchronize_state(env);
kvm_save_mpstate(env);
@@ -338,17 +337,6 @@ static void cpu_pre_save(void *opaque)
#else
env->fpregs_format_vmstate = 1;
#endif
-
- /* There can only be one pending IRQ set in the bitmap at a time, so try
- to find it and save its number instead (-1 for none). */
- env->pending_irq_vmstate = -1;
- for (i = 0; i < ARRAY_SIZE(env->interrupt_bitmap); i++) {
- if (env->interrupt_bitmap[i]) {
- bit = ctz64(env->interrupt_bitmap[i]);
- env->pending_irq_vmstate = i * 64 + bit;
- break;
- }
- }
}
static int cpu_pre_load(void *opaque)
@@ -377,14 +365,6 @@ static int cpu_post_load(void *opaque, int version_id)
for (i = 0; i < 4; i++)
hw_breakpoint_insert(env, i);
- if (version_id >= 9) {
- memset(&env->interrupt_bitmap, 0, sizeof(env->interrupt_bitmap));
- if (env->pending_irq_vmstate >= 0) {
- env->interrupt_bitmap[env->pending_irq_vmstate / 64] |=
- (uint64_t)1 << (env->pending_irq_vmstate % 64);
- }
- }
-
tlb_flush(env, 1);
kvm_load_mpstate(env);
@@ -469,7 +449,7 @@ static const VMStateDescription vmstate_cpu = {
VMSTATE_UINT64_V(mtrr_deftype, CPUState, 8),
VMSTATE_MTRR_VARS(mtrr_var, CPUState, 8, 8),
/* KVM-related states */
- VMSTATE_INT32_V(pending_irq_vmstate, CPUState, 9),
+ VMSTATE_INT32_V(interrupt_injected, CPUState, 9),
VMSTATE_UINT32_V(mp_state, CPUState, 9),
VMSTATE_UINT64_V(tsc, CPUState, 9),
/* MCE */
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index c27738ac4..cefa5ae58 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -175,8 +175,6 @@ struct CPUMIPSState {
TCState active_tc;
CPUMIPSFPUContext active_fpu;
- CPUMIPSMVPContext *mvp;
- CPUMIPSTLBContext *tlb;
uint32_t current_tc;
uint32_t current_fpu;
@@ -458,6 +456,9 @@ struct CPUMIPSState {
CPU_COMMON
+ CPUMIPSMVPContext *mvp;
+ CPUMIPSTLBContext *tlb;
+
const mips_def_t *cpu_model;
void *irq[8];
struct QEMUTimer *timer; /* Internal timer */
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index d3dab33a3..83734b123 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -1169,7 +1169,7 @@ void helper_mtc0_status (target_ulong arg1)
case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
case MIPS_HFLAG_KM: qemu_log("\n"); break;
default: cpu_abort(env, "Invalid MMU mode!\n"); break;
- }
+ }
}
cpu_mips_update_irq(env);
}
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 58f483fa0..7bae5414c 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1624,7 +1624,7 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
tcg_temp_free(t2);
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
tcg_temp_free(t1);
- /* operands of different sign, first operand and result different sign */
+ /* operands of different sign, first operand and result different sign */
generate_exception(ctx, EXCP_OVERFLOW);
gen_set_label(l1);
gen_store_gpr(t0, rd);
@@ -1700,7 +1700,7 @@ static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
tcg_temp_free(t2);
tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
tcg_temp_free(t1);
- /* operands of different sign, first operand and result different sign */
+ /* operands of different sign, first operand and result different sign */
generate_exception(ctx, EXCP_OVERFLOW);
gen_set_label(l1);
gen_store_gpr(t0, rd);
@@ -8598,9 +8598,14 @@ CPUMIPSState *cpu_mips_init (const char *cpu_model)
return NULL;
env = qemu_mallocz(sizeof(CPUMIPSState));
env->cpu_model = def;
+ env->cpu_model_str = cpu_model;
cpu_exec_init(env);
- env->cpu_model_str = cpu_model;
+#ifndef CONFIG_USER_ONLY
+ mmu_init(env, def);
+#endif
+ fpu_init(env, def);
+ mvp_init(env, def);
mips_tcg_init();
cpu_reset(env);
qemu_init_vcpu(env);
@@ -8615,10 +8620,46 @@ void cpu_reset (CPUMIPSState *env)
}
memset(env, 0, offsetof(CPUMIPSState, breakpoints));
-
tlb_flush(env, 1);
- /* Minimal init */
+ /* Reset registers to their default values */
+ env->CP0_PRid = env->cpu_model->CP0_PRid;
+ env->CP0_Config0 = env->cpu_model->CP0_Config0;
+#ifdef TARGET_WORDS_BIGENDIAN
+ env->CP0_Config0 |= (1 << CP0C0_BE);
+#endif
+ env->CP0_Config1 = env->cpu_model->CP0_Config1;
+ env->CP0_Config2 = env->cpu_model->CP0_Config2;
+ env->CP0_Config3 = env->cpu_model->CP0_Config3;
+ env->CP0_Config6 = env->cpu_model->CP0_Config6;
+ env->CP0_Config7 = env->cpu_model->CP0_Config7;
+ env->SYNCI_Step = env->cpu_model->SYNCI_Step;
+ env->CCRes = env->cpu_model->CCRes;
+ env->CP0_Status_rw_bitmask = env->cpu_model->CP0_Status_rw_bitmask;
+ env->CP0_TCStatus_rw_bitmask = env->cpu_model->CP0_TCStatus_rw_bitmask;
+ env->CP0_SRSCtl = env->cpu_model->CP0_SRSCtl;
+ env->current_tc = 0;
+ env->SEGBITS = env->cpu_model->SEGBITS;
+ env->SEGMask = (target_ulong)((1ULL << env->cpu_model->SEGBITS) - 1);
+#if defined(TARGET_MIPS64)
+ if (env->cpu_model->insn_flags & ISA_MIPS3) {
+ env->SEGMask |= 3ULL << 62;
+ }
+#endif
+ env->PABITS = env->cpu_model->PABITS;
+ env->PAMask = (target_ulong)((1ULL << env->cpu_model->PABITS) - 1);
+ env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask;
+ env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0;
+ env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask;
+ env->CP0_SRSConf1 = env->cpu_model->CP0_SRSConf1;
+ env->CP0_SRSConf2_rw_bitmask = env->cpu_model->CP0_SRSConf2_rw_bitmask;
+ env->CP0_SRSConf2 = env->cpu_model->CP0_SRSConf2;
+ env->CP0_SRSConf3_rw_bitmask = env->cpu_model->CP0_SRSConf3_rw_bitmask;
+ env->CP0_SRSConf3 = env->cpu_model->CP0_SRSConf3;
+ env->CP0_SRSConf4_rw_bitmask = env->cpu_model->CP0_SRSConf4_rw_bitmask;
+ env->CP0_SRSConf4 = env->cpu_model->CP0_SRSConf4;
+ env->insn_flags = env->cpu_model->insn_flags;
+
#if defined(CONFIG_USER_ONLY)
env->hflags = MIPS_HFLAG_UM;
/* Enable access to the SYNCI_Step register. */
@@ -8632,6 +8673,8 @@ void cpu_reset (CPUMIPSState *env)
env->CP0_ErrorEPC = env->active_tc.PC;
}
env->active_tc.PC = (int32_t)0xBFC00000;
+ env->CP0_Random = env->tlb->nb_tlb - 1;
+ env->tlb->tlb_in_use = env->tlb->nb_tlb;
env->CP0_Wired = 0;
/* SMP not implemented */
env->CP0_EBase = 0x80000000;
@@ -8653,8 +8696,12 @@ void cpu_reset (CPUMIPSState *env)
env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
env->hflags = MIPS_HFLAG_CP0;
#endif
+#if defined(TARGET_MIPS64)
+ if (env->cpu_model->insn_flags & ISA_MIPS3) {
+ env->hflags |= MIPS_HFLAG_64;
+ }
+#endif
env->exception_index = EXCP_NONE;
- cpu_mips_register(env, env->cpu_model);
}
void gen_pc_load(CPUState *env, TranslationBlock *tb,
diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index eb35dbad3..088e2b4c2 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -481,8 +481,6 @@ static void mmu_init (CPUMIPSState *env, const mips_def_t *def)
default:
cpu_abort(env, "MMU type not supported\n");
}
- env->CP0_Random = env->tlb->nb_tlb - 1;
- env->tlb->tlb_in_use = env->tlb->nb_tlb;
}
#endif /* CONFIG_USER_ONLY */
@@ -530,51 +528,3 @@ static void mvp_init (CPUMIPSState *env, const mips_def_t *def)
(0x0 << CP0MVPC1_PCX) | (0x0 << CP0MVPC1_PCP2) |
(0x1 << CP0MVPC1_PCP1);
}
-
-static int cpu_mips_register (CPUMIPSState *env, const mips_def_t *def)
-{
- env->CP0_PRid = def->CP0_PRid;
- env->CP0_Config0 = def->CP0_Config0;
-#ifdef TARGET_WORDS_BIGENDIAN
- env->CP0_Config0 |= (1 << CP0C0_BE);
-#endif
- env->CP0_Config1 = def->CP0_Config1;
- env->CP0_Config2 = def->CP0_Config2;
- env->CP0_Config3 = def->CP0_Config3;
- env->CP0_Config6 = def->CP0_Config6;
- env->CP0_Config7 = def->CP0_Config7;
- env->SYNCI_Step = def->SYNCI_Step;
- env->CCRes = def->CCRes;
- env->CP0_Status_rw_bitmask = def->CP0_Status_rw_bitmask;
- env->CP0_TCStatus_rw_bitmask = def->CP0_TCStatus_rw_bitmask;
- env->CP0_SRSCtl = def->CP0_SRSCtl;
- env->current_tc = 0;
- env->SEGBITS = def->SEGBITS;
- env->SEGMask = (target_ulong)((1ULL << def->SEGBITS) - 1);
-#if defined(TARGET_MIPS64)
- if (def->insn_flags & ISA_MIPS3) {
- env->hflags |= MIPS_HFLAG_64;
- env->SEGMask |= 3ULL << 62;
- }
-#endif
- env->PABITS = def->PABITS;
- env->PAMask = (target_ulong)((1ULL << def->PABITS) - 1);
- env->CP0_SRSConf0_rw_bitmask = def->CP0_SRSConf0_rw_bitmask;
- env->CP0_SRSConf0 = def->CP0_SRSConf0;
- env->CP0_SRSConf1_rw_bitmask = def->CP0_SRSConf1_rw_bitmask;
- env->CP0_SRSConf1 = def->CP0_SRSConf1;
- env->CP0_SRSConf2_rw_bitmask = def->CP0_SRSConf2_rw_bitmask;
- env->CP0_SRSConf2 = def->CP0_SRSConf2;
- env->CP0_SRSConf3_rw_bitmask = def->CP0_SRSConf3_rw_bitmask;
- env->CP0_SRSConf3 = def->CP0_SRSConf3;
- env->CP0_SRSConf4_rw_bitmask = def->CP0_SRSConf4_rw_bitmask;
- env->CP0_SRSConf4 = def->CP0_SRSConf4;
- env->insn_flags = def->insn_flags;
-
-#ifndef CONFIG_USER_ONLY
- mmu_init(env, def);
-#endif
- fpu_init(env, def);
- mvp_init(env, def);
- return 0;
-}
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index b53d6e99a..4e1c65f12 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -53,6 +53,10 @@ int kvm_arch_init_vcpu(CPUState *cenv)
return ret;
}
+void kvm_arch_reset_vcpu(CPUState *env)
+{
+}
+
int kvm_arch_put_registers(CPUState *env)
{
struct kvm_regs regs;
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index dd4d4e071..972b10211 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -1147,7 +1147,6 @@ static const TCGTargetOpDef x86_op_defs[] = {
{ INDEX_op_shl_i32, { "r", "0", "ci" } },
{ INDEX_op_shr_i32, { "r", "0", "ci" } },
{ INDEX_op_sar_i32, { "r", "0", "ci" } },
- { INDEX_op_sar_i32, { "r", "0", "ci" } },
{ INDEX_op_rotl_i32, { "r", "0", "ci" } },
{ INDEX_op_rotr_i32, { "r", "0", "ci" } },
diff --git a/vl.c b/vl.c
index 581bef2df..7be5512d6 100644
--- a/vl.c
+++ b/vl.c
@@ -148,6 +148,8 @@ int main(int argc, char **argv)
#include "qemu-char.h"
#include "cache-utils.h"
#include "block.h"
+#include "block_int.h"
+#include "block-migration.h"
#include "dma.h"
#include "audio/audio.h"
#include "migration.h"
@@ -3006,9 +3008,7 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque)
bwidth = 0.000001;
/* try transferring iterative blocks of memory */
-
if (stage == 3) {
-
/* flush all remaining blocks regardless of rate limiting */
while (ram_save_block(f) != 0) {
bytes_transferred += TARGET_PAGE_SIZE;
@@ -5666,6 +5666,8 @@ int main(int argc, char **argv, char **envp)
bdrv_init_with_whitelist();
+ blk_mig_init();
+
/* we always create the cdrom drive, even if no disk is there */
drive_add(NULL, CDROM_ALIAS);
@@ -5682,7 +5684,8 @@ int main(int argc, char **argv, char **envp)
exit(1);
vmstate_register(0, &vmstate_timers ,&timers_state);
- register_savevm_live("ram", 0, 3, ram_save_live, NULL, ram_load, NULL);
+ register_savevm_live("ram", 0, 3, NULL, ram_save_live, NULL,
+ ram_load, NULL);
/* Maintain compatibility with multiple stdio monitors */
if (!strcmp(monitor_devices[0],"stdio")) {
@@ -5903,7 +5906,6 @@ int main(int argc, char **argv, char **envp)
}
text_consoles_set_display(display_state);
- qemu_chr_initial_reset();
for (i = 0; i < MAX_MONITOR_DEVICES; i++) {
if (monitor_devices[i] && monitor_hds[i]) {