aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2009-04-06 10:47:06 +0300
committerAvi Kivity <avi@redhat.com>2009-04-06 10:47:06 +0300
commit67afa42dada0e8eab8b88bcc12447bddfccad5f7 (patch)
tree25d0be082487757dd67a932345bc293c75f87eed
parent1f28c06981a34f279cc90fa2b72a91bc6884af4e (diff)
parentc20d7afb366e5d969858fcdcd4b5d5250fa3be91 (diff)
Merge commit 'qemu-svn/trunk'kvm-85rc3
* commit 'qemu-svn/trunk': (38 commits) Remove WIN32 guard around -k Add new command line option -singlestep for tcg single stepping. tcg/x86_64: optimize register allocation order stop dirty tracking just at the end of migration (Glauber Costa) create qemu_file_set_error (Glauber Costa) propagate error on failed completion (Glauber Costa) Disable qemu-io on Win32 Add files not included in previous commit. Fix savevm after BDRV_FILE size enforcement Fix the build for --disable-aio gdbstub: Rework configuration via command line and monitor (Jan Kiszka) Make `-icount' help fit 80 chars screen width (Robert Riebisch) qemu-io - an I/O path exerciser (Christoph Hellwig) Fix display breakage when resizing the screen (v2) (Avi Kivity) Fix some win32 compile warnings Make binary stripping conditional (Riku Voipio) qcow2: fix image creation for large, > ~2TB, images (Chris Wright) pci_add storage: fix error handling for 'if' parameter (Eduardo Habkost) build system: clean qemu-options.texi and gdbstub-xml.c (Jan Kiszka) build system: silent generation of doc files and qemu-options.h (Jan Kiszka) ... Conflicts: qemu/Makefile.target qemu/hw/vga.c qemu/vl.c Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--CODING_STYLE78
-rw-r--r--Makefile34
-rw-r--r--Makefile.target21
-rw-r--r--block-qcow2.c52
-rw-r--r--block-raw-posix.c42
-rw-r--r--block-raw-win32.c4
-rw-r--r--block.c20
-rw-r--r--block.h5
-rw-r--r--block_int.h5
-rw-r--r--bsd-user/main.c5
-rw-r--r--cmd.c565
-rw-r--r--cmd.h78
-rwxr-xr-xconfigure20
-rw-r--r--cpu-exec.c10
-rw-r--r--darwin-user/main.c5
-rw-r--r--exec-all.h4
-rw-r--r--exec.c1
-rw-r--r--gdbstub.c41
-rw-r--r--hw/cirrus_vga.c11
-rw-r--r--hw/framebuffer.c119
-rw-r--r--hw/framebuffer.h22
-rw-r--r--hw/hw.h1
-rw-r--r--hw/omap.h2
-rw-r--r--hw/omap_lcd_template.h23
-rw-r--r--hw/omap_lcdc.c96
-rw-r--r--hw/pci-hotplug.c12
-rw-r--r--hw/pl110.c86
-rw-r--r--hw/pl110_template.h16
-rw-r--r--hw/ptimer.c31
-rw-r--r--hw/pxa2xx_lcd.c117
-rw-r--r--hw/pxa2xx_template.h27
-rw-r--r--hw/vga.c278
-rw-r--r--hw/vga_int.h4
-rw-r--r--hw/virtio-net.c16
-rw-r--r--hw/virtio.c9
-rw-r--r--hw/virtio.h3
-rw-r--r--linux-user/main.c5
-rw-r--r--migration.c10
-rw-r--r--monitor.c42
-rw-r--r--nbd.c2
-rw-r--r--net.c2
-rw-r--r--pc-bios/README2
-rw-r--r--pc-bios/openbios-ppcbin271336 -> 271336 bytes
-rw-r--r--pc-bios/openbios-sparc32bin234116 -> 238212 bytes
-rw-r--r--pc-bios/openbios-sparc64bin476064 -> 476064 bytes
-rw-r--r--qemu-doc.texi10
-rw-r--r--qemu-img.c34
-rw-r--r--qemu-io.c1074
-rw-r--r--qemu-options.hx36
-rw-r--r--savevm.c17
-rw-r--r--slirp/misc.c6
-rw-r--r--slirp/socket.h1
-rw-r--r--tap-win32.c10
-rw-r--r--target-alpha/translate.c8
-rw-r--r--target-arm/translate.c1
-rw-r--r--target-cris/translate.c1
-rw-r--r--target-i386/translate.c89
-rw-r--r--target-m68k/translate.c1
-rw-r--r--target-mips/translate.c7
-rw-r--r--target-ppc/translate.c5
-rw-r--r--target-sh4/cpu.h15
-rw-r--r--target-sh4/helper.c50
-rw-r--r--target-sh4/helper.h4
-rw-r--r--target-sh4/op_helper.c52
-rw-r--r--target-sh4/translate.c51
-rw-r--r--target-sparc/translate.c2
-rw-r--r--tcg/sparc/tcg-target.c106
-rw-r--r--tcg/sparc/tcg-target.h8
-rw-r--r--tcg/x86_64/tcg-target.c19
-rw-r--r--vl.c53
70 files changed, 3016 insertions, 570 deletions
diff --git a/CODING_STYLE b/CODING_STYLE
new file mode 100644
index 000000000..1ab13b686
--- /dev/null
+++ b/CODING_STYLE
@@ -0,0 +1,78 @@
+Qemu Coding Style
+=================
+
+1. Whitespace
+
+Of course, the most important aspect in any coding style is whitespace.
+Crusty old coders who have trouble spotting the glasses on their noses
+can tell the difference between a tab and eight spaces from a distance
+of approximately fifteen parsecs. Many a flamewar have been fought and
+lost on this issue.
+
+QEMU indents are four spaces. Tabs are never used, except in Makefiles
+where they have been irreversibly coded into the syntax by some moron.
+Spaces of course are superior to tabs because:
+
+ - You have just one way to specify whitespace, not two. Ambiguity breeds
+ mistakes.
+ - The confusion surrounding 'use tabs to indent, spaces to justify' is gone.
+ - Tab indents push your code to the right, making your screen seriously
+ unbalanced.
+ - Tabs will be rendered incorrectly on editors who are misconfigured not
+ to use tab stops of eight positions.
+ - Tabs are rendered badly in patches, causing off-by-one errors in almost
+ every line.
+ - It is the QEMU coding style.
+
+Do not leave whitespace dangling off the ends of lines.
+
+2. Line width
+
+Lines are 80 characters; not longer.
+
+Rationale:
+ - Some people like to tile their 24" screens with a 6x4 matrix of 80x24
+ xterms and use vi in all of them. The best way to punish them is to
+ let them keep doing it.
+ - Code and especially patches is much more readable if limited to a sane
+ line length. Eighty is traditional.
+ - It is the QEMU coding style.
+
+3. Naming
+
+Variables are lower_case_with_underscores; easy to type and read. Structured
+type names are in CamelCase; harder to type but standing out. Scalar type
+names are lower_case_with_underscores_ending_with_a_t, like the POSIX
+uint64_t and family. Note that this last convention contradicts POSIX
+and is therefore likely to be changed.
+
+Typedefs are used to eliminate the redundant 'struct' keyword. It is the
+QEMU coding style.
+
+4. Block structure
+
+Every indented statement is braced; even if the block contains just one
+statement. The opening brace is on the line that contains the control
+flow statement that introduces the new block; the closing brace is on the
+same line as the else keyword, or on a line by itself if there is no else
+keyword. Example:
+
+ if (a == 5) {
+ printf("a was 5.\n");
+ } else if (a == 6) {
+ printf("a was 6.\n");
+ } else {
+ printf("a was something else entirely.\n");
+ }
+
+An exception is the opening brace for a function; for reasons of tradition
+and clarity it comes on a line by itself:
+
+ void a_function(void)
+ {
+ do_something();
+ }
+
+Rationale: a consistent (except for functions...) bracing style reduces
+ambiguity and avoids needless churn when lines are added or removed.
+Furthermore, it is the QEMU coding style.
diff --git a/Makefile b/Makefile
index 36c240220..f6f3c32ac 100644
--- a/Makefile
+++ b/Makefile
@@ -210,7 +210,9 @@ qemu-img$(EXESUF): qemu-img.o qemu-tool.o osdep.o $(BLOCK_OBJS)
qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o osdep.o $(BLOCK_OBJS)
-qemu-img$(EXESUF) qemu-nbd$(EXESUF): LIBS += -lz
+qemu-io$(EXESUF): qemu-io.o qemu-tool.o osdep.o cmd.o $(BLOCK_OBJS)
+
+qemu-img$(EXESUF) qemu-nbd$(EXESUF) qemu-io$(EXESUF): LIBS += -lz
clean:
# avoid old build problems by removing potentially incorrect old files
@@ -223,7 +225,7 @@ clean:
done
distclean: clean
- rm -f config-host.mak config-host.h $(DOCS)
+ rm -f config-host.mak config-host.h $(DOCS) qemu-options.texi
rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr}
for d in $(TARGET_DIRS); do \
rm -rf $$d || exit 1 ; \
@@ -256,7 +258,7 @@ endif
install: all $(if $(BUILD_DOCS),install-doc)
mkdir -p "$(DESTDIR)$(bindir)"
ifneq ($(TOOLS),)
- $(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
+ $(INSTALL) -m 755 $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
endif
ifneq ($(BLOBS),)
mkdir -p "$(DESTDIR)$(datadir)"
@@ -290,28 +292,34 @@ cscope:
# documentation
%.html: %.texi
- texi2html -I=. -monolithic -number $<
+ $(call quiet-command,texi2html -I=. -monolithic -number $<," GEN $@")
%.info: %.texi
- makeinfo -I . $< -o $@
+ $(call quiet-command,makeinfo -I . $< -o $@," GEN $@")
%.dvi: %.texi
- texi2dvi -I . $<
+ $(call quiet-command,texi2dvi -I . $<," GEN $@")
qemu-options.texi: $(SRC_PATH)/qemu-options.hx
- sh $(SRC_PATH)/hxtool -t < $< > $@
+ $(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@")
qemu.1: qemu-doc.texi
- perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu.pod
- pod2man --section=1 --center=" " --release=" " qemu.pod > $@
+ $(call quiet-command, \
+ perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu.pod && \
+ pod2man --section=1 --center=" " --release=" " qemu.pod > $@, \
+ " GEN $@")
qemu-img.1: qemu-img.texi
- perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-img.pod
- pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@
+ $(call quiet-command, \
+ perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-img.pod && \
+ pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@, \
+ " GEN $@")
qemu-nbd.8: qemu-nbd.texi
- perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-nbd.pod
- pod2man --section=8 --center=" " --release=" " qemu-nbd.pod > $@
+ $(call quiet-command, \
+ perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu-nbd.pod && \
+ pod2man --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
+ " GEN $@")
info: qemu-doc.info qemu-tech.info
diff --git a/Makefile.target b/Makefile.target
index 6eed85387..f89a9ecc1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -91,19 +91,13 @@ ifeq ($(ARCH),i386)
HELPER_CFLAGS+=-fomit-frame-pointer
endif
-ifeq ($(ARCH),sparc)
- CFLAGS+=-ffixed-g2 -ffixed-g3
- ifneq ($(CONFIG_SOLARIS),yes)
- CFLAGS+=-ffixed-g1 -ffixed-g6
- HELPER_CFLAGS+=-ffixed-i0
- endif
+ifeq ($(subst ppc64,ppc,$(ARCH))$(TARGET_BASE_ARCH),ppcppc)
+translate.o: CFLAGS := $(CFLAGS) $(call cc-option, $(CFLAGS), -fno-unit-at-a-time,)
endif
-ifeq ($(ARCH),sparc64)
+ifeq ($(ARCH),sparc)
ifneq ($(CONFIG_SOLARIS),yes)
- CFLAGS+=-ffixed-g5 -ffixed-g6 -ffixed-g7
- else
- CFLAGS+=-ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
+ HELPER_CFLAGS+=-ffixed-i0
endif
endif
@@ -754,6 +748,7 @@ OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
OBJS+= tsc2005.o bt-hci-csr.o
OBJS+= mst_fpga.o mainstone.o
OBJS+= musicpal.o pflash_cfi02.o
+OBJS+= framebuffer.o
CPPFLAGS += -DHAS_AUDIO
endif
ifeq ($(TARGET_BASE_ARCH), sh4)
@@ -832,15 +827,15 @@ else
endif
qemu-options.h: $(SRC_PATH)/qemu-options.hx
- sh $(SRC_PATH)/hxtool -h < $< > $@
+ $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
clean:
- rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o qemu-options.h
+ rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o qemu-options.h gdbstub-xml.c
rm -f *.d */*.d tcg/*.o
install: all
ifneq ($(PROGS),)
- $(INSTALL) -m 755 $(PROGS) "$(DESTDIR)$(bindir)"
+ $(INSTALL) -m 755 $(STRIP_OPT) $(PROGS) "$(DESTDIR)$(bindir)"
endif
# Include automatically generated dependency files
diff --git a/block-qcow2.c b/block-qcow2.c
index 60d87a4b8..6eba524a2 100644
--- a/block-qcow2.c
+++ b/block-qcow2.c
@@ -761,6 +761,10 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
nb_available = (nb_available >> 9) + index_in_cluster;
+ if (nb_needed > nb_available) {
+ nb_needed = nb_available;
+ }
+
cluster_offset = 0;
/* seek the the l2 offset in the l1 table */
@@ -1551,7 +1555,7 @@ static int qcow_create2(const char *filename, int64_t total_size,
{
int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits;
- int backing_format_len = 0;
+ int ref_clusters, backing_format_len = 0;
QCowHeader header;
uint64_t tmp, offset;
QCowCreateState s1, *s = &s1;
@@ -1600,22 +1604,28 @@ static int qcow_create2(const char *filename, int64_t total_size,
offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size);
s->refcount_table = qemu_mallocz(s->cluster_size);
- s->refcount_block = qemu_mallocz(s->cluster_size);
s->refcount_table_offset = offset;
header.refcount_table_offset = cpu_to_be64(offset);
header.refcount_table_clusters = cpu_to_be32(1);
offset += s->cluster_size;
-
- s->refcount_table[0] = cpu_to_be64(offset);
s->refcount_block_offset = offset;
- offset += s->cluster_size;
+
+ /* count how many refcount blocks needed */
+ tmp = offset >> s->cluster_bits;
+ ref_clusters = (tmp >> (s->cluster_bits - REFCOUNT_SHIFT)) + 1;
+ for (i=0; i < ref_clusters; i++) {
+ s->refcount_table[i] = cpu_to_be64(offset);
+ offset += s->cluster_size;
+ }
+
+ s->refcount_block = qemu_mallocz(ref_clusters * s->cluster_size);
/* update refcounts */
create_refcount_update(s, 0, header_size);
create_refcount_update(s, s->l1_table_offset, l1_size * sizeof(uint64_t));
create_refcount_update(s, s->refcount_table_offset, s->cluster_size);
- create_refcount_update(s, s->refcount_block_offset, s->cluster_size);
+ create_refcount_update(s, s->refcount_block_offset, ref_clusters * s->cluster_size);
/* write all the data */
write(fd, &header, sizeof(header));
@@ -1644,7 +1654,7 @@ static int qcow_create2(const char *filename, int64_t total_size,
write(fd, s->refcount_table, s->cluster_size);
lseek(fd, s->refcount_block_offset, SEEK_SET);
- write(fd, s->refcount_block, s->cluster_size);
+ write(fd, s->refcount_block, ref_clusters * s->cluster_size);
qemu_free(s->refcount_table);
qemu_free(s->refcount_block);
@@ -2711,6 +2721,31 @@ static void dump_refcounts(BlockDriverState *bs)
#endif
#endif
+static int qcow_put_buffer(BlockDriverState *bs, const uint8_t *buf,
+ int64_t pos, int size)
+{
+ int growable = bs->growable;
+
+ bs->growable = 1;
+ bdrv_pwrite(bs, pos, buf, size);
+ bs->growable = growable;
+
+ return size;
+}
+
+static int qcow_get_buffer(BlockDriverState *bs, uint8_t *buf,
+ int64_t pos, int size)
+{
+ int growable = bs->growable;
+ int ret;
+
+ bs->growable = 1;
+ ret = bdrv_pread(bs, pos, buf, size);
+ bs->growable = growable;
+
+ return ret;
+}
+
BlockDriver bdrv_qcow2 = {
.format_name = "qcow2",
.instance_size = sizeof(BDRVQcowState),
@@ -2735,5 +2770,8 @@ BlockDriver bdrv_qcow2 = {
.bdrv_snapshot_list = qcow_snapshot_list,
.bdrv_get_info = qcow_get_info,
+ .bdrv_put_buffer = qcow_put_buffer,
+ .bdrv_get_buffer = qcow_get_buffer,
+
.bdrv_create2 = qcow_create2,
};
diff --git a/block-raw-posix.c b/block-raw-posix.c
index 6d617bb3a..a972f80ae 100644
--- a/block-raw-posix.c
+++ b/block-raw-posix.c
@@ -1015,8 +1015,10 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
s->fd_open_flags = open_flags;
/* open will not fail even if no floppy is inserted */
open_flags |= O_NONBLOCK;
+#ifdef CONFIG_AIO
} else if (strstart(filename, "/dev/sg", NULL)) {
bs->sg = 1;
+#endif
}
#endif
#if defined(__FreeBSD__)
@@ -1207,6 +1209,7 @@ static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
return ioctl(s->fd, req, buf);
}
+#ifdef CONFIG_AIO
static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
unsigned long int req, void *buf,
BlockDriverCompletionFunc *cb, void *opaque)
@@ -1225,6 +1228,7 @@ static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
return &acb->common;
}
+#endif
#elif defined(__FreeBSD__)
@@ -1375,11 +1379,47 @@ static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
}
#endif /* !linux && !FreeBSD */
+#if defined(__linux__) || defined(__FreeBSD__)
+static int hdev_create(const char *filename, int64_t total_size,
+ const char *backing_file, int flags)
+{
+ int fd;
+ int ret = 0;
+ struct stat stat_buf;
+
+ if (flags || backing_file)
+ return -ENOTSUP;
+
+ fd = open(filename, O_WRONLY | O_BINARY);
+ if (fd < 0)
+ return -EIO;
+
+ if (fstat(fd, &stat_buf) < 0)
+ ret = -EIO;
+ else if (!S_ISBLK(stat_buf.st_mode))
+ ret = -EIO;
+ else if (lseek(fd, 0, SEEK_END) < total_size * 512)
+ ret = -ENOSPC;
+
+ close(fd);
+ return ret;
+}
+
+#else /* !(linux || freebsd) */
+
+static int hdev_create(const char *filename, int64_t total_size,
+ const char *backing_file, int flags)
+{
+ return -ENOTSUP;
+}
+#endif
+
BlockDriver bdrv_host_device = {
.format_name = "host_device",
.instance_size = sizeof(BDRVRawState),
.bdrv_open = hdev_open,
.bdrv_close = raw_close,
+ .bdrv_create = hdev_create,
.bdrv_flush = raw_flush,
#ifdef CONFIG_AIO
@@ -1400,5 +1440,7 @@ BlockDriver bdrv_host_device = {
.bdrv_set_locked = raw_set_locked,
/* generic scsi device */
.bdrv_ioctl = raw_ioctl,
+#ifdef CONFIG_AIO
.bdrv_aio_ioctl = raw_aio_ioctl,
+#endif
};
diff --git a/block-raw-win32.c b/block-raw-win32.c
index 11638b8d4..af9cc6db3 100644
--- a/block-raw-win32.c
+++ b/block-raw-win32.c
@@ -166,7 +166,7 @@ static void raw_close(BlockDriverState *bs)
static int raw_truncate(BlockDriverState *bs, int64_t offset)
{
BDRVRawState *s = bs->opaque;
- DWORD low, high;
+ LONG low, high;
low = offset;
high = offset >> 32;
@@ -188,7 +188,7 @@ static int64_t raw_getlength(BlockDriverState *bs)
switch(s->type) {
case FTYPE_FILE:
- l.LowPart = GetFileSize(s->hfile, &l.HighPart);
+ l.LowPart = GetFileSize(s->hfile, (PDWORD)&l.HighPart);
if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
return -EIO;
break;
diff --git a/block.c b/block.c
index a86c48250..657de8107 100644
--- a/block.c
+++ b/block.c
@@ -1155,6 +1155,26 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
return drv->bdrv_get_info(bs, bdi);
}
+int bdrv_put_buffer(BlockDriverState *bs, const uint8_t *buf, int64_t pos, int size)
+{
+ BlockDriver *drv = bs->drv;
+ if (!drv)
+ return -ENOMEDIUM;
+ if (!drv->bdrv_put_buffer)
+ return -ENOTSUP;
+ return drv->bdrv_put_buffer(bs, buf, pos, size);
+}
+
+int bdrv_get_buffer(BlockDriverState *bs, uint8_t *buf, int64_t pos, int size)
+{
+ BlockDriver *drv = bs->drv;
+ if (!drv)
+ return -ENOMEDIUM;
+ if (!drv->bdrv_get_buffer)
+ return -ENOTSUP;
+ return drv->bdrv_get_buffer(bs, buf, pos, size);
+}
+
/**************************************************************/
/* handling of snapshots */
diff --git a/block.h b/block.h
index 6701d3450..f1919b668 100644
--- a/block.h
+++ b/block.h
@@ -178,4 +178,9 @@ void path_combine(char *dest, int dest_size,
const char *base_path,
const char *filename);
+int bdrv_put_buffer(BlockDriverState *bs, const uint8_t *buf,
+ int64_t pos, int size);
+
+int bdrv_get_buffer(BlockDriverState *bs, uint8_t *buf, int64_t pos, int size);
+
#endif
diff --git a/block_int.h b/block_int.h
index 38bf28047..a59f54c4c 100644
--- a/block_int.h
+++ b/block_int.h
@@ -78,6 +78,11 @@ struct BlockDriver {
QEMUSnapshotInfo **psn_info);
int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
+ int (*bdrv_put_buffer)(BlockDriverState *bs, const uint8_t *buf,
+ int64_t pos, int size);
+ int (*bdrv_get_buffer)(BlockDriverState *bs, uint8_t *buf,
+ int64_t pos, int size);
+
/* removable device specific */
int (*bdrv_is_inserted)(BlockDriverState *bs);
int (*bdrv_media_changed)(BlockDriverState *bs);
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 0dc9b996e..34a6b0762 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -33,6 +33,8 @@
#define DEBUG_LOGFILE "/tmp/qemu.log"
+int singlestep;
+
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
extern char **environ;
@@ -378,6 +380,7 @@ static void usage(void)
"Debug options:\n"
"-d options activate log (logfile=%s)\n"
"-p pagesize set the host page size to 'pagesize'\n"
+ "-singlestep always run in singlestep mode\n"
"-strace log system calls\n"
"\n"
"Environment variables:\n"
@@ -500,6 +503,8 @@ int main(int argc, char **argv)
usage();
}
optind++;
+ } else if (!strcmp(r, "singlestep")) {
+ singlestep = 1;
} else if (!strcmp(r, "strace")) {
do_strace = 1;
} else
diff --git a/cmd.c b/cmd.c
new file mode 100644
index 000000000..e2f4486a1
--- /dev/null
+++ b/cmd.c
@@ -0,0 +1,565 @@
+/*
+ * Copyright (c) 2003-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "cmd.h"
+
+#define _(x) x /* not gettext support yet */
+
+extern int optind;
+
+/* from libxcmd/command.c */
+
+cmdinfo_t *cmdtab;
+int ncmds;
+
+static argsfunc_t args_func;
+static checkfunc_t check_func;
+static int ncmdline;
+static char **cmdline;
+
+static int
+compare(const void *a, const void *b)
+{
+ return strcmp(((const cmdinfo_t *)a)->name,
+ ((const cmdinfo_t *)b)->name);
+}
+
+void
+add_command(
+ const cmdinfo_t *ci)
+{
+ cmdtab = realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab));
+ cmdtab[ncmds - 1] = *ci;
+ qsort(cmdtab, ncmds, sizeof(*cmdtab), compare);
+}
+
+static int
+check_command(
+ const cmdinfo_t *ci)
+{
+ if (check_func)
+ return check_func(ci);
+ return 1;
+}
+
+void
+add_check_command(
+ checkfunc_t cf)
+{
+ check_func = cf;
+}
+
+int
+command_usage(
+ const cmdinfo_t *ci)
+{
+ printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline);
+ return 0;
+}
+
+int
+command(
+ const cmdinfo_t *ct,
+ int argc,
+ char **argv)
+{
+ char *cmd = argv[0];
+
+ if (!check_command(ct))
+ return 0;
+
+ if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) {
+ if (ct->argmax == -1)
+ fprintf(stderr,
+ _("bad argument count %d to %s, expected at least %d arguments\n"),
+ argc-1, cmd, ct->argmin);
+ else if (ct->argmin == ct->argmax)
+ fprintf(stderr,
+ _("bad argument count %d to %s, expected %d arguments\n"),
+ argc-1, cmd, ct->argmin);
+ else
+ fprintf(stderr,
+ _("bad argument count %d to %s, expected between %d and %d arguments\n"),
+ argc-1, cmd, ct->argmin, ct->argmax);
+ return 0;
+ }
+ optind = 0;
+ return ct->cfunc(argc, argv);
+}
+
+const cmdinfo_t *
+find_command(
+ const char *cmd)
+{
+ cmdinfo_t *ct;
+
+ for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
+ if (strcmp(ct->name, cmd) == 0 ||
+ (ct->altname && strcmp(ct->altname, cmd) == 0))
+ return (const cmdinfo_t *)ct;
+ }
+ return NULL;
+}
+
+void
+add_user_command(char *optarg)
+{
+ ncmdline++;
+ cmdline = realloc(cmdline, sizeof(char*) * (ncmdline));
+ if (!cmdline) {
+ perror("realloc");
+ exit(1);
+ }
+ cmdline[ncmdline-1] = optarg;
+}
+
+static int
+args_command(
+ int index)
+{
+ if (args_func)
+ return args_func(index);
+ return 0;
+}
+
+void
+add_args_command(
+ argsfunc_t af)
+{
+ args_func = af;
+}
+
+void
+command_loop(void)
+{
+ int c, i, j = 0, done = 0;
+ char *input;
+ char **v;
+ const cmdinfo_t *ct;
+
+ for (i = 0; !done && i < ncmdline; i++) {
+ input = strdup(cmdline[i]);
+ if (!input) {
+ fprintf(stderr,
+ _("cannot strdup command '%s': %s\n"),
+ cmdline[i], strerror(errno));
+ exit(1);
+ }
+ v = breakline(input, &c);
+ if (c) {
+ ct = find_command(v[0]);
+ if (ct) {
+ if (ct->flags & CMD_FLAG_GLOBAL)
+ done = command(ct, c, v);
+ else {
+ j = 0;
+ while (!done && (j = args_command(j)))
+ done = command(ct, c, v);
+ }
+ } else
+ fprintf(stderr, _("command \"%s\" not found\n"),
+ v[0]);
+ }
+ doneline(input, v);
+ }
+ if (cmdline) {
+ free(cmdline);
+ return;
+ }
+ while (!done) {
+ if ((input = fetchline()) == NULL)
+ break;
+ v = breakline(input, &c);
+ if (c) {
+ ct = find_command(v[0]);
+ if (ct)
+ done = command(ct, c, v);
+ else
+ fprintf(stderr, _("command \"%s\" not found\n"),
+ v[0]);
+ }
+ doneline(input, v);
+ }
+}
+
+/* from libxcmd/input.c */
+
+#if defined(ENABLE_READLINE)
+# include <readline/history.h>
+# include <readline/readline.h>
+#elif defined(ENABLE_EDITLINE)
+# include <histedit.h>
+#endif
+
+extern char *progname;
+
+static char *
+get_prompt(void)
+{
+ static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ];
+
+ if (!prompt[0])
+ snprintf(prompt, sizeof(prompt), "%s> ", progname);
+ return prompt;
+}
+
+#if defined(ENABLE_READLINE)
+char *
+fetchline(void)
+{
+ char *line;
+
+ line = readline(get_prompt());
+ if (line && *line)
+ add_history(line);
+ return line;
+}
+#elif defined(ENABLE_EDITLINE)
+static char *el_get_prompt(EditLine *e) { return get_prompt(); }
+char *
+fetchline(void)
+{
+ static EditLine *el;
+ static History *hist;
+ HistEvent hevent;
+ char *line;
+ int count;
+
+ if (!el) {
+ hist = history_init();
+ history(hist, &hevent, H_SETSIZE, 100);
+ el = el_init(progname, stdin, stdout, stderr);
+ el_source(el, NULL);
+ el_set(el, EL_SIGNAL, 1);
+ el_set(el, EL_PROMPT, el_get_prompt);
+ el_set(el, EL_HIST, history, (const char *)hist);
+ }
+ line = strdup(el_gets(el, &count));
+ if (line) {
+ if (count > 0)
+ line[count-1] = '\0';
+ if (*line)
+ history(hist, &hevent, H_ENTER, line);
+ }
+ return line;
+}
+#else
+# define MAXREADLINESZ 1024
+char *
+fetchline(void)
+{
+ char *p, *line = malloc(MAXREADLINESZ);
+
+ if (!line)
+ return NULL;
+ printf("%s", get_prompt());
+ fflush(stdout);
+ if (!fgets(line, MAXREADLINESZ, stdin)) {
+ free(line);
+ return NULL;
+ }
+ p = line + strlen(line);
+ if (p != line && p[-1] == '\n')
+ p[-1] = '\0';
+ return line;
+}
+#endif
+
+char **
+breakline(
+ char *input,
+ int *count)
+{
+ int c = 0;
+ char *p;
+ char **rval = calloc(sizeof(char *), 1);
+
+ while (rval && (p = strsep(&input, " ")) != NULL) {
+ if (!*p)
+ continue;
+ c++;
+ rval = realloc(rval, sizeof(*rval) * (c + 1));
+ if (!rval) {
+ c = 0;
+ break;
+ }
+ rval[c - 1] = p;
+ rval[c] = NULL;
+ }
+ *count = c;
+ return rval;
+}
+
+void
+doneline(
+ char *input,
+ char **vec)
+{
+ free(input);
+ free(vec);
+}
+
+#define EXABYTES(x) ((long long)(x) << 60)
+#define PETABYTES(x) ((long long)(x) << 50)
+#define TERABYTES(x) ((long long)(x) << 40)
+#define GIGABYTES(x) ((long long)(x) << 30)
+#define MEGABYTES(x) ((long long)(x) << 20)
+#define KILOBYTES(x) ((long long)(x) << 10)
+
+long long
+cvtnum(
+ char *s)
+{
+ long long i;
+ char *sp;
+ int c;
+
+ i = strtoll(s, &sp, 0);
+ if (i == 0 && sp == s)
+ return -1LL;
+ if (*sp == '\0')
+ return i;
+
+ if (sp[1] != '\0')
+ return -1LL;
+
+ c = tolower(*sp);
+ switch (c) {
+ default:
+ return i;
+ case 'k':
+ return KILOBYTES(i);
+ case 'm':
+ return MEGABYTES(i);
+ case 'g':
+ return GIGABYTES(i);
+ case 't':
+ return TERABYTES(i);
+ case 'p':
+ return PETABYTES(i);
+ case 'e':
+ return EXABYTES(i);
+ }
+ return -1LL;
+}
+
+#define TO_EXABYTES(x) ((x) / EXABYTES(1))
+#define TO_PETABYTES(x) ((x) / PETABYTES(1))
+#define TO_TERABYTES(x) ((x) / TERABYTES(1))
+#define TO_GIGABYTES(x) ((x) / GIGABYTES(1))
+#define TO_MEGABYTES(x) ((x) / MEGABYTES(1))
+#define TO_KILOBYTES(x) ((x) / KILOBYTES(1))
+
+void
+cvtstr(
+ double value,
+ char *str,
+ size_t size)
+{
+ const char *fmt;
+ int precise;
+
+ precise = ((double)value * 1000 == (double)(int)value * 1000);
+
+ if (value >= EXABYTES(1)) {
+ fmt = precise ? "%.f EiB" : "%.3f EiB";
+ snprintf(str, size, fmt, TO_EXABYTES(value));
+ } else if (value >= PETABYTES(1)) {
+ fmt = precise ? "%.f PiB" : "%.3f PiB";
+ snprintf(str, size, fmt, TO_PETABYTES(value));
+ } else if (value >= TERABYTES(1)) {
+ fmt = precise ? "%.f TiB" : "%.3f TiB";
+ snprintf(str, size, fmt, TO_TERABYTES(value));
+ } else if (value >= GIGABYTES(1)) {
+ fmt = precise ? "%.f GiB" : "%.3f GiB";
+ snprintf(str, size, fmt, TO_GIGABYTES(value));
+ } else if (value >= MEGABYTES(1)) {
+ fmt = precise ? "%.f MiB" : "%.3f MiB";
+ snprintf(str, size, fmt, TO_MEGABYTES(value));
+ } else if (value >= KILOBYTES(1)) {
+ fmt = precise ? "%.f KiB" : "%.3f KiB";
+ snprintf(str, size, fmt, TO_KILOBYTES(value));
+ } else {
+ snprintf(str, size, "%f bytes", value);
+ }
+}
+
+struct timeval
+tsub(struct timeval t1, struct timeval t2)
+{
+ t1.tv_usec -= t2.tv_usec;
+ if (t1.tv_usec < 0) {
+ t1.tv_usec += 1000000;
+ t1.tv_sec--;
+ }
+ t1.tv_sec -= t2.tv_sec;
+ return t1;
+}
+
+double
+tdiv(double value, struct timeval tv)
+{
+ return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
+}
+
+#define HOURS(sec) ((sec) / (60 * 60))
+#define MINUTES(sec) (((sec) % (60 * 60)) / 60)
+#define SECONDS(sec) ((sec) % 60)
+
+void
+timestr(
+ struct timeval *tv,
+ char *ts,
+ size_t size,
+ int format)
+{
+ double usec = (double)tv->tv_usec / 1000000.0;
+
+ if (format & TERSE_FIXED_TIME) {
+ if (!HOURS(tv->tv_sec)) {
+ snprintf(ts, size, "%u:%02u.%02u",
+ (unsigned int) MINUTES(tv->tv_sec),
+ (unsigned int) SECONDS(tv->tv_sec),
+ (unsigned int) usec * 100);
+ return;
+ }
+ format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */
+ }
+
+ if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
+ snprintf(ts, size, "%u:%02u:%02u.%02u",
+ (unsigned int) HOURS(tv->tv_sec),
+ (unsigned int) MINUTES(tv->tv_sec),
+ (unsigned int) SECONDS(tv->tv_sec),
+ (unsigned int) usec * 100);
+ } else {
+ snprintf(ts, size, "0.%04u sec", (unsigned int) usec * 10000);
+ }
+}
+
+
+/* from libxcmd/quit.c */
+
+static cmdinfo_t quit_cmd;
+
+/* ARGSUSED */
+static int
+quit_f(
+ int argc,
+ char **argv)
+{
+ return 1;
+}
+
+void
+quit_init(void)
+{
+ quit_cmd.name = _("quit");
+ quit_cmd.altname = _("q");
+ quit_cmd.cfunc = quit_f;
+ quit_cmd.argmin = -1;
+ quit_cmd.argmax = -1;
+ quit_cmd.flags = CMD_FLAG_GLOBAL;
+ quit_cmd.oneline = _("exit the program");
+
+ add_command(&quit_cmd);
+}
+
+/* from libxcmd/help.c */
+
+static cmdinfo_t help_cmd;
+static void help_onecmd(const char *cmd, const cmdinfo_t *ct);
+static void help_oneline(const char *cmd, const cmdinfo_t *ct);
+
+static void
+help_all(void)
+{
+ const cmdinfo_t *ct;
+
+ for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++)
+ help_oneline(ct->name, ct);
+ printf(_("\nUse 'help commandname' for extended help.\n"));
+}
+
+static int
+help_f(
+ int argc,
+ char **argv)
+{
+ const cmdinfo_t *ct;
+
+ if (argc == 1) {
+ help_all();
+ return 0;
+ }
+ ct = find_command(argv[1]);
+ if (ct == NULL) {
+ printf(_("command %s not found\n"), argv[1]);
+ return 0;
+ }
+ help_onecmd(argv[1], ct);
+ return 0;
+}
+
+static void
+help_onecmd(
+ const char *cmd,
+ const cmdinfo_t *ct)
+{
+ help_oneline(cmd, ct);
+ if (ct->help)
+ ct->help();
+}
+
+static void
+help_oneline(
+ const char *cmd,
+ const cmdinfo_t *ct)
+{
+ if (cmd)
+ printf("%s ", cmd);
+ else {
+ printf("%s ", ct->name);
+ if (ct->altname)
+ printf("(or %s) ", ct->altname);
+ }
+ if (ct->args)
+ printf("%s ", ct->args);
+ printf("-- %s\n", ct->oneline);
+}
+
+void
+help_init(void)
+{
+ help_cmd.name = _("help");
+ help_cmd.altname = _("?");
+ help_cmd.cfunc = help_f;
+ help_cmd.argmin = 0;
+ help_cmd.argmax = 1;
+ help_cmd.flags = CMD_FLAG_GLOBAL;
+ help_cmd.args = _("[command]");
+ help_cmd.oneline = _("help for one or all commands");
+
+ add_command(&help_cmd);
+}
diff --git a/cmd.h b/cmd.h
new file mode 100644
index 000000000..5ca8fcf07
--- /dev/null
+++ b/cmd.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __COMMAND_H__
+#define __COMMAND_H__
+
+#define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */
+
+typedef int (*cfunc_t)(int argc, char **argv);
+typedef void (*helpfunc_t)(void);
+
+typedef struct cmdinfo {
+ const char *name;
+ const char *altname;
+ cfunc_t cfunc;
+ int argmin;
+ int argmax;
+ int canpush;
+ int flags;
+ const char *args;
+ const char *oneline;
+ helpfunc_t help;
+} cmdinfo_t;
+
+extern cmdinfo_t *cmdtab;
+extern int ncmds;
+
+extern void help_init(void);
+extern void quit_init(void);
+
+typedef int (*argsfunc_t)(int index);
+typedef int (*checkfunc_t)(const cmdinfo_t *ci);
+
+extern void add_command(const cmdinfo_t *ci);
+extern void add_user_command(char *optarg);
+extern void add_args_command(argsfunc_t af);
+extern void add_check_command(checkfunc_t cf);
+
+extern const cmdinfo_t *find_command(const char *cmd);
+
+extern void command_loop(void);
+extern int command_usage(const cmdinfo_t *ci);
+extern int command(const cmdinfo_t *ci, int argc, char **argv);
+
+/* from input.h */
+extern char **breakline(char *input, int *count);
+extern void doneline(char *input, char **vec);
+extern char *fetchline(void);
+
+extern long long cvtnum(char *s);
+extern void cvtstr(double value, char *str, size_t sz);
+
+extern struct timeval tsub(struct timeval t1, struct timeval t2);
+extern double tdiv(double value, struct timeval tv);
+
+enum {
+ DEFAULT_TIME = 0x0,
+ TERSE_FIXED_TIME = 0x1,
+ VERBOSE_FIXED_TIME = 0x2
+};
+
+extern void timestr(struct timeval *tv, char *str, size_t sz, int flags);
+
+#endif /* __COMMAND_H__ */
diff --git a/configure b/configure
index 2170d0060..8b6b69365 100755
--- a/configure
+++ b/configure
@@ -154,6 +154,7 @@ case "$cpu" in
esac
gprof="no"
sparse="no"
+strip_opt="yes"
bigendian="no"
mingw32="no"
EXESUF=""
@@ -412,6 +413,8 @@ for opt do
;;
--disable-sparse) sparse="no"
;;
+ --disable-strip) strip_opt="no"
+ ;;
--disable-vnc-tls) vnc_tls="no"
;;
--disable-vnc-sasl) vnc_sasl="no"
@@ -516,6 +519,10 @@ case "$cpu" in
ARCH_CFLAGS="${SP_CFLAGS}"
ARCH_LDFLAGS="${SP_LDFLAGS}"
fi
+ ARCH_CFLAGS="$ARCH_CFLAGS -ffixed-g2 -ffixed-g3"
+ if test "$solaris" = "no" ; then
+ ARCH_CFLAGS="$ARCH_CFLAGS -ffixed-g1 -ffixed-g6"
+ fi
;;
sparc64) if test -z "$sparc_cpu" ; then
ARCH_CFLAGS="-m64 -mcpu=ultrasparc -D__sparc_v9__"
@@ -524,6 +531,11 @@ case "$cpu" in
ARCH_CFLAGS="${SP_CFLAGS}"
ARCH_LDFLAGS="${SP_LDFLAGS}"
fi
+ if test "$solaris" = "no" ; then
+ ARCH_CFLAGS="$ARCH_CFLAGS -ffixed-g5 -ffixed-g6 -ffixed-g7"
+ else
+ ARCH_CFLAGS="$ARCH_CFLAGS -ffixed-g1 -ffixed-g5 -ffixed-g6 -ffixed-g7"
+ fi
;;
s390)
ARCH_CFLAGS="-march=z900"
@@ -565,6 +577,7 @@ echo " --install=INSTALL use specified install [$install]"
echo " --static enable static build [$static]"
echo " --enable-sparse enable sparse checker"
echo " --disable-sparse disable sparse checker (default)"
+echo " --disable-strip disable stripping binaries"
echo " --disable-werror disable compilation abort on warning"
echo " --disable-sdl disable SDL"
echo " --enable-cocoa enable COCOA (Mac OS X only)"
@@ -1266,6 +1279,7 @@ echo "host big endian $bigendian"
echo "target list $target_list"
echo "gprof enabled $gprof"
echo "sparse enabled $sparse"
+echo "strip binaries $strip_opt"
echo "profiler $profiler"
echo "static build $static"
echo "-Werror enabled $werror"
@@ -1342,7 +1356,6 @@ echo "INSTALL=$install" >> $config_mak
echo "CC=$cc" >> $config_mak
echo "HOST_CC=$host_cc" >> $config_mak
echo "AR=$ar" >> $config_mak
-echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
# XXX: only use CFLAGS and LDFLAGS ?
# XXX: should export HOST_CFLAGS and HOST_LDFLAGS for cross
# compilation of dyngen tool (useful for win32 build on Linux host)
@@ -1429,6 +1442,9 @@ if test "$sparse" = "yes" ; then
echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_mak
echo "CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_mak
fi
+if test "$strip_opt" = "yes" ; then
+ echo "STRIP_OPT=-s" >> $config_mak
+fi
if test "$bigendian" = "yes" ; then
echo "WORDS_BIGENDIAN=yes" >> $config_mak
echo "#define WORDS_BIGENDIAN 1" >> $config_h
@@ -1644,7 +1660,7 @@ tools=
if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then
tools="qemu-img\$(EXESUF) $tools"
if [ "$linux" = "yes" ] ; then
- tools="qemu-nbd\$(EXESUF) $tools"
+ tools="qemu-nbd\$(EXESUF) qemu-io\$(EXESUF) $tools"
fi
fi
echo "TOOLS=$tools" >> $config_mak
diff --git a/cpu-exec.c b/cpu-exec.c
index bf42318fb..d724464d1 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -258,6 +258,11 @@ int cpu_exec(CPUState *env1)
/* prepare setjmp context for exception handling */
for(;;) {
if (setjmp(env->jmp_env) == 0) {
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+#undef env
+ env = cpu_single_env;
+#define env cpu_single_env
+#endif
env->current_tb = NULL;
/* if an exception is pending, we execute it here */
if (env->exception_index >= 0) {
@@ -403,6 +408,11 @@ int cpu_exec(CPUState *env1)
env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
intno = cpu_get_pic_interrupt(env);
qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+#undef env
+ env = cpu_single_env;
+#define env cpu_single_env
+#endif
do_interrupt(intno, 0, 0, 0, 1);
/* ensure that no TB jump will be modified as
the program flow was changed */
diff --git a/darwin-user/main.c b/darwin-user/main.c
index 9b8a3dccc..51c6aa0f4 100644
--- a/darwin-user/main.c
+++ b/darwin-user/main.c
@@ -41,6 +41,8 @@
#include <mach/mach_init.h>
#include <mach/vm_map.h>
+int singlestep;
+
const char *interp_prefix = "";
asm(".zerofill __STD_PROG_ZONE, __STD_PROG_ZONE, __std_prog_zone, 0x0dfff000");
@@ -751,6 +753,7 @@ void usage(void)
"-d options activate log (logfile='%s')\n"
"-g wait for gdb on port 1234\n"
"-p pagesize set the host page size to 'pagesize'\n",
+ "-singlestep always run in singlestep mode\n"
TARGET_ARCH,
TARGET_ARCH,
interp_prefix,
@@ -842,6 +845,8 @@ int main(int argc, char **argv)
#endif
exit(1);
}
+ } else if (!strcmp(r, "singlestep")) {
+ singlestep = 1;
} else
{
usage();
diff --git a/exec-all.h b/exec-all.h
index 143aca184..33ccb7b44 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -384,4 +384,8 @@ static inline int kqemu_is_ok(CPUState *env)
typedef void (CPUDebugExcpHandler)(CPUState *env);
CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler);
+
+/* vl.c */
+extern int singlestep;
+
#endif
diff --git a/exec.c b/exec.c
index b77d6b8de..cc2eb044f 100644
--- a/exec.c
+++ b/exec.c
@@ -19,7 +19,6 @@
*/
#include "config.h"
#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <sys/types.h>
diff --git a/gdbstub.c b/gdbstub.c
index cbd5a7c75..955835800 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2340,27 +2340,40 @@ static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len)
return len;
}
-int gdbserver_start(const char *port)
+#ifndef _WIN32
+static void gdb_sigterm_handler(int signal)
+{
+ if (vm_running)
+ vm_stop(EXCP_INTERRUPT);
+}
+#endif
+
+int gdbserver_start(const char *device)
{
GDBState *s;
- char gdbstub_port_name[128];
- int port_num;
- char *p;
+ char gdbstub_device_name[128];
CharDriverState *chr = NULL;
CharDriverState *mon_chr;
- if (!port || !*port)
- return -1;
- if (strcmp(port, "none") != 0) {
- port_num = strtol(port, &p, 10);
- if (*p == 0) {
- /* A numeric value is interpreted as a port number. */
- snprintf(gdbstub_port_name, sizeof(gdbstub_port_name),
- "tcp::%d,nowait,nodelay,server", port_num);
- port = gdbstub_port_name;
+ if (!device)
+ return -1;
+ if (strcmp(device, "none") != 0) {
+ if (strstart(device, "tcp:", NULL)) {
+ /* enforce required TCP attributes */
+ snprintf(gdbstub_device_name, sizeof(gdbstub_device_name),
+ "%s,nowait,nodelay,server", device);
+ device = gdbstub_device_name;
}
+#ifndef _WIN32
+ else if (strcmp(device, "stdio") == 0) {
+ struct sigaction act;
- chr = qemu_chr_open("gdb", port, NULL);
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = gdb_sigterm_handler;
+ sigaction(SIGINT, &act, NULL);
+ }
+#endif
+ chr = qemu_chr_open("gdb", device, NULL);
if (!chr)
return -1;
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index dfbb59ad7..e79dd1765 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -1393,6 +1393,8 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value)
break;
}
+ vga_update_resolution((VGAState *)s);
+
return CIRRUS_HOOK_HANDLED;
}
@@ -1420,6 +1422,7 @@ static void cirrus_write_hidden_dac(CirrusVGAState * s, int reg_value)
#endif
}
s->cirrus_hidden_dac_lockindex = 0;
+ vga_update_resolution((VGAState *)s);
}
/***************************************
@@ -1706,6 +1709,8 @@ cirrus_hook_write_cr(CirrusVGAState * s, unsigned reg_index, int reg_value)
break;
}
+ vga_update_resolution((VGAState *)s);
+
return CIRRUS_HOOK_HANDLED;
}
@@ -2833,6 +2838,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (s->ar_flip_flop == 0) {
val &= 0x3f;
s->ar_index = val;
+ vga_update_resolution((VGAState *)s);
} else {
index = s->ar_index & 0x1f;
switch (index) {
@@ -2926,6 +2932,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
/* can always write bit 4 of CR7 */
if (s->cr_index == 7)
s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
+ vga_update_resolution((VGAState *)s);
return;
}
switch (s->cr_index) {
@@ -2954,6 +2961,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
s->update_retrace_info((VGAState *) s);
break;
}
+ vga_update_resolution((VGAState *)s);
break;
case 0x3ba:
case 0x3da:
@@ -3160,7 +3168,8 @@ static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id)
cirrus_update_memory_access(s);
/* force refresh */
- s->graphic_mode = -1;
+ vga_update_resolution((VGAState *)s);
+ s->want_full_update = 1;
cirrus_update_bank_ptr(s, 0);
cirrus_update_bank_ptr(s, 1);
return 0;
diff --git a/hw/framebuffer.c b/hw/framebuffer.c
new file mode 100644
index 000000000..1086ba9d0
--- /dev/null
+++ b/hw/framebuffer.c
@@ -0,0 +1,119 @@
+/*
+ * Framebuffer device helper routines
+ *
+ * Copyright (c) 2009 CodeSourcery
+ * Written by Paul Brook <paul@codesourcery.com>
+ *
+ * This code is licensed under the GNU GPLv2.
+ */
+
+/* TODO:
+ - Do something similar for framebuffers with local ram
+ - Handle rotation here instead of hacking dest_pitch
+ - Use common pixel conversion routines instead of per-device drawfn
+ - Remove all DisplayState knowledge from devices.
+ */
+
+#include "hw.h"
+#include "console.h"
+#include "framebuffer.h"
+#include "kvm.h"
+
+/* Render an image from a shared memory framebuffer. */
+
+void framebuffer_update_display(
+ DisplayState *ds,
+ target_phys_addr_t base,
+ int cols, /* Width in pixels. */
+ int rows, /* Leight in pixels. */
+ int src_width, /* Length of source line, in bytes. */
+ int dest_row_pitch, /* Bytes between adjacent horizontal output pixels. */
+ int dest_col_pitch, /* Bytes between adjacent vertical output pixels. */
+ int invalidate, /* nonzero to redraw the whole image. */
+ drawfn fn,
+ void *opaque,
+ int *first_row, /* Input and output. */
+ int *last_row /* Output only */)
+{
+ target_phys_addr_t src_len;
+ uint8_t *dest;
+ uint8_t *src;
+ uint8_t *src_base;
+ int first, last = 0;
+ int dirty;
+ int i;
+ ram_addr_t addr;
+ ram_addr_t pd;
+ ram_addr_t pd2;
+
+ i = *first_row;
+ *first_row = -1;
+ src_len = src_width * rows;
+
+ if (kvm_enabled()) {
+ kvm_physical_sync_dirty_bitmap(base, src_len);
+ }
+ pd = cpu_get_physical_page_desc(base);
+ pd2 = cpu_get_physical_page_desc(base + src_len - 1);
+ /* We should reall check that this is a continuous ram region.
+ Instead we just check that the first and last pages are
+ both ram, and the right distance apart. */
+ if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM
+ || (pd2 & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
+ return;
+ }
+ pd = (pd & TARGET_PAGE_MASK) + (base & ~TARGET_PAGE_MASK);
+ if (((pd + src_len - 1) & TARGET_PAGE_MASK) != (pd2 & TARGET_PAGE_MASK)) {
+ return;
+ }
+
+ src_base = cpu_physical_memory_map(base, &src_len, 0);
+ /* If we can't map the framebuffer then bail. We could try harder,
+ but it's not really worth it as dirty flag tracking will probably
+ already have failed above. */
+ if (!src_base)
+ return;
+ if (src_len != src_width * rows) {
+ cpu_physical_memory_unmap(src_base, src_len, 0, 0);
+ return;
+ }
+ src = src_base;
+ dest = ds_get_data(ds);
+ if (dest_col_pitch < 0)
+ dest -= dest_col_pitch * (cols - 1);
+ first = -1;
+ addr = pd;
+
+ addr += i * src_width;
+ src += i * src_width;
+ dest += i * dest_row_pitch;
+
+ for (; i < rows; i++) {
+ target_phys_addr_t dirty_offset;
+ dirty = 0;
+ dirty_offset = 0;
+ while (addr + dirty_offset < TARGET_PAGE_ALIGN(addr + src_width)) {
+ dirty |= cpu_physical_memory_get_dirty(addr + dirty_offset,
+ VGA_DIRTY_FLAG);
+ dirty_offset += TARGET_PAGE_SIZE;
+ }
+
+ if (dirty || invalidate) {
+ fn(opaque, dest, src, cols, dest_col_pitch);
+ if (first == -1)
+ first = i;
+ last = i;
+ }
+ addr += src_width;
+ src += src_width;
+ dest += dest_row_pitch;
+ }
+ cpu_physical_memory_unmap(src_base, src_len, 0, 0);
+ if (first < 0) {
+ return;
+ }
+ cpu_physical_memory_reset_dirty(pd, pd + src_len, VGA_DIRTY_FLAG);
+ *first_row = first;
+ *last_row = last;
+ return;
+}
diff --git a/hw/framebuffer.h b/hw/framebuffer.h
new file mode 100644
index 000000000..a3a214649
--- /dev/null
+++ b/hw/framebuffer.h
@@ -0,0 +1,22 @@
+#ifndef QEMU_FRAMEBUFFER_H
+#define QEMU_FRAMEBUFFER_H
+
+/* Framebuffer device helper routines. */
+
+typedef void (*drawfn)(void *, uint8_t *, const uint8_t *, int, int);
+
+void framebuffer_update_display(
+ DisplayState *ds,
+ target_phys_addr_t base,
+ int cols,
+ int rows,
+ int src_width,
+ int dest_row_pitch,
+ int dest_col_pitch,
+ int invalidate,
+ drawfn fn,
+ void *opaque,
+ int *first_row,
+ int *last_row);
+
+#endif
diff --git a/hw/hw.h b/hw/hw.h
index eab7bb4db..e9628d46f 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -67,6 +67,7 @@ unsigned int qemu_get_be32(QEMUFile *f);
uint64_t qemu_get_be64(QEMUFile *f);
int qemu_file_rate_limit(QEMUFile *f);
int qemu_file_has_error(QEMUFile *f);
+void qemu_file_set_error(QEMUFile *f);
/* Try to send any outstanding data. This function is useful when output is
* halted due to rate limiting or EAGAIN errors occur as it can be used to
diff --git a/hw/omap.h b/hw/omap.h
index 7965eb260..e94047460 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -490,7 +490,7 @@ struct omap_dma_lcd_channel_s {
int dual;
int current_frame;
- ram_addr_t phys_framebuffer[2];
+ target_phys_addr_t phys_framebuffer[2];
qemu_irq irq;
struct omap_mpu_state_s *mpu;
} *omap_dma_get_lcdch(struct soc_dma_s *s);
diff --git a/hw/omap_lcd_template.h b/hw/omap_lcd_template.h
index 4e84fa1d9..0590e4501 100644
--- a/hw/omap_lcd_template.h
+++ b/hw/omap_lcd_template.h
@@ -43,9 +43,10 @@
/*
* 2-bit colour
*/
-static void glue(draw_line2_, DEPTH)(
- uint8_t *d, const uint8_t *s, int width, const uint16_t *pal)
+static void glue(draw_line2_, DEPTH)(void *opaque,
+ uint8_t *d, const uint8_t *s, int width, int deststep)
{
+ uint16_t *pal = opaque;
uint8_t v, r, g, b;
do {
@@ -81,9 +82,10 @@ static void glue(draw_line2_, DEPTH)(
/*
* 4-bit colour
*/
-static void glue(draw_line4_, DEPTH)(
- uint8_t *d, const uint8_t *s, int width, const uint16_t *pal)
+static void glue(draw_line4_, DEPTH)(void *opaque,
+ uint8_t *d, const uint8_t *s, int width, int deststep)
{
+ uint16_t *pal = opaque;
uint8_t v, r, g, b;
do {
@@ -107,9 +109,10 @@ static void glue(draw_line4_, DEPTH)(
/*
* 8-bit colour
*/
-static void glue(draw_line8_, DEPTH)(
- uint8_t *d, const uint8_t *s, int width, const uint16_t *pal)
+static void glue(draw_line8_, DEPTH)(void *opaque,
+ uint8_t *d, const uint8_t *s, int width, int deststep)
{
+ uint16_t *pal = opaque;
uint8_t v, r, g, b;
do {
@@ -126,8 +129,8 @@ static void glue(draw_line8_, DEPTH)(
/*
* 12-bit colour
*/
-static void glue(draw_line12_, DEPTH)(
- uint8_t *d, const uint8_t *s, int width, const uint16_t *pal)
+static void glue(draw_line12_, DEPTH)(void *opaque,
+ uint8_t *d, const uint8_t *s, int width, int deststep)
{
uint16_t v;
uint8_t r, g, b;
@@ -146,8 +149,8 @@ static void glue(draw_line12_, DEPTH)(
/*
* 16-bit colour
*/
-static void glue(draw_line16_, DEPTH)(
- uint8_t *d, const uint8_t *s, int width, const uint16_t *pal)
+static void glue(draw_line16_, DEPTH)(void *opaque,
+ uint8_t *d, const uint8_t *s, int width, int deststep)
{
#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
memcpy(d, s, width * 2);
diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c
index a02d99d27..6a91b27d4 100644
--- a/hw/omap_lcdc.c
+++ b/hw/omap_lcdc.c
@@ -20,6 +20,7 @@
#include "hw.h"
#include "console.h"
#include "omap.h"
+#include "framebuffer.h"
struct omap_lcd_panel_s {
qemu_irq irq;
@@ -68,8 +69,7 @@ static void omap_lcd_interrupts(struct omap_lcd_panel_s *s)
#include "pixel_ops.h"
-typedef void draw_line_func(
- uint8_t *d, const uint8_t *s, int width, const uint16_t *pal);
+#define draw_line_func drawfn
#define DEPTH 8
#include "omap_lcd_template.h"
@@ -80,31 +80,31 @@ typedef void draw_line_func(
#define DEPTH 32
#include "omap_lcd_template.h"
-static draw_line_func *draw_line_table2[33] = {
+static draw_line_func draw_line_table2[33] = {
[0 ... 32] = 0,
[8] = draw_line2_8,
[15] = draw_line2_15,
[16] = draw_line2_16,
[32] = draw_line2_32,
-}, *draw_line_table4[33] = {
+}, draw_line_table4[33] = {
[0 ... 32] = 0,
[8] = draw_line4_8,
[15] = draw_line4_15,
[16] = draw_line4_16,
[32] = draw_line4_32,
-}, *draw_line_table8[33] = {
+}, draw_line_table8[33] = {
[0 ... 32] = 0,
[8] = draw_line8_8,
[15] = draw_line8_15,
[16] = draw_line8_16,
[32] = draw_line8_32,
-}, *draw_line_table12[33] = {
+}, draw_line_table12[33] = {
[0 ... 32] = 0,
[8] = draw_line12_8,
[15] = draw_line12_15,
[16] = draw_line12_16,
[32] = draw_line12_32,
-}, *draw_line_table16[33] = {
+}, draw_line_table16[33] = {
[0 ... 32] = 0,
[8] = draw_line16_8,
[15] = draw_line16_15,
@@ -115,11 +115,10 @@ static draw_line_func *draw_line_table2[33] = {
static void omap_update_display(void *opaque)
{
struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque;
- draw_line_func *draw_line;
- int size, dirty[2], minline, maxline, height;
- int line, width, linesize, step, bpp, frame_offset;
- ram_addr_t frame_base, scanline, newline, x;
- uint8_t *s, *d;
+ draw_line_func draw_line;
+ int size, height, first, last;
+ int width, linesize, step, bpp, frame_offset;
+ target_phys_addr_t frame_base;
if (!omap_lcd || omap_lcd->plm == 1 ||
!omap_lcd->enable || !ds_get_bits_per_pixel(omap_lcd->state))
@@ -127,9 +126,9 @@ static void omap_update_display(void *opaque)
frame_offset = 0;
if (omap_lcd->plm != 2) {
- memcpy(omap_lcd->palette, phys_ram_base +
- omap_lcd->dma->phys_framebuffer[
- omap_lcd->dma->current_frame], 0x200);
+ cpu_physical_memory_read(omap_lcd->dma->phys_framebuffer[
+ omap_lcd->dma->current_frame],
+ (void *)omap_lcd->palette, 0x200);
switch (omap_lcd->palette[0] >> 12 & 7) {
case 3 ... 7:
frame_offset += 0x200;
@@ -202,49 +201,28 @@ static void omap_update_display(void *opaque)
if (!ds_get_bits_per_pixel(omap_lcd->state))
return;
- line = 0;
+ first = 0;
height = omap_lcd->height;
if (omap_lcd->subpanel & (1 << 31)) {
if (omap_lcd->subpanel & (1 << 29))
- line = (omap_lcd->subpanel >> 16) & 0x3ff;
+ first = (omap_lcd->subpanel >> 16) & 0x3ff;
else
height = (omap_lcd->subpanel >> 16) & 0x3ff;
/* TODO: fill the rest of the panel with DPD */
}
+
step = width * bpp >> 3;
- scanline = frame_base + step * line;
- s = (uint8_t *) (phys_ram_base + scanline);
- d = ds_get_data(omap_lcd->state);
linesize = ds_get_linesize(omap_lcd->state);
-
- dirty[0] = dirty[1] =
- cpu_physical_memory_get_dirty(scanline, VGA_DIRTY_FLAG);
- minline = height;
- maxline = line;
- for (; line < height; line ++) {
- newline = scanline + step;
- for (x = scanline + TARGET_PAGE_SIZE; x < newline;
- x += TARGET_PAGE_SIZE) {
- dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG);
- dirty[0] |= dirty[1];
- }
- if (dirty[0] || omap_lcd->invalidate) {
- draw_line(d, s, width, omap_lcd->palette);
- if (line < minline)
- minline = line;
- maxline = line + 1;
- }
- scanline = newline;
- dirty[0] = dirty[1];
- s += step;
- d += linesize;
- }
-
- if (maxline >= minline) {
- dpy_update(omap_lcd->state, 0, minline, width, maxline);
- cpu_physical_memory_reset_dirty(frame_base + step * minline,
- frame_base + step * maxline, VGA_DIRTY_FLAG);
+ framebuffer_update_display(omap_lcd->state,
+ frame_base, width, height,
+ step, linesize, 0,
+ omap_lcd->invalidate,
+ draw_line, omap_lcd->palette,
+ &first, &last);
+ if (first >= 0) {
+ dpy_update(omap_lcd->state, 0, first, width, last - first + 1);
}
+ omap_lcd->invalidate = 0;
}
static int ppm_save(const char *filename, uint8_t *data,
@@ -336,25 +314,13 @@ static void omap_lcd_update(struct omap_lcd_panel_s *s) {
return;
}
- if (s->dma->src == imif) {
- /* Framebuffers are in SRAM */
- s->dma->phys_framebuffer[0] = s->imif_base +
- s->dma->src_f1_top - OMAP_IMIF_BASE;
-
- s->dma->phys_framebuffer[1] = s->imif_base +
- s->dma->src_f2_top - OMAP_IMIF_BASE;
- } else {
- /* Framebuffers are in RAM */
- s->dma->phys_framebuffer[0] = s->emiff_base +
- s->dma->src_f1_top - OMAP_EMIFF_BASE;
-
- s->dma->phys_framebuffer[1] = s->emiff_base +
- s->dma->src_f2_top - OMAP_EMIFF_BASE;
- }
+ s->dma->phys_framebuffer[0] = s->dma->src_f1_top;
+ s->dma->phys_framebuffer[1] = s->dma->src_f2_top;
if (s->plm != 2 && !s->palette_done) {
- memcpy(s->palette, phys_ram_base +
- s->dma->phys_framebuffer[s->dma->current_frame], 0x200);
+ cpu_physical_memory_read(
+ s->dma->phys_framebuffer[s->dma->current_frame],
+ (void *)s->palette, 0x200);
s->palette_done = 1;
omap_lcd_interrupts(s);
}
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index 3f01dea08..c2248c34a 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -98,19 +98,22 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, PCIBus *pci_bus,
type = IF_SCSI;
else if (!strcmp(buf, "virtio")) {
type = IF_VIRTIO;
+ } else {
+ monitor_printf(mon, "type %s not a hotpluggable PCI device.\n", buf);
+ goto out;
}
} else {
monitor_printf(mon, "no if= specified\n");
- return NULL;
+ goto out;
}
if (get_param_value(buf, sizeof(buf), "file", opts)) {
drive_idx = add_init_drive(opts);
if (drive_idx < 0)
- return NULL;
+ goto out;
} else if (type == IF_VIRTIO) {
monitor_printf(mon, "virtio requires a backing file/device.\n");
- return NULL;
+ goto out;
}
switch (type) {
@@ -123,10 +126,9 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon, PCIBus *pci_bus,
case IF_VIRTIO:
opaque = virtio_blk_init (pci_bus, drives_table[drive_idx].bdrv);
break;
- default:
- monitor_printf(mon, "type %s not a hotpluggable PCI device.\n", buf);
}
+out:
return opaque;
}
diff --git a/hw/pl110.c b/hw/pl110.c
index bc33da7d5..f21b63b0c 100644
--- a/hw/pl110.c
+++ b/hw/pl110.c
@@ -10,6 +10,7 @@
#include "hw.h"
#include "primecell.h"
#include "console.h"
+#include "framebuffer.h"
#define PL110_CR_EN 0x001
#define PL110_CR_BGR 0x100
@@ -59,32 +60,7 @@ static const unsigned char pl110_versatile_id[] =
#define pl110_versatile_id pl110_id
#endif
-static inline uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
-{
- return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
-}
-
-static inline uint32_t rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
-{
- return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
-}
-
-static inline uint32_t rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
-{
- return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
-}
-
-static inline uint32_t rgb_to_pixel24(unsigned int r, unsigned int g, unsigned b)
-{
- return (r << 16) | (g << 8) | b;
-}
-
-static inline uint32_t rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
-{
- return (r << 16) | (g << 8) | b;
-}
-
-typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int);
+#include "pixel_ops.h"
#define BITS 8
#include "pl110_template.h"
@@ -107,17 +83,11 @@ static void pl110_update_display(void *opaque)
pl110_state *s = (pl110_state *)opaque;
drawfn* fntable;
drawfn fn;
- uint32_t *pallette;
- uint32_t addr;
- uint32_t base;
int dest_width;
int src_width;
- uint8_t *dest;
- uint8_t *src;
- int first, last = 0;
- int dirty, new_dirty;
- int i;
int bpp_offset;
+ int first;
+ int last;
if (!pl110_enabled(s))
return;
@@ -182,47 +152,17 @@ static void pl110_update_display(void *opaque)
break;
}
dest_width *= s->cols;
- pallette = s->pallette;
- base = s->upbase;
- /* HACK: Arm aliases physical memory at 0x80000000. */
- if (base > 0x80000000)
- base -= 0x80000000;
- src = phys_ram_base + base;
- dest = ds_get_data(s->ds);
- first = -1;
- addr = base;
-
- dirty = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG);
- new_dirty = dirty;
- for (i = 0; i < s->rows; i++) {
- if ((addr & ~TARGET_PAGE_MASK) + src_width >= TARGET_PAGE_SIZE) {
- uint32_t tmp;
- new_dirty = 0;
- for (tmp = 0; tmp < src_width; tmp += TARGET_PAGE_SIZE) {
- new_dirty |= cpu_physical_memory_get_dirty(addr + tmp,
- VGA_DIRTY_FLAG);
- }
- }
-
- if (dirty || new_dirty || s->invalidate) {
- fn(pallette, dest, src, s->cols);
- if (first == -1)
- first = i;
- last = i;
- }
- dirty = new_dirty;
- addr += src_width;
- dest += dest_width;
- src += src_width;
+ first = 0;
+ framebuffer_update_display(s->ds,
+ s->upbase, s->cols, s->rows,
+ src_width, dest_width, 0,
+ s->invalidate,
+ fn, s->pallette,
+ &first, &last);
+ if (first >= 0) {
+ dpy_update(s->ds, 0, first, s->cols, last - first + 1);
}
- if (first < 0)
- return;
-
s->invalidate = 0;
- cpu_physical_memory_reset_dirty(base + first * src_width,
- base + (last + 1) * src_width,
- VGA_DIRTY_FLAG);
- dpy_update(s->ds, 0, first, s->cols, last - first + 1);
}
static void pl110_invalidate_display(void * opaque)
diff --git a/hw/pl110_template.h b/hw/pl110_template.h
index 33483c027..5b5f47560 100644
--- a/hw/pl110_template.h
+++ b/hw/pl110_template.h
@@ -115,8 +115,9 @@ static drawfn glue(pl110_draw_fn_,BITS)[36] =
#define FN_4(x, y) FN_2(x, y) FN_2(x+2, y)
#define FN_8(y) FN_4(0, y) FN_4(4, y)
-static void glue(pl110_draw_line1_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
+static void glue(pl110_draw_line1_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
+ uint32_t *pallette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *)src;
@@ -142,8 +143,9 @@ static void glue(pl110_draw_line1_,NAME)(uint32_t *pallette, uint8_t *d, const u
}
}
-static void glue(pl110_draw_line2_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
+static void glue(pl110_draw_line2_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
+ uint32_t *pallette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *)src;
@@ -169,8 +171,9 @@ static void glue(pl110_draw_line2_,NAME)(uint32_t *pallette, uint8_t *d, const u
}
}
-static void glue(pl110_draw_line4_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
+static void glue(pl110_draw_line4_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
+ uint32_t *pallette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *)src;
@@ -196,8 +199,9 @@ static void glue(pl110_draw_line4_,NAME)(uint32_t *pallette, uint8_t *d, const u
}
}
-static void glue(pl110_draw_line8_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
+static void glue(pl110_draw_line8_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
+ uint32_t *pallette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *)src;
@@ -219,7 +223,7 @@ static void glue(pl110_draw_line8_,NAME)(uint32_t *pallette, uint8_t *d, const u
}
}
-static void glue(pl110_draw_line16_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
+static void glue(pl110_draw_line16_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
uint32_t data;
unsigned int r, g, b;
@@ -265,7 +269,7 @@ static void glue(pl110_draw_line16_,NAME)(uint32_t *pallette, uint8_t *d, const
}
}
-static void glue(pl110_draw_line32_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
+static void glue(pl110_draw_line32_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
{
uint32_t data;
unsigned int r, g, b;
diff --git a/hw/ptimer.c b/hw/ptimer.c
index 9d3862724..f1994bd2b 100644
--- a/hw/ptimer.c
+++ b/hw/ptimer.c
@@ -7,7 +7,7 @@
*/
#include "hw.h"
#include "qemu-timer.h"
-
+#include "host-utils.h"
struct ptimer_state
{
@@ -78,9 +78,38 @@ uint64_t ptimer_get_count(ptimer_state *s)
} else {
uint64_t rem;
uint64_t div;
+ int clz1, clz2;
+ int shift;
+
+ /* We need to divide time by period, where time is stored in
+ rem (64-bit integer) and period is stored in period/period_frac
+ (64.32 fixed point).
+
+ Doing full precision division is hard, so scale values and
+ do a 64-bit division. The result should be rounded down,
+ so that the rounding error never causes the timer to go
+ backwards.
+ */
rem = s->next_event - now;
div = s->period;
+
+ clz1 = clz64(rem);
+ clz2 = clz64(div);
+ shift = clz1 < clz2 ? clz1 : clz2;
+
+ rem <<= shift;
+ div <<= shift;
+ if (shift >= 32) {
+ div |= ((uint64_t)s->period_frac << (shift - 32));
+ } else {
+ if (shift != 0)
+ div |= (s->period_frac >> (32 - shift));
+ /* Look at remaining bits of period_frac and round div up if
+ necessary. */
+ if ((uint32_t)(s->period_frac << shift))
+ div += 1;
+ }
counter = rem / div;
}
} else {
diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c
index 5c2eff10e..49eafa722 100644
--- a/hw/pxa2xx_lcd.c
+++ b/hw/pxa2xx_lcd.c
@@ -13,8 +13,7 @@
#include "pixel_ops.h"
/* FIXME: For graphic_rotate. Should probably be done in common code. */
#include "sysemu.h"
-
-typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int, int);
+#include "framebuffer.h"
struct pxa2xx_lcdc_s {
qemu_irq irq;
@@ -56,7 +55,7 @@ struct pxa2xx_lcdc_s {
int up;
uint8_t palette[1024];
uint8_t pbuffer[1024];
- void (*redraw)(struct pxa2xx_lcdc_s *s, uint8_t *fb,
+ void (*redraw)(struct pxa2xx_lcdc_s *s, target_phys_addr_t addr,
int *miny, int *maxy);
target_phys_addr_t descriptor;
@@ -669,18 +668,15 @@ static void pxa2xx_palette_parse(struct pxa2xx_lcdc_s *s, int ch, int bpp)
}
static void pxa2xx_lcdc_dma0_redraw_horiz(struct pxa2xx_lcdc_s *s,
- uint8_t *fb, int *miny, int *maxy)
+ target_phys_addr_t addr, int *miny, int *maxy)
{
- int y, src_width, dest_width, dirty[2];
- uint8_t *src, *dest;
- ram_addr_t x, addr, new_addr, start, end;
+ int src_width, dest_width;
drawfn fn = 0;
if (s->dest_width)
fn = s->line_fn[s->transp][s->bpp];
if (!fn)
return;
- src = fb;
src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
src_width *= 3;
@@ -689,54 +685,25 @@ static void pxa2xx_lcdc_dma0_redraw_horiz(struct pxa2xx_lcdc_s *s,
else if (s->bpp > pxa_lcdc_8bpp)
src_width *= 2;
- dest = ds_get_data(s->ds);
dest_width = s->xres * s->dest_width;
-
- addr = (ram_addr_t) (fb - phys_ram_base);
- start = addr + s->yres * src_width;
- end = addr;
- dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG);
- for (y = 0; y < s->yres; y ++) {
- new_addr = addr + src_width;
- for (x = addr + TARGET_PAGE_SIZE; x < new_addr;
- x += TARGET_PAGE_SIZE) {
- dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG);
- dirty[0] |= dirty[1];
- }
- if (dirty[0] || s->invalidated) {
- fn((uint32_t *) s->dma_ch[0].palette,
- dest, src, s->xres, s->dest_width);
- if (addr < start)
- start = addr;
- end = new_addr;
- if (y < *miny)
- *miny = y;
- if (y >= *maxy)
- *maxy = y + 1;
- }
- addr = new_addr;
- dirty[0] = dirty[1];
- src += src_width;
- dest += dest_width;
- }
-
- if (end > start)
- cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG);
+ *miny = 0;
+ framebuffer_update_display(s->ds,
+ addr, s->xres, s->yres,
+ src_width, dest_width, s->dest_width,
+ s->invalidated,
+ fn, s->dma_ch[0].palette, miny, maxy);
}
static void pxa2xx_lcdc_dma0_redraw_vert(struct pxa2xx_lcdc_s *s,
- uint8_t *fb, int *miny, int *maxy)
+ target_phys_addr_t addr, int *miny, int *maxy)
{
- int y, src_width, dest_width, dirty[2];
- uint8_t *src, *dest;
- ram_addr_t x, addr, new_addr, start, end;
+ int src_width, dest_width;
drawfn fn = 0;
if (s->dest_width)
fn = s->line_fn[s->transp][s->bpp];
if (!fn)
return;
- src = fb;
src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
src_width *= 3;
@@ -746,38 +713,13 @@ static void pxa2xx_lcdc_dma0_redraw_vert(struct pxa2xx_lcdc_s *s,
src_width *= 2;
dest_width = s->yres * s->dest_width;
- dest = ds_get_data(s->ds) + dest_width * (s->xres - 1);
-
- addr = (ram_addr_t) (fb - phys_ram_base);
- start = addr + s->yres * src_width;
- end = addr;
- x = addr + TARGET_PAGE_SIZE;
- dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG);
- for (y = 0; y < s->yres; y ++) {
- new_addr = addr + src_width;
- for (; x < new_addr; x += TARGET_PAGE_SIZE) {
- dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG);
- dirty[0] |= dirty[1];
- }
- if (dirty[0] || s->invalidated) {
- fn((uint32_t *) s->dma_ch[0].palette,
- dest, src, s->xres, -dest_width);
- if (addr < start)
- start = addr;
- end = new_addr;
- if (y < *miny)
- *miny = y;
- if (y >= *maxy)
- *maxy = y + 1;
- }
- addr = new_addr;
- dirty[0] = dirty[1];
- src += src_width;
- dest += s->dest_width;
- }
-
- if (end > start)
- cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG);
+ *miny = 0;
+ framebuffer_update_display(s->ds,
+ addr, s->xres, s->yres,
+ src_width, s->dest_width, -dest_width,
+ s->invalidated,
+ fn, s->dma_ch[0].palette,
+ miny, maxy);
}
static void pxa2xx_lcdc_resize(struct pxa2xx_lcdc_s *s)
@@ -803,7 +745,6 @@ static void pxa2xx_lcdc_resize(struct pxa2xx_lcdc_s *s)
static void pxa2xx_update_display(void *opaque)
{
struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
- uint8_t *fb;
target_phys_addr_t fbptr;
int miny, maxy;
int ch;
@@ -829,13 +770,11 @@ static void pxa2xx_update_display(void *opaque)
pxa2xx_dma_ber_set(s, ch);
continue;
}
- fbptr -= PXA2XX_SDRAM_BASE;
- fb = phys_ram_base + fbptr;
if (s->dma_ch[ch].command & LDCMD_PAL) {
- memcpy(s->dma_ch[ch].pbuffer, fb,
- MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
- sizeof(s->dma_ch[ch].pbuffer)));
+ cpu_physical_memory_read(fbptr, s->dma_ch[ch].pbuffer,
+ MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
+ sizeof(s->dma_ch[ch].pbuffer)));
pxa2xx_palette_parse(s, ch, s->bpp);
} else {
/* Do we need to reparse palette */
@@ -845,7 +784,7 @@ static void pxa2xx_update_display(void *opaque)
/* ACK frame start */
pxa2xx_dma_sof_set(s, ch);
- s->dma_ch[ch].redraw(s, fb, &miny, &maxy);
+ s->dma_ch[ch].redraw(s, fbptr, &miny, &maxy);
s->invalidated = 0;
/* ACK frame completed */
@@ -859,10 +798,12 @@ static void pxa2xx_update_display(void *opaque)
s->status[0] |= LCSR0_LDD;
}
- if (s->orientation)
- dpy_update(s->ds, miny, 0, maxy, s->xres);
- else
- dpy_update(s->ds, 0, miny, s->xres, maxy);
+ if (miny >= 0) {
+ if (s->orientation)
+ dpy_update(s->ds, miny, 0, maxy, s->xres);
+ else
+ dpy_update(s->ds, 0, miny, s->xres, maxy);
+ }
pxa2xx_lcdc_int_update(s);
qemu_irq_raise(s->vsync_cb);
diff --git a/hw/pxa2xx_template.h b/hw/pxa2xx_template.h
index 903df7b38..35312ec29 100644
--- a/hw/pxa2xx_template.h
+++ b/hw/pxa2xx_template.h
@@ -30,9 +30,10 @@
#define FN_2(x) FN(x + 1) FN(x)
#define FN_4(x) FN_2(x + 2) FN_2(x)
-static void glue(pxa2xx_draw_line2_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line2_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
+ uint32_t *palette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *) src;
@@ -54,9 +55,10 @@ static void glue(pxa2xx_draw_line2_, BITS)(uint32_t *palette,
}
}
-static void glue(pxa2xx_draw_line4_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line4_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
+ uint32_t *palette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *) src;
@@ -78,9 +80,10 @@ static void glue(pxa2xx_draw_line4_, BITS)(uint32_t *palette,
}
}
-static void glue(pxa2xx_draw_line8_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line8_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
+ uint32_t *palette = opaque;
uint32_t data;
while (width > 0) {
data = *(uint32_t *) src;
@@ -102,7 +105,7 @@ static void glue(pxa2xx_draw_line8_, BITS)(uint32_t *palette,
}
}
-static void glue(pxa2xx_draw_line16_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line16_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data;
@@ -130,7 +133,7 @@ static void glue(pxa2xx_draw_line16_, BITS)(uint32_t *palette,
}
}
-static void glue(pxa2xx_draw_line16t_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line16t_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data;
@@ -166,7 +169,7 @@ static void glue(pxa2xx_draw_line16t_, BITS)(uint32_t *palette,
}
}
-static void glue(pxa2xx_draw_line18_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line18_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data;
@@ -188,7 +191,7 @@ static void glue(pxa2xx_draw_line18_, BITS)(uint32_t *palette,
}
/* The wicked packed format */
-static void glue(pxa2xx_draw_line18p_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line18p_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data[3];
@@ -236,7 +239,7 @@ static void glue(pxa2xx_draw_line18p_, BITS)(uint32_t *palette,
}
}
-static void glue(pxa2xx_draw_line19_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line19_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data;
@@ -262,7 +265,7 @@ static void glue(pxa2xx_draw_line19_, BITS)(uint32_t *palette,
}
/* The wicked packed format */
-static void glue(pxa2xx_draw_line19p_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line19p_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data[3];
@@ -326,7 +329,7 @@ static void glue(pxa2xx_draw_line19p_, BITS)(uint32_t *palette,
}
}
-static void glue(pxa2xx_draw_line24_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line24_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data;
@@ -347,7 +350,7 @@ static void glue(pxa2xx_draw_line24_, BITS)(uint32_t *palette,
}
}
-static void glue(pxa2xx_draw_line24t_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line24t_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data;
@@ -372,7 +375,7 @@ static void glue(pxa2xx_draw_line24t_, BITS)(uint32_t *palette,
}
}
-static void glue(pxa2xx_draw_line25_, BITS)(uint32_t *palette,
+static void glue(pxa2xx_draw_line25_, BITS)(void *opaque,
uint8_t *dest, const uint8_t *src, int width, int deststep)
{
uint32_t data;
diff --git a/hw/vga.c b/hw/vga.c
index 1b6af239f..4a081ce28 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -37,6 +37,10 @@
//#define DEBUG_BOCHS_VBE
+#define GMODE_TEXT 0
+#define GMODE_GRAPH 1
+#define GMODE_BLANK 2
+
/* force some bits to zero */
const uint8_t sr_mask[8] = {
0x03,
@@ -394,6 +398,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (s->ar_flip_flop == 0) {
val &= 0x3f;
s->ar_index = val;
+ vga_update_resolution(s);
} else {
index = s->ar_index & 0x1f;
switch(index) {
@@ -434,6 +439,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
if (s->sr_index == 1) s->update_retrace_info(s);
+ vga_update_resolution(s);
break;
case 0x3c7:
s->dac_read_index = val;
@@ -461,6 +467,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+ vga_update_resolution(s);
break;
case 0x3b4:
case 0x3d4:
@@ -476,6 +483,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
/* can always write bit 4 of CR7 */
if (s->cr_index == 7)
s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
+ vga_update_resolution(s);
return;
}
switch(s->cr_index) {
@@ -503,6 +511,7 @@ static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
s->update_retrace_info(s);
break;
}
+ vga_update_resolution(s);
break;
case 0x3ba:
case 0x3da:
@@ -582,11 +591,13 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
s->vbe_regs[s->vbe_index] = val;
}
+ vga_update_resolution(s);
break;
case VBE_DISPI_INDEX_YRES:
if (val <= VBE_DISPI_MAX_YRES) {
s->vbe_regs[s->vbe_index] = val;
}
+ vga_update_resolution(s);
break;
case VBE_DISPI_INDEX_BPP:
if (val == 0)
@@ -595,6 +606,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
val == 16 || val == 24 || val == 32) {
s->vbe_regs[s->vbe_index] = val;
}
+ vga_update_resolution(s);
break;
case VBE_DISPI_INDEX_BANK:
if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
@@ -663,6 +675,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
}
s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
s->vbe_regs[s->vbe_index] = val;
+ vga_update_resolution(s);
break;
case VBE_DISPI_INDEX_VIRT_WIDTH:
{
@@ -683,6 +696,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
s->vbe_line_offset = line_offset;
}
+ vga_update_resolution(s);
break;
case VBE_DISPI_INDEX_X_OFFSET:
case VBE_DISPI_INDEX_Y_OFFSET:
@@ -697,6 +711,7 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
s->vbe_start_addr >>= 2;
}
+ vga_update_resolution(s);
break;
default:
break;
@@ -1303,7 +1318,6 @@ static void vga_draw_text(VGAState *s, int full_update)
s->plane_updated = 0;
full_update = 1;
}
- full_update |= update_basic_params(s);
line_offset = s->line_offset;
s1 = s->vram_ptr + (s->start_addr * 4);
@@ -1315,18 +1329,6 @@ static void vga_draw_text(VGAState *s, int full_update)
return;
}
- if (width != s->last_width || height != s->last_height ||
- cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
- s->last_scr_width = width * cw;
- s->last_scr_height = height * cheight;
- qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
- s->last_depth = 0;
- s->last_width = width;
- s->last_height = height;
- s->last_ch = cheight;
- s->last_cw = cw;
- full_update = 1;
- }
s->rgb_to_pixel =
rgb_to_pixel_dup_table[get_depth_index(s->ds)];
full_update |= update_palette16(s);
@@ -1583,40 +1585,21 @@ static void vga_sync_dirty_bitmap(VGAState *s)
vga_dirty_log_start(s);
}
-/*
- * graphic modes
- */
-static void vga_draw_graphic(VGAState *s, int full_update)
+static void vga_update_resolution_graphics(VGAState *s)
{
- int y1, y, update, linesize, y_start, double_scan, mask, depth;
- int width, height, shift_control, line_offset, bwidth, bits;
+ int depth = s->get_bpp(s);
+ int width, height, shift_control, double_scan;
int disp_width, multi_scan, multi_run;
- uint8_t *d;
- uint32_t v, addr1, addr;
- long page0, page1, page_min, page_max;
- vga_draw_line_func *vga_draw_line;
-
- full_update |= update_basic_params(s);
-
- if (!full_update)
- vga_sync_dirty_bitmap(s);
s->get_resolution(s, &width, &height);
disp_width = width;
shift_control = (s->gr[0x05] >> 5) & 3;
double_scan = (s->cr[0x09] >> 7);
- if (shift_control != 1) {
- multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
- } else {
- /* in CGA modes, multi_scan is ignored */
- /* XXX: is it correct ? */
- multi_scan = double_scan;
- }
- multi_run = multi_scan;
+
if (shift_control != s->shift_control ||
double_scan != s->double_scan) {
- full_update = 1;
+ s->want_full_update = 1;
s->shift_control = shift_control;
s->double_scan = double_scan;
}
@@ -1630,12 +1613,28 @@ static void vga_draw_graphic(VGAState *s, int full_update)
disp_width <<= 1;
}
}
+ disp_width = width;
+
+ if (shift_control != 1) {
+ multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
+ } else {
+ /* in CGA modes, multi_scan is ignored */
+ /* XXX: is it correct ? */
+ multi_scan = double_scan;
+ }
+
+ multi_run = multi_scan;
- depth = s->get_bpp(s);
if (s->line_offset != s->last_line_offset ||
disp_width != s->last_width ||
height != s->last_height ||
- s->last_depth != depth) {
+ s->last_depth != depth ||
+ s->multi_run != multi_run ||
+ s->multi_scan != multi_scan ||
+ s->want_full_update) {
+ if (s->ds->surface->pf.depth == 0) {
+ goto dont_touch_display_surface;
+ }
#if defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
if (depth == 16 || depth == 32) {
#else
@@ -1652,14 +1651,91 @@ static void vga_draw_graphic(VGAState *s, int full_update)
} else {
qemu_console_resize(s->ds, disp_width, height);
}
+ dont_touch_display_surface:
s->last_scr_width = disp_width;
s->last_scr_height = height;
s->last_width = disp_width;
s->last_height = height;
s->last_line_offset = s->line_offset;
s->last_depth = depth;
- full_update = 1;
- } else if (is_buffer_shared(s->ds->surface) &&
+ s->multi_run = multi_run;
+ s->multi_scan = multi_scan;
+ s->want_full_update = 1;
+ }
+}
+
+static void vga_update_resolution_text(VGAState *s)
+{
+ int width, height, cw, cheight;
+
+ vga_get_text_resolution(s, &width, &height, &cw, &cheight);
+ if (width != s->last_width || height != s->last_height ||
+ cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
+ s->last_scr_width = width * cw;
+ s->last_scr_height = height * cheight;
+ if (s->ds->surface->pf.depth != 0) {
+ qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
+ } else {
+ /*
+ * curses expects width and height to be in character cell
+ * dimensions, not pixels.
+ */
+ s->ds->surface->width = width;
+ s->ds->surface->height = height;
+ dpy_resize(s->ds);
+ }
+ s->last_depth = 0;
+ s->last_width = width;
+ s->last_height = height;
+ s->last_ch = cheight;
+ s->last_cw = cw;
+ s->want_full_update = 1;
+ }
+}
+
+void vga_update_resolution(VGAState *s)
+{
+ int graphic_mode;
+
+ if (!(s->ar_index & 0x20)) {
+ graphic_mode = GMODE_BLANK;
+ } else {
+ graphic_mode = s->gr[6] & 1;
+ }
+ if (graphic_mode != s->graphic_mode) {
+ s->graphic_mode = graphic_mode;
+ s->want_full_update = 1;
+ }
+ s->want_full_update |= update_basic_params(s);
+ switch (graphic_mode) {
+ case GMODE_TEXT:
+ vga_update_resolution_text(s);
+ break;
+ case GMODE_GRAPH:
+ vga_update_resolution_graphics(s);
+ break;
+ }
+}
+
+/*
+ * graphic modes
+ */
+static void vga_draw_graphic(VGAState *s, int full_update)
+{
+ int y1, y, update, linesize, y_start, mask;
+ int width, height, line_offset, bwidth, bits;
+ int multi_run;
+ uint8_t *d;
+ uint32_t v, addr1, addr;
+ long page0, page1, page_min, page_max;
+ vga_draw_line_func *vga_draw_line;
+
+ if (!full_update)
+ vga_sync_dirty_bitmap(s);
+
+ s->get_resolution(s, &width, &height);
+ multi_run = s->multi_run;
+ if (is_buffer_shared(s->ds->surface) &&
(full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
dpy_setdata(s->ds);
@@ -1668,7 +1744,7 @@ static void vga_draw_graphic(VGAState *s, int full_update)
s->rgb_to_pixel =
rgb_to_pixel_dup_table[get_depth_index(s->ds)];
- if (shift_control == 0) {
+ if (s->shift_control == 0) {
full_update |= update_palette16(s);
if (s->sr[0x01] & 8) {
v = VGA_DRAW_LINE4D2;
@@ -1676,7 +1752,7 @@ static void vga_draw_graphic(VGAState *s, int full_update)
v = VGA_DRAW_LINE4;
}
bits = 4;
- } else if (shift_control == 1) {
+ } else if (s->shift_control == 1) {
full_update |= update_palette16(s);
if (s->sr[0x01] & 8) {
v = VGA_DRAW_LINE2D2;
@@ -1772,7 +1848,7 @@ static void vga_draw_graphic(VGAState *s, int full_update)
if (y_start >= 0) {
/* flush to display */
dpy_update(s->ds, 0, y_start,
- disp_width, y - y_start);
+ s->last_width, y - y_start);
y_start = -1;
}
}
@@ -1781,7 +1857,7 @@ static void vga_draw_graphic(VGAState *s, int full_update)
if ((y1 & mask) == mask)
addr1 += line_offset;
y1++;
- multi_run = multi_scan;
+ multi_run = s->multi_scan;
} else {
multi_run--;
}
@@ -1793,7 +1869,7 @@ static void vga_draw_graphic(VGAState *s, int full_update)
if (y_start >= 0) {
/* flush to display */
dpy_update(s->ds, 0, y_start,
- disp_width, y - y_start);
+ s->last_width, y - y_start);
}
/* reset modified pages */
if (page_max != -1) {
@@ -1830,29 +1906,17 @@ static void vga_draw_blank(VGAState *s, int full_update)
s->last_scr_width, s->last_scr_height);
}
-#define GMODE_TEXT 0
-#define GMODE_GRAPH 1
-#define GMODE_BLANK 2
-
static void vga_update_display(void *opaque)
{
VGAState *s = (VGAState *)opaque;
- int full_update, graphic_mode;
+ int full_update;
if (ds_get_bits_per_pixel(s->ds) == 0) {
/* nothing to do */
} else {
- full_update = 0;
- if (!(s->ar_index & 0x20)) {
- graphic_mode = GMODE_BLANK;
- } else {
- graphic_mode = s->gr[6] & 1;
- }
- if (graphic_mode != s->graphic_mode) {
- s->graphic_mode = graphic_mode;
- full_update = 1;
- }
- switch(graphic_mode) {
+ full_update = s->want_full_update;
+ s->want_full_update = 0;
+ switch(s->graphic_mode) {
case GMODE_TEXT:
vga_draw_text(s, full_update);
break;
@@ -1875,8 +1939,8 @@ static void vga_invalidate_display(void *opaque)
{
VGAState *s = (VGAState *)opaque;
- s->last_width = -1;
- s->last_height = -1;
+ vga_update_resolution(s);
+ s->want_full_update = 1;
}
void vga_reset(void *opaque)
@@ -1920,7 +1984,6 @@ void vga_reset(void *opaque)
s->vbe_bank_mask = (s->vram_size >> 16) - 1;
#endif
memset(s->font_offsets, '\0', sizeof(s->font_offsets));
- s->graphic_mode = -1; /* force full update */
s->shift_control = 0;
s->double_scan = 0;
s->line_offset = 0;
@@ -1946,6 +2009,7 @@ void vga_reset(void *opaque)
memset(&s->retrace_info, 0, sizeof (s->retrace_info));
break;
}
+ vga_update_resolution(s);
}
#define TEXTMODE_X(x) ((x) % width)
@@ -1957,50 +2021,28 @@ void vga_reset(void *opaque)
static void vga_update_text(void *opaque, console_ch_t *chardata)
{
VGAState *s = (VGAState *) opaque;
- int graphic_mode, i, cursor_offset, cursor_visible;
+ int i, cursor_offset, cursor_visible;
int cw, cheight, width, height, size, c_min, c_max;
uint32_t *src;
console_ch_t *dst, val;
char msg_buffer[80];
- int full_update = 0;
+ int full_update = s->want_full_update;
- if (!(s->ar_index & 0x20)) {
- graphic_mode = GMODE_BLANK;
- } else {
- graphic_mode = s->gr[6] & 1;
- }
- if (graphic_mode != s->graphic_mode) {
- s->graphic_mode = graphic_mode;
- full_update = 1;
- }
- if (s->last_width == -1) {
- s->last_width = 0;
- full_update = 1;
- }
-
- switch (graphic_mode) {
+ s->want_full_update = 0;
+ switch (s->graphic_mode) {
case GMODE_TEXT:
/* TODO: update palette */
- full_update |= update_basic_params(s);
- /* total width & height */
- cheight = (s->cr[9] & 0x1f) + 1;
- cw = 8;
- if (!(s->sr[1] & 0x01))
- cw = 9;
- if (s->sr[1] & 0x08)
- cw = 16; /* NOTE: no 18 pixel wide */
- width = (s->cr[0x01] + 1);
- if (s->cr[0x06] == 100) {
- /* ugly hack for CGA 160x100x16 - explain me the logic */
- height = 100;
- } else {
- height = s->cr[0x12] |
- ((s->cr[0x07] & 0x02) << 7) |
- ((s->cr[0x07] & 0x40) << 3);
- height = (height + 1) / cheight;
+ vga_get_text_resolution(s, &width, &height, &cw, &cheight);
+
+ if (s->ds->surface->width != width
+ || s->ds->surface->height != height) {
+ s->ds->surface->width = width;
+ s->ds->surface->height = height;
+ dpy_resize(s->ds);
}
+ /* total width & height */
size = (height * width);
if (size > CH_ATTR_SIZE) {
if (!full_update)
@@ -2011,20 +2053,6 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
break;
}
- if (width != s->last_width || height != s->last_height ||
- cw != s->last_cw || cheight != s->last_ch) {
- s->last_scr_width = width * cw;
- s->last_scr_height = height * cheight;
- s->ds->surface->width = width;
- s->ds->surface->height = height;
- dpy_resize(s->ds);
- s->last_width = width;
- s->last_height = height;
- s->last_ch = cheight;
- s->last_cw = cw;
- full_update = 1;
- }
-
/* Update "hardware" cursor */
cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
if (cursor_offset != s->cursor_offset ||
@@ -2223,7 +2251,8 @@ static int vga_load(QEMUFile *f, void *opaque, int version_id)
#endif
/* force refresh */
- s->graphic_mode = -1;
+ vga_update_resolution(s);
+ s->want_full_update = 1;
return 0;
}
@@ -2419,6 +2448,8 @@ void vga_bios_init(VGAState *s)
s->bank_offset = 0;
s->graphic_mode = -1;
+ vga_update_resolution(s);
+
/* TODO: add vbe support if enabled */
}
#endif
@@ -2803,7 +2834,8 @@ static void vga_screen_dump_common(VGAState *s, const char *filename,
ds->surface = qemu_create_displaysurface(ds, w, h);
s->ds = ds;
- s->graphic_mode = -1;
+ vga_update_resolution(s);
+ s->want_full_update = 1;
vga_update_display(s);
ppm_save(filename, ds->surface);
@@ -2834,10 +2866,16 @@ static void vga_screen_dump(void *opaque, const char *filename)
{
VGAState *s = (VGAState *)opaque;
- if (!(s->ar_index & 0x20))
- vga_screen_dump_blank(s, filename);
- else if (s->gr[6] & 1)
- vga_screen_dump_graphic(s, filename);
- else
+ switch (s->graphic_mode) {
+ case GMODE_TEXT:
vga_screen_dump_text(s, filename);
+ break;
+ case GMODE_GRAPH:
+ vga_screen_dump_graphic(s, filename);
+ break;
+ case GMODE_BLANK:
+ default:
+ vga_screen_dump_blank(s, filename);
+ break;
+ }
}
diff --git a/hw/vga_int.h b/hw/vga_int.h
index 8ba8a60f2..71ffeb569 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -147,8 +147,11 @@ typedef void (* vga_update_retrace_info_fn)(struct VGAState *s);
DisplayState *ds; \
uint32_t font_offsets[2]; \
int graphic_mode; \
+ int want_full_update; \
uint8_t shift_control; \
uint8_t double_scan; \
+ uint8_t multi_run; \
+ uint8_t multi_scan; \
uint32_t line_offset; \
uint32_t line_compare; \
uint32_t start_addr; \
@@ -195,6 +198,7 @@ void vga_common_init(VGAState *s, uint8_t *vga_ram_base,
ram_addr_t vga_ram_offset, int vga_ram_size);
void vga_init(VGAState *s);
void vga_reset(void *s);
+void vga_update_resolution(VGAState *s);
void vga_dirty_log_start(VGAState *s);
void vga_dirty_log_stop(VGAState *s);
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 9bce3a059..ef7789b05 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -136,6 +136,21 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev)
return features;
}
+static uint32_t virtio_net_bad_features(VirtIODevice *vdev)
+{
+ uint32_t features = 0;
+
+ /* Linux kernel 2.6.25. It understood MAC (as everyone must),
+ * but also these: */
+ features |= (1 << VIRTIO_NET_F_MAC);
+ features |= (1 << VIRTIO_NET_F_GUEST_CSUM);
+ features |= (1 << VIRTIO_NET_F_GUEST_TSO4);
+ features |= (1 << VIRTIO_NET_F_GUEST_TSO6);
+ features |= (1 << VIRTIO_NET_F_GUEST_ECN);
+
+ return features & virtio_net_get_features(vdev);
+}
+
static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features)
{
VirtIONet *n = to_virtio_net(vdev);
@@ -674,6 +689,7 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn)
n->vdev.set_config = virtio_net_set_config;
n->vdev.get_features = virtio_net_get_features;
n->vdev.set_features = virtio_net_set_features;
+ n->vdev.bad_features = virtio_net_bad_features;
n->vdev.reset = virtio_net_reset;
n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx);
diff --git a/hw/virtio.c b/hw/virtio.c
index 8a72d8d21..93a7de689 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -451,6 +451,13 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
switch (addr) {
case VIRTIO_PCI_GUEST_FEATURES:
+ /* Guest does not negotiate properly? We have to assume nothing. */
+ if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
+ if (vdev->bad_features)
+ val = vdev->bad_features(vdev);
+ else
+ val = 0;
+ }
if (vdev->set_features)
vdev->set_features(vdev, val);
vdev->features = val;
@@ -490,7 +497,7 @@ static uint32_t virtio_ioport_read(void *opaque, uint32_t addr)
switch (addr) {
case VIRTIO_PCI_HOST_FEATURES:
ret = vdev->get_features(vdev);
- ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
+ ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY) | (1 << VIRTIO_F_BAD_FEATURE);
break;
case VIRTIO_PCI_GUEST_FEATURES:
ret = vdev->features;
diff --git a/hw/virtio.h b/hw/virtio.h
index 18c7a1a7c..cce8a4747 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -32,6 +32,8 @@
/* We notify when the ring is completely used, even if the guest is supressing
* callbacks */
#define VIRTIO_F_NOTIFY_ON_EMPTY 24
+/* A guest should never accept this. It implies negotiation is broken. */
+#define VIRTIO_F_BAD_FEATURE 30
/* from Linux's linux/virtio_ring.h */
@@ -82,6 +84,7 @@ struct VirtIODevice
size_t config_len;
void *config;
uint32_t (*get_features)(VirtIODevice *vdev);
+ uint32_t (*bad_features)(VirtIODevice *vdev);
void (*set_features)(VirtIODevice *vdev, uint32_t val);
void (*get_config)(VirtIODevice *vdev, uint8_t *config);
void (*set_config)(VirtIODevice *vdev, const uint8_t *config);
diff --git a/linux-user/main.c b/linux-user/main.c
index 153318129..3235381b5 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -39,6 +39,8 @@
char *exec_path;
+int singlestep;
+
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
const char *cpu_vendor_string = NULL;
@@ -2218,6 +2220,7 @@ static void usage(void)
"Debug options:\n"
"-d options activate log (logfile=%s)\n"
"-p pagesize set the host page size to 'pagesize'\n"
+ "-singlestep always run in singlestep mode\n"
"-strace log system calls\n"
"\n"
"Environment variables:\n"
@@ -2360,6 +2363,8 @@ int main(int argc, char **argv, char **envp)
}
} else if (!strcmp(r, "drop-ld-preload")) {
(void) envlist_unsetenv(envlist, "LD_PRELOAD");
+ } else if (!strcmp(r, "singlestep")) {
+ singlestep = 1;
} else if (!strcmp(r, "strace")) {
do_strace = 1;
} else
diff --git a/migration.c b/migration.c
index b3904b2d4..859d94543 100644
--- a/migration.c
+++ b/migration.c
@@ -220,13 +220,19 @@ void migrate_fd_put_ready(void *opaque)
dprintf("iterate\n");
if (qemu_savevm_state_iterate(s->file) == 1) {
+ int state;
dprintf("done iterating\n");
vm_stop(0);
bdrv_flush_all();
- qemu_savevm_state_complete(s->file);
- s->state = MIG_STATE_COMPLETED;
+ if ((qemu_savevm_state_complete(s->file)) < 0) {
+ vm_start();
+ state = MIG_STATE_ERROR;
+ } else {
+ state = MIG_STATE_COMPLETED;
+ }
migrate_fd_cleanup(s);
+ s->state = state;
}
}
diff --git a/monitor.c b/monitor.c
index ab5de15a9..b3ea22ac6 100644
--- a/monitor.c
+++ b/monitor.c
@@ -547,6 +547,17 @@ static void do_log(Monitor *mon, const char *items)
cpu_set_log(mask);
}
+static void do_singlestep(Monitor *mon, const char *option)
+{
+ if (!option || !strcmp(option, "on")) {
+ singlestep = 1;
+ } else if (!strcmp(option, "off")) {
+ singlestep = 0;
+ } else {
+ monitor_printf(mon, "unexpected option %s\n", option);
+ }
+}
+
static void do_stop(Monitor *mon)
{
vm_stop(EXCP_INTERRUPT);
@@ -590,17 +601,18 @@ static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs)
}
#ifdef CONFIG_GDBSTUB
-static void do_gdbserver(Monitor *mon, const char *port)
-{
- if (!port)
- port = DEFAULT_GDBSTUB_PORT;
- if (gdbserver_start(port) < 0) {
- monitor_printf(mon, "Could not open gdbserver socket on port '%s'\n",
- port);
- } else if (strcmp(port, "none") == 0) {
+static void do_gdbserver(Monitor *mon, const char *device)
+{
+ if (!device)
+ device = "tcp::" DEFAULT_GDBSTUB_PORT;
+ if (gdbserver_start(device) < 0) {
+ monitor_printf(mon, "Could not open gdbserver on device '%s'\n",
+ device);
+ } else if (strcmp(device, "none") == 0) {
monitor_printf(mon, "Disabled gdbserver\n");
} else {
- monitor_printf(mon, "Waiting gdb connection on port '%s'\n", port);
+ monitor_printf(mon, "Waiting for gdb connection on device '%s'\n",
+ device);
}
}
#endif
@@ -1533,9 +1545,13 @@ static void do_inject_nmi(Monitor *mon, int cpu_index)
static void do_info_status(Monitor *mon)
{
- if (vm_running)
- monitor_printf(mon, "VM status: running\n");
- else
+ if (vm_running) {
+ if (singlestep) {
+ monitor_printf(mon, "VM status: running (single step mode)\n");
+ } else {
+ monitor_printf(mon, "VM status: running\n");
+ }
+ } else
monitor_printf(mon, "VM status: paused\n");
}
@@ -1666,6 +1682,8 @@ static const mon_cmd_t mon_cmds[] = {
"tag|id", "restore a VM snapshot from its tag or id" },
{ "delvm", "s", do_delvm,
"tag|id", "delete a VM snapshot from its tag or id" },
+ { "singlestep", "s?", do_singlestep,
+ "[on|off]", "run emulation in singlestep mode or switch to normal mode", },
{ "stop", "", do_stop,
"", "stop emulation", },
{ "c|cont", "", do_cont,
diff --git a/nbd.c b/nbd.c
index 77b3e1692..1586ea755 100644
--- a/nbd.c
+++ b/nbd.c
@@ -579,7 +579,7 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
if ((request.from + request.len) > size) {
LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
", Offset: %" PRIu64 "\n",
- request.from, request.len, size, dev_offset);
+ request.from, request.len, (uint64_t)size, dev_offset);
LOG("requested operation past EOF--bad client?");
errno = EINVAL;
return -1;
diff --git a/net.c b/net.c
index 703d01ca6..9c199d666 100644
--- a/net.c
+++ b/net.c
@@ -2087,9 +2087,9 @@ done:
void net_cleanup(void)
{
+#if !defined(_WIN32)
VLANState *vlan;
-#if !defined(_WIN32)
/* close network clients */
for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
VLANClientState *vc;
diff --git a/pc-bios/README b/pc-bios/README
index 4b9b2c5bb..162dfe807 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -42,7 +42,7 @@
firmware implementation. The goal is to implement a 100% IEEE
1275-1994 (referred to as Open Firmware) compliant firmware.
The included images for Sparc32, Sparc64 and PowerPC (for 32 and 64 bit
- PPC CPUs) are built from OpenBIOS SVN revision 479.
+ PPC CPUs) are built from OpenBIOS SVN revision 482.
- The PXE roms come from Rom-o-Matic etherboot 5.4.2.
pcnet32:pcnet32 -- [0x1022,0x2000]
diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc
index d0fa6c930..00d9a78eb 100644
--- a/pc-bios/openbios-ppc
+++ b/pc-bios/openbios-ppc
Binary files differ
diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32
index 8f6289e05..7c84965b7 100644
--- a/pc-bios/openbios-sparc32
+++ b/pc-bios/openbios-sparc32
Binary files differ
diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64
index b23d3bbb2..76886f49c 100644
--- a/pc-bios/openbios-sparc64
+++ b/pc-bios/openbios-sparc64
Binary files differ
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 61a08eeae..3742b4598 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -490,6 +490,10 @@ Set the whole virtual machine to the snapshot identified by the tag
@item delvm @var{tag}|@var{id}
Delete the snapshot identified by @var{tag} or @var{id}.
+@item singlestep [off]
+Run the emulation in single step mode.
+If called with option off, the emulation returns to normal mode.
+
@item stop
Stop emulation.
@@ -2370,6 +2374,8 @@ Activate log (logfile=/tmp/qemu.log)
Act as if the host page size was 'pagesize' bytes
@item -g port
Wait gdb connection to port
+@item -singlestep
+Run the emulation in single step mode.
@end table
Environment variables:
@@ -2488,6 +2494,8 @@ Debug options:
Activate log (logfile=/tmp/qemu.log)
@item -p pagesize
Act as if the host page size was 'pagesize' bytes
+@item -singlestep
+Run the emulation in single step mode.
@end table
@node BSD User space emulator
@@ -2550,6 +2558,8 @@ Debug options:
Activate log (logfile=/tmp/qemu.log)
@item -p pagesize
Act as if the host page size was 'pagesize' bytes
+@item -singlestep
+Run the emulation in single step mode.
@end table
@node compilation
diff --git a/qemu-img.c b/qemu-img.c
index ab380c8a4..913ad34bf 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -493,7 +493,7 @@ static int img_convert(int argc, char **argv)
ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags);
if (ret < 0) {
if (ret == -ENOTSUP) {
- error("Formatting not supported for file format '%s'", fmt);
+ error("Formatting not supported for file format '%s'", out_fmt);
} else {
error("Error while formatting '%s'", out_filename);
}
@@ -592,18 +592,17 @@ static int img_convert(int argc, char **argv)
if (n > bs_offset + bs_sectors - sector_num)
n = bs_offset + bs_sectors - sector_num;
- /* If the output image is being created as a copy on write image,
- assume that sectors which are unallocated in the input image
- are present in both the output's and input's base images (no
- need to copy them). */
- if (out_baseimg) {
- if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset, n, &n1)) {
- sector_num += n1;
- continue;
- }
- /* The next 'n1' sectors are allocated in the input image. Copy
- only those as they may be followed by unallocated sectors. */
- n = n1;
+ if (drv != &bdrv_host_device) {
+ if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset,
+ n, &n1)) {
+ sector_num += n1;
+ continue;
+ }
+ /* The next 'n1' sectors are allocated in the input image. Copy
+ only those as they may be followed by unallocated sectors. */
+ n = n1;
+ } else {
+ n1 = n;
}
if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0)
@@ -615,8 +614,13 @@ static int img_convert(int argc, char **argv)
while (n > 0) {
/* If the output image is being created as a copy on write image,
copy all sectors even the ones containing only NUL bytes,
- because they may differ from the sectors in the base image. */
- if (out_baseimg || is_allocated_sectors(buf1, n, &n1)) {
+ because they may differ from the sectors in the base image.
+
+ If the output is to a host device, we also write out
+ sectors that are entirely 0, since whatever data was
+ already there is garbage, not 0s. */
+ if (drv == &bdrv_host_device || out_baseimg ||
+ is_allocated_sectors(buf1, n, &n1)) {
if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
error("error while writing");
}
diff --git a/qemu-io.c b/qemu-io.c
new file mode 100644
index 000000000..466d22cb3
--- /dev/null
+++ b/qemu-io.c
@@ -0,0 +1,1074 @@
+/*
+ * Command line utility to exercise the QEMU I/O path.
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (c) 2003-2005 Silicon Graphics, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <getopt.h>
+
+#include "qemu-common.h"
+#include "block_int.h"
+#include "cmd.h"
+
+#define VERSION "0.0.1"
+
+#define CMD_NOFILE_OK 0x01
+
+char *progname;
+static BlockDriverState *bs;
+
+static int misalign;
+
+/*
+ * Memory allocation helpers.
+ *
+ * Make sure memory is aligned by default, or purposefully misaligned if
+ * that is specified on the command line.
+ */
+
+#define MISALIGN_OFFSET 16
+static void *qemu_io_alloc(size_t len, int pattern)
+{
+ void *buf;
+
+ if (misalign)
+ len += MISALIGN_OFFSET;
+ buf = qemu_memalign(512, len);
+ memset(buf, pattern, len);
+ if (misalign)
+ buf += MISALIGN_OFFSET;
+ return buf;
+}
+
+static void qemu_io_free(void *p)
+{
+ if (misalign)
+ p -= MISALIGN_OFFSET;
+ qemu_vfree(p);
+}
+
+static void
+dump_buffer(char *buffer, int64_t offset, int len)
+{
+ int i, j;
+ char *p;
+
+ for (i = 0, p = buffer; i < len; i += 16) {
+ char *s = p;
+
+ printf("%08llx: ", (unsigned long long)offset + i);
+ for (j = 0; j < 16 && i + j < len; j++, p++)
+ printf("%02x ", *p);
+ printf(" ");
+ for (j = 0; j < 16 && i + j < len; j++, s++) {
+ if (isalnum((int)*s))
+ printf("%c", *s);
+ else
+ printf(".");
+ }
+ printf("\n");
+ }
+}
+
+static void
+print_report(const char *op, struct timeval *t, int64_t offset,
+ int count, int total, int cnt, int Cflag)
+{
+ char s1[64], s2[64], ts[64];
+
+ timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
+ if (!Cflag) {
+ cvtstr((double)total, s1, sizeof(s1));
+ cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
+ printf("%s %d/%d bytes at offset %lld\n",
+ op, total, count, (long long)offset);
+ printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
+ s1, cnt, ts, s2, tdiv((double)cnt, *t));
+ } else {/* bytes,ops,time,bytes/sec,ops/sec */
+ printf("%d,%d,%s,%.3f,%.3f\n",
+ total, cnt, ts,
+ tdiv((double)total, *t),
+ tdiv((double)cnt, *t));
+ }
+}
+
+static int do_read(char *buf, int64_t offset, int count, int *total)
+{
+ int ret;
+
+ ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+ if (ret < 0)
+ return ret;
+ *total = count;
+ return 1;
+}
+
+static int do_write(char *buf, int64_t offset, int count, int *total)
+{
+ int ret;
+
+ ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+ if (ret < 0)
+ return ret;
+ *total = count;
+ return 1;
+}
+
+static int do_pread(char *buf, int64_t offset, int count, int *total)
+{
+ *total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
+ if (*total < 0)
+ return *total;
+ return 1;
+}
+
+static int do_pwrite(char *buf, int64_t offset, int count, int *total)
+{
+ *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
+ if (*total < 0)
+ return *total;
+ return 1;
+}
+
+#define NOT_DONE 0x7fffffff
+static void aio_rw_done(void *opaque, int ret)
+{
+ *(int *)opaque = ret;
+}
+
+static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
+{
+ BlockDriverAIOCB *acb;
+ int async_ret = NOT_DONE;
+
+ acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
+ aio_rw_done, &async_ret);
+ if (!acb)
+ return -EIO;
+
+ while (async_ret == NOT_DONE)
+ qemu_aio_wait();
+
+ *total = qiov->size;
+ return async_ret < 0 ? async_ret : 1;
+}
+
+static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total)
+{
+ BlockDriverAIOCB *acb;
+ int async_ret = NOT_DONE;
+
+ acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
+ aio_rw_done, &async_ret);
+ if (!acb)
+ return -EIO;
+
+ while (async_ret == NOT_DONE)
+ qemu_aio_wait();
+
+ *total = qiov->size >> 9;
+ return async_ret < 0 ? async_ret : 1;
+}
+
+
+static const cmdinfo_t read_cmd;
+
+static void
+read_help(void)
+{
+ printf(
+"\n"
+" reads a range of bytes from the given offset\n"
+"\n"
+" Example:\n"
+" 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n"
+"\n"
+" Reads a segment of the currently open file, optionally dumping it to the\n"
+" standard output stream (with -v option) for subsequent inspection.\n"
+" -p, -- use bdrv_pread to read the file\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -v, -- dump buffer to standard output\n"
+" -q, -- quite mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int
+read_f(int argc, char **argv)
+{
+ struct timeval t1, t2;
+ int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
+ int c, cnt;
+ char *buf;
+ int64_t offset;
+ int count, total;
+
+ while ((c = getopt(argc, argv, "Cpqv")) != EOF) {
+ switch (c) {
+ case 'C':
+ Cflag = 1;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ default:
+ return command_usage(&read_cmd);
+ }
+ }
+
+ if (optind != argc - 2)
+ return command_usage(&read_cmd);
+
+ offset = cvtnum(argv[optind]);
+ if (offset < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ return 0;
+ }
+
+ optind++;
+ count = cvtnum(argv[optind]);
+ if (count < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ return 0;
+ }
+
+ if (!pflag)
+ if (offset & 0x1ff) {
+ printf("offset %lld is not sector aligned\n",
+ (long long)offset);
+ return 0;
+
+ if (count & 0x1ff) {
+ printf("count %d is not sector aligned\n",
+ count);
+ return 0;
+ }
+ }
+
+ buf = qemu_io_alloc(count, 0xab);
+
+ gettimeofday(&t1, NULL);
+ if (pflag)
+ cnt = do_pread(buf, offset, count, &total);
+ else
+ cnt = do_read(buf, offset, count, &total);
+ gettimeofday(&t2, NULL);
+
+ if (cnt < 0) {
+ printf("read failed: %s\n", strerror(-cnt));
+ return 0;
+ }
+
+ if (qflag)
+ return 0;
+
+ if (vflag)
+ dump_buffer(buf, offset, count);
+
+ /* Finally, report back -- -C gives a parsable format */
+ t2 = tsub(t2, t1);
+ print_report("read", &t2, offset, count, total, cnt, Cflag);
+
+ qemu_io_free(buf);
+
+ return 0;
+}
+
+static const cmdinfo_t read_cmd = {
+ .name = "read",
+ .altname = "r",
+ .cfunc = read_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-aCpqv] off len",
+ .oneline = "reads a number of bytes at a specified offset",
+ .help = read_help,
+};
+
+static const cmdinfo_t readv_cmd;
+
+static void
+readv_help(void)
+{
+ printf(
+"\n"
+" reads a range of bytes from the given offset into multiple buffers\n"
+"\n"
+" Example:\n"
+" 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
+"\n"
+" Reads a segment of the currently open file, optionally dumping it to the\n"
+" standard output stream (with -v option) for subsequent inspection.\n"
+" Uses multiple iovec buffers if more than one byte range is specified.\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -v, -- dump buffer to standard output\n"
+" -q, -- quite mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int
+readv_f(int argc, char **argv)
+{
+ struct timeval t1, t2;
+ int Cflag = 0, qflag = 0, vflag = 0;
+ int c, cnt;
+ char *buf, *p;
+ int64_t offset;
+ int count = 0, total;
+ int nr_iov, i;
+ QEMUIOVector qiov;
+
+ while ((c = getopt(argc, argv, "Cqv")) != EOF) {
+ switch (c) {
+ case 'C':
+ Cflag = 1;
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ default:
+ return command_usage(&readv_cmd);
+ }
+ }
+
+ if (optind > argc - 2)
+ return command_usage(&readv_cmd);
+
+
+ offset = cvtnum(argv[optind]);
+ if (offset < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ return 0;
+ }
+ optind++;
+
+ if (offset & 0x1ff) {
+ printf("offset %lld is not sector aligned\n",
+ (long long)offset);
+ return 0;
+ }
+
+ if (count & 0x1ff) {
+ printf("count %d is not sector aligned\n",
+ count);
+ return 0;
+ }
+
+ for (i = optind; i < argc; i++) {
+ size_t len;
+
+ len = cvtnum(argv[i]);
+ if (len < 0) {
+ printf("non-numeric length argument -- %s\n", argv[i]);
+ return 0;
+ }
+ count += len;
+ }
+
+ nr_iov = argc - optind;
+ qemu_iovec_init(&qiov, nr_iov);
+ buf = p = qemu_io_alloc(count, 0xab);
+ for (i = 0; i < nr_iov; i++) {
+ size_t len;
+
+ len = cvtnum(argv[optind]);
+ if (len < 0) {
+ printf("non-numeric length argument -- %s\n",
+ argv[optind]);
+ return 0;
+ }
+
+ qemu_iovec_add(&qiov, p, len);
+ p += len;
+ optind++;
+ }
+
+ gettimeofday(&t1, NULL);
+ cnt = do_aio_readv(&qiov, offset, &total);
+ gettimeofday(&t2, NULL);
+
+ if (cnt < 0) {
+ printf("readv failed: %s\n", strerror(-cnt));
+ return 0;
+ }
+
+ if (qflag)
+ return 0;
+
+ if (vflag)
+ dump_buffer(buf, offset, qiov.size);
+
+ /* Finally, report back -- -C gives a parsable format */
+ t2 = tsub(t2, t1);
+ print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
+
+ qemu_io_free(buf);
+
+ return 0;
+}
+
+static const cmdinfo_t readv_cmd = {
+ .name = "readv",
+ .cfunc = readv_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-Cqv] off len [len..]",
+ .oneline = "reads a number of bytes at a specified offset",
+ .help = readv_help,
+};
+
+static const cmdinfo_t write_cmd;
+
+static void
+write_help(void)
+{
+ printf(
+"\n"
+" writes a range of bytes from the given offset\n"
+"\n"
+" Example:\n"
+" 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n"
+"\n"
+" Writes into a segment of the currently open file, using a buffer\n"
+" filled with a set pattern (0xcdcdcdcd).\n"
+" -p, -- use bdrv_pwrite to write the file\n"
+" -P, -- use different pattern to fill file\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quite mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int
+write_f(int argc, char **argv)
+{
+ struct timeval t1, t2;
+ int Cflag = 0, pflag = 0, qflag = 0;
+ int c, cnt;
+ char *buf;
+ int64_t offset;
+ int count, total;
+ int pattern = 0xcd;
+
+ while ((c = getopt(argc, argv, "CpP:q")) != EOF) {
+ switch (c) {
+ case 'C':
+ Cflag = 1;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'P':
+ pattern = atoi(optarg);
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ default:
+ return command_usage(&write_cmd);
+ }
+ }
+
+ if (optind != argc - 2)
+ return command_usage(&write_cmd);
+
+ offset = cvtnum(argv[optind]);
+ if (offset < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ return 0;
+ }
+
+ optind++;
+ count = cvtnum(argv[optind]);
+ if (count < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ return 0;
+ }
+
+ if (!pflag) {
+ if (offset & 0x1ff) {
+ printf("offset %lld is not sector aligned\n",
+ (long long)offset);
+ return 0;
+ }
+
+ if (count & 0x1ff) {
+ printf("count %d is not sector aligned\n",
+ count);
+ return 0;
+ }
+ }
+
+ buf = qemu_io_alloc(count, pattern);
+
+ gettimeofday(&t1, NULL);
+ if (pflag)
+ cnt = do_pwrite(buf, offset, count, &total);
+ else
+ cnt = do_write(buf, offset, count, &total);
+ gettimeofday(&t2, NULL);
+
+ if (cnt < 0) {
+ printf("write failed: %s\n", strerror(-cnt));
+ return 0;
+ }
+
+ if (qflag)
+ return 0;
+
+ /* Finally, report back -- -C gives a parsable format */
+ t2 = tsub(t2, t1);
+ print_report("wrote", &t2, offset, count, total, cnt, Cflag);
+
+ qemu_io_free(buf);
+
+ return 0;
+}
+
+static const cmdinfo_t write_cmd = {
+ .name = "write",
+ .altname = "w",
+ .cfunc = write_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-aCpq] [-P pattern ] off len",
+ .oneline = "writes a number of bytes at a specified offset",
+ .help = write_help,
+};
+
+static const cmdinfo_t writev_cmd;
+
+static void
+writev_help(void)
+{
+ printf(
+"\n"
+" writes a range of bytes from the given offset source from multiple buffers\n"
+"\n"
+" Example:\n"
+" 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
+"\n"
+" Writes into a segment of the currently open file, using a buffer\n"
+" filled with a set pattern (0xcdcdcdcd).\n"
+" -P, -- use different pattern to fill file\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quite mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int
+writev_f(int argc, char **argv)
+{
+ struct timeval t1, t2;
+ int Cflag = 0, qflag = 0;
+ int c, cnt;
+ char *buf, *p;
+ int64_t offset;
+ int count = 0, total;
+ int nr_iov, i;
+ int pattern = 0xcd;
+ QEMUIOVector qiov;
+
+ while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+ switch (c) {
+ case 'C':
+ Cflag = 1;
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'P':
+ pattern = atoi(optarg);
+ break;
+ default:
+ return command_usage(&writev_cmd);
+ }
+ }
+
+ if (optind > argc - 2)
+ return command_usage(&writev_cmd);
+
+ offset = cvtnum(argv[optind]);
+ if (offset < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ return 0;
+ }
+ optind++;
+
+ if (offset & 0x1ff) {
+ printf("offset %lld is not sector aligned\n",
+ (long long)offset);
+ return 0;
+ }
+
+ if (count & 0x1ff) {
+ printf("count %d is not sector aligned\n",
+ count);
+ return 0;
+ }
+
+
+ for (i = optind; i < argc; i++) {
+ size_t len;
+
+ len = cvtnum(argv[optind]);
+ if (len < 0) {
+ printf("non-numeric length argument -- %s\n", argv[i]);
+ return 0;
+ }
+ count += len;
+ }
+
+ nr_iov = argc - optind;
+ qemu_iovec_init(&qiov, nr_iov);
+ buf = p = qemu_io_alloc(count, 0xab);
+ for (i = 0; i < nr_iov; i++) {
+ size_t len;
+
+ len = cvtnum(argv[optind]);
+ if (len < 0) {
+ printf("non-numeric length argument -- %s\n",
+ argv[optind]);
+ return 0;
+ }
+
+ qemu_iovec_add(&qiov, p, len);
+ p += len;
+ optind++;
+ }
+
+ gettimeofday(&t1, NULL);
+ cnt = do_aio_writev(&qiov, offset, &total);
+ gettimeofday(&t2, NULL);
+
+ if (cnt < 0) {
+ printf("writev failed: %s\n", strerror(-cnt));
+ return 0;
+ }
+
+ if (qflag)
+ return 0;
+
+ /* Finally, report back -- -C gives a parsable format */
+ t2 = tsub(t2, t1);
+ print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
+
+ qemu_io_free(buf);
+
+ return 0;
+}
+
+static const cmdinfo_t writev_cmd = {
+ .name = "writev",
+ .cfunc = writev_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-Cq] [-P pattern ] off len [len..]",
+ .oneline = "writes a number of bytes at a specified offset",
+ .help = writev_help,
+};
+
+static int
+flush_f(int argc, char **argv)
+{
+ bdrv_flush(bs);
+ return 0;
+}
+
+static const cmdinfo_t flush_cmd = {
+ .name = "flush",
+ .altname = "f",
+ .cfunc = flush_f,
+ .oneline = "flush all in-core file state to disk",
+};
+
+static int
+truncate_f(int argc, char **argv)
+{
+ int64_t offset;
+ int ret;
+
+ offset = cvtnum(argv[1]);
+ if (offset < 0) {
+ printf("non-numeric truncate argument -- %s\n", argv[1]);
+ return 0;
+ }
+
+ ret = bdrv_truncate(bs, offset);
+ if (ret < 0) {
+ printf("truncate: %s", strerror(ret));
+ return 0;
+ }
+
+ return 0;
+}
+
+static const cmdinfo_t truncate_cmd = {
+ .name = "truncate",
+ .altname = "t",
+ .cfunc = truncate_f,
+ .argmin = 1,
+ .argmax = 1,
+ .args = "off",
+ .oneline = "truncates the current file at the given offset",
+};
+
+static int
+length_f(int argc, char **argv)
+{
+ int64_t size;
+ char s1[64];
+
+ size = bdrv_getlength(bs);
+ if (size < 0) {
+ printf("getlength: %s", strerror(size));
+ return 0;
+ }
+
+ cvtstr(size, s1, sizeof(s1));
+ printf("%s\n", s1);
+ return 0;
+}
+
+
+static const cmdinfo_t length_cmd = {
+ .name = "length",
+ .altname = "l",
+ .cfunc = length_f,
+ .oneline = "gets the length of the current file",
+};
+
+
+static int
+info_f(int argc, char **argv)
+{
+ BlockDriverInfo bdi;
+ char s1[64], s2[64];
+ int ret;
+
+ if (bs->drv && bs->drv->format_name)
+ printf("format name: %s\n", bs->drv->format_name);
+ if (bs->drv && bs->drv->protocol_name)
+ printf("format name: %s\n", bs->drv->protocol_name);
+
+ ret = bdrv_get_info(bs, &bdi);
+ if (ret)
+ return 0;
+
+ cvtstr(bdi.cluster_size, s1, sizeof(s1));
+ cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
+
+ printf("cluster size: %s\n", s1);
+ printf("vm state offset: %s\n", s2);
+
+ return 0;
+}
+
+
+
+static const cmdinfo_t info_cmd = {
+ .name = "info",
+ .altname = "i",
+ .cfunc = info_f,
+ .oneline = "prints information about the current file",
+};
+
+static int
+alloc_f(int argc, char **argv)
+{
+ int64_t offset;
+ int nb_sectors;
+ char s1[64];
+ int num;
+ int ret;
+
+ offset = cvtnum(argv[1]);
+ if (offset & 0x1ff) {
+ printf("offset %lld is not sector aligned\n",
+ (long long)offset);
+ return 0;
+ }
+
+ if (argc == 3)
+ nb_sectors = cvtnum(argv[2]);
+ else
+ nb_sectors = 1;
+
+ ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
+ if (ret) {
+ printf("is_allocated: %s", strerror(ret));
+ return 0;
+ }
+
+ cvtstr(offset, s1, sizeof(s1));
+
+ if (nb_sectors == 1)
+ printf("sector allocated at offset %s\n", s1);
+ else
+ printf("%d/%d sectors allocated at offset %s\n",
+ num, nb_sectors, s1);
+ return 0;
+}
+
+static const cmdinfo_t alloc_cmd = {
+ .name = "alloc",
+ .altname = "a",
+ .argmin = 1,
+ .argmax = 2,
+ .cfunc = alloc_f,
+ .args = "off [sectors]",
+ .oneline = "checks if a sector is present in the file",
+};
+
+static int
+close_f(int argc, char **argv)
+{
+ bdrv_close(bs);
+ bs = NULL;
+ return 0;
+}
+
+static const cmdinfo_t close_cmd = {
+ .name = "close",
+ .altname = "c",
+ .cfunc = close_f,
+ .oneline = "close the current open file",
+};
+
+static int openfile(char *name, int flags)
+{
+ if (bs) {
+ fprintf(stderr, "file open already, try 'help close'\n");
+ return 1;
+ }
+
+ bs = bdrv_new("hda");
+ if (!bs)
+ return 1;
+
+ if (bdrv_open(bs, name, flags) == -1) {
+ fprintf(stderr, "%s: can't open device %s\n", progname, name);
+ bs = NULL;
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+open_help(void)
+{
+ printf(
+"\n"
+" opens a new file in the requested mode\n"
+"\n"
+" Example:\n"
+" 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"
+"\n"
+" Opens a file for subsequent use by all of the other qemu-io commands.\n"
+" -C, -- create new file if it doesn't exist\n"
+" -r, -- open file read-only\n"
+" -s, -- use snapshot file\n"
+" -n, -- disable host cache\n"
+"\n");
+}
+
+static const cmdinfo_t open_cmd;
+
+static int
+open_f(int argc, char **argv)
+{
+ int flags = 0;
+ int readonly = 0;
+ int c;
+
+ while ((c = getopt(argc, argv, "snCr")) != EOF) {
+ switch (c) {
+ case 's':
+ flags |= BDRV_O_SNAPSHOT;
+ break;
+ case 'n':
+ flags |= BDRV_O_NOCACHE;
+ break;
+ case 'C':
+ flags |= BDRV_O_CREAT;
+ break;
+ case 'r':
+ readonly = 1;
+ break;
+ default:
+ return command_usage(&open_cmd);
+ }
+ }
+
+ if (readonly)
+ flags |= BDRV_O_RDONLY;
+ else
+ flags |= BDRV_O_RDWR;
+
+ if (optind != argc - 1)
+ return command_usage(&open_cmd);
+
+ return openfile(argv[optind], flags);
+}
+
+static const cmdinfo_t open_cmd = {
+ .name = "open",
+ .altname = "o",
+ .cfunc = open_f,
+ .argmin = 1,
+ .argmax = -1,
+ .flags = CMD_NOFILE_OK,
+ .args = "[-Crsn] [path]",
+ .oneline = "open the file specified by path",
+ .help = open_help,
+};
+
+static int
+init_args_command(
+ int index)
+{
+ /* only one device allowed so far */
+ if (index >= 1)
+ return 0;
+ return ++index;
+}
+
+static int
+init_check_command(
+ const cmdinfo_t *ct)
+{
+ if (ct->flags & CMD_FLAG_GLOBAL)
+ return 1;
+ if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
+ fprintf(stderr, "no file open, try 'help open'\n");
+ return 0;
+ }
+ return 1;
+}
+
+static void usage(const char *name)
+{
+ printf(
+"Usage: %s [-h] [-V] [-Crsnm] [-c cmd] ... [file]\n"
+"QEMU Disk excerciser\n"
+"\n"
+" -C, --create create new file if it doesn't exist\n"
+" -c, --cmd command to execute\n"
+" -r, --read-only export read-only\n"
+" -s, --snapshot use snapshot file\n"
+" -n, --nocache disable host cache\n"
+" -m, --misalign misalign allocations for O_DIRECT\n"
+" -h, --help display this help and exit\n"
+" -V, --version output version information and exit\n"
+"\n",
+ name);
+}
+
+
+int main(int argc, char **argv)
+{
+ int readonly = 0;
+ const char *sopt = "hVc:Crsnm";
+ struct option lopt[] = {
+ { "help", 0, 0, 'h' },
+ { "version", 0, 0, 'V' },
+ { "offset", 1, 0, 'o' },
+ { "cmd", 1, 0, 'c' },
+ { "create", 0, 0, 'C' },
+ { "read-only", 0, 0, 'r' },
+ { "snapshot", 0, 0, 's' },
+ { "nocache", 0, 0, 'n' },
+ { "misalign", 0, 0, 'm' },
+ { NULL, 0, 0, 0 }
+ };
+ int c;
+ int opt_index = 0;
+ int flags = 0;
+
+ progname = basename(argv[0]);
+
+ while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
+ switch (c) {
+ case 's':
+ flags |= BDRV_O_SNAPSHOT;
+ break;
+ case 'n':
+ flags |= BDRV_O_NOCACHE;
+ break;
+ case 'c':
+ add_user_command(optarg);
+ break;
+ case 'C':
+ flags |= BDRV_O_CREAT;
+ break;
+ case 'r':
+ readonly = 1;
+ break;
+ case 'm':
+ misalign = 1;
+ break;
+ case 'V':
+ printf("%s version %s\n", progname, VERSION);
+ exit(0);
+ case 'h':
+ usage(progname);
+ exit(0);
+ default:
+ usage(progname);
+ exit(1);
+ }
+ }
+
+ if ((argc - optind) > 1) {
+ usage(progname);
+ exit(1);
+ }
+
+ bdrv_init();
+
+ /* initialize commands */
+ quit_init();
+ help_init();
+ add_command(&open_cmd);
+ add_command(&close_cmd);
+ add_command(&read_cmd);
+ add_command(&readv_cmd);
+ add_command(&write_cmd);
+ add_command(&writev_cmd);
+ add_command(&flush_cmd);
+ add_command(&truncate_cmd);
+ add_command(&length_cmd);
+ add_command(&info_cmd);
+ add_command(&alloc_cmd);
+
+ add_args_command(init_args_command);
+ add_check_command(init_check_command);
+
+ /* open the device */
+ if (readonly)
+ flags |= BDRV_O_RDONLY;
+ else
+ flags |= BDRV_O_RDWR;
+
+ if ((argc - optind) == 1)
+ openfile(argv[optind], flags);
+ command_loop();
+
+ if (bs)
+ bdrv_close(bs);
+ return 0;
+}
diff --git a/qemu-options.hx b/qemu-options.hx
index bb4c8e6ce..ba7f29192 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -228,10 +228,8 @@ a suffix of ``M'' or ``G'' can be used to signify a value in megabytes or
gigabytes respectively.
ETEXI
-#ifndef _WIN32
DEF("k", HAS_ARG, QEMU_OPTION_k,
"-k language use keyboard layout (for example 'fr' for French)\n")
-#endif
STEXI
@item -k @var{language}
@@ -1209,6 +1207,13 @@ Store the QEMU process PID in @var{file}. It is useful if you launch QEMU
from a script.
ETEXI
+DEF("singlestep", 0, QEMU_OPTION_singlestep, \
+ "-singlestep always run in singlestep mode\n")
+STEXI
+@item -singlestep
+Run the emulation in single step mode.
+ETEXI
+
DEF("S", 0, QEMU_OPTION_S, \
"-S freeze CPU at startup (use 'c' to start execution)\n")
STEXI
@@ -1216,19 +1221,25 @@ STEXI
Do not start CPU at startup (you must type 'c' in the monitor).
ETEXI
-DEF("s", 0, QEMU_OPTION_s, \
- "-s wait gdb connection to port\n")
+DEF("gdb", HAS_ARG, QEMU_OPTION_gdb, \
+ "-gdb dev wait for gdb connection on 'dev'\n")
STEXI
-@item -s
-Wait gdb connection to port 1234 (@pxref{gdb_usage}).
+@item -gdb @var{dev}
+Wait for gdb connection on device @var{dev} (@pxref{gdb_usage}). Typical
+connections will likely be TCP-based, but also UDP, pseudo TTY, or even
+stdio are reasonable use case. The latter is allowing to start qemu from
+within gdb and establish the connection via a pipe:
+@example
+(gdb) target remote | exec qemu -gdb stdio ...
+@end example
ETEXI
-DEF("p", HAS_ARG, QEMU_OPTION_p, \
- "-p port set gdb connection port [default=%s]\n")
+DEF("s", 0, QEMU_OPTION_s, \
+ "-s shorthand for -gdb tcp::%s\n")
STEXI
-@item -p @var{port}
-Change gdb connection port. @var{port} can be either a decimal number
-to specify a TCP port, or a host device (same devices as the serial port).
+@item -s
+Shorthand for -gdb tcp::1234, i.e. open a gdbserver on TCP port 1234
+(@pxref{gdb_usage}).
ETEXI
DEF("d", HAS_ARG, QEMU_OPTION_d, \
@@ -1368,7 +1379,8 @@ ETEXI
DEF("icount", HAS_ARG, QEMU_OPTION_icount, \
"-icount [N|auto]\n" \
- " enable virtual instruction counter with 2^N clock ticks per instruction\n")
+ " enable virtual instruction counter with 2^N clock ticks per\n" \
+ " instruction\n")
STEXI
@item -icount [N|auto]
Enable virtual instruction counter. The virtual cpu will execute one
diff --git a/savevm.c b/savevm.c
index 72c370941..2766d4cac 100644
--- a/savevm.c
+++ b/savevm.c
@@ -310,18 +310,18 @@ typedef struct QEMUFileBdrv
int64_t base_offset;
} QEMUFileBdrv;
-static int bdrv_put_buffer(void *opaque, const uint8_t *buf,
+static int block_put_buffer(void *opaque, const uint8_t *buf,
int64_t pos, int size)
{
QEMUFileBdrv *s = opaque;
- bdrv_pwrite(s->bs, s->base_offset + pos, buf, size);
+ bdrv_put_buffer(s->bs, buf, s->base_offset + pos, size);
return size;
}
-static int bdrv_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+static int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
{
QEMUFileBdrv *s = opaque;
- return bdrv_pread(s->bs, s->base_offset + pos, buf, size);
+ return bdrv_get_buffer(s->bs, buf, s->base_offset + pos, size);
}
static int bdrv_fclose(void *opaque)
@@ -341,9 +341,9 @@ static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_wr
s->base_offset = offset;
if (is_writable)
- return qemu_fopen_ops(s, bdrv_put_buffer, NULL, bdrv_fclose, NULL);
+ return qemu_fopen_ops(s, block_put_buffer, NULL, bdrv_fclose, NULL);
- return qemu_fopen_ops(s, NULL, bdrv_get_buffer, bdrv_fclose, NULL);
+ return qemu_fopen_ops(s, NULL, block_get_buffer, bdrv_fclose, NULL);
}
QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
@@ -370,6 +370,11 @@ int qemu_file_has_error(QEMUFile *f)
return f->has_error;
}
+void qemu_file_set_error(QEMUFile *f)
+{
+ f->has_error = 1;
+}
+
void qemu_fflush(QEMUFile *f)
{
if (!f->put_buffer)
diff --git a/slirp/misc.c b/slirp/misc.c
index 581db880d..0137e75ed 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -777,7 +777,11 @@ void
fd_nonblock(int fd)
{
#ifdef FIONBIO
- int opt = 1;
+#ifdef _WIN32
+ long opt = 1;
+#else
+ int opt = 1;
+#endif
ioctlsocket(fd, FIONBIO, &opt);
#else
diff --git a/slirp/socket.h b/slirp/socket.h
index 72b473d63..f5adaba6e 100644
--- a/slirp/socket.h
+++ b/slirp/socket.h
@@ -87,6 +87,7 @@ void soisfconnecting _P((register struct socket *));
void soisfconnected _P((register struct socket *));
void soisfdisconnected _P((struct socket *));
void sofwdrain _P((struct socket *));
+struct iovec; /* For win32 */
size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
int soreadbuf(struct socket *so, const char *buf, int size);
diff --git a/tap-win32.c b/tap-win32.c
index df31fda49..e8a04dc7c 100644
--- a/tap-win32.c
+++ b/tap-win32.c
@@ -254,7 +254,7 @@ static int is_tap_win32_dev(const char *guid)
component_id_string,
NULL,
&data_type,
- component_id,
+ (LPBYTE)component_id,
&len);
if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) {
@@ -264,7 +264,7 @@ static int is_tap_win32_dev(const char *guid)
net_cfg_instance_id_string,
NULL,
&data_type,
- net_cfg_instance_id,
+ (LPBYTE)net_cfg_instance_id,
&len);
if (status == ERROR_SUCCESS && data_type == REG_SZ) {
@@ -353,7 +353,7 @@ static int get_device_guid(
name_string,
NULL,
&name_type,
- name_data,
+ (LPBYTE)name_data,
&len);
if (status != ERROR_SUCCESS || name_type != REG_SZ) {
@@ -560,7 +560,7 @@ static int tap_win32_read(tap_win32_overlapped_t *overlapped,
}
static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped,
- char* pbuf)
+ uint8_t *pbuf)
{
tun_buffer_t* buffer = (tun_buffer_t*)pbuf;
put_buffer_on_free_list(overlapped, buffer);
@@ -580,7 +580,7 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle,
unsigned long minor;
unsigned long debug;
} version;
- LONG version_len;
+ DWORD version_len;
DWORD idThread;
HANDLE hThread;
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 6156fb5d0..1e1da542d 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -2412,11 +2412,11 @@ static always_inline void gen_intermediate_code_internal (CPUState *env,
if (env->singlestep_enabled) {
gen_excp(&ctx, EXCP_DEBUG, 0);
break;
- }
+ }
-#if defined (DO_SINGLE_STEP)
- break;
-#endif
+ if (singlestep) {
+ break;
+ }
}
if (ret != 1 && ret != 3) {
tcg_gen_movi_i64(cpu_pc, ctx.pc);
diff --git a/target-arm/translate.c b/target-arm/translate.c
index f7f2a8d6f..9aff6197c 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -8791,6 +8791,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
num_insns ++;
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
!env->singlestep_enabled &&
+ !singlestep &&
dc->pc < next_page_start &&
num_insns < max_insns);
diff --git a/target-cris/translate.c b/target-cris/translate.c
index d5fcb9e63..d9256ca42 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -3272,6 +3272,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
break;
} while (!dc->is_jmp && !dc->cpustate_changed
&& gen_opc_ptr < gen_opc_end
+ && !singlestep
&& (dc->pc < next_page_start)
&& num_insns < max_insns);
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 04ef295ce..8df3ea439 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -1551,7 +1551,6 @@ static inline void tcg_gen_lshift(TCGv ret, TCGv arg1, target_long arg2)
tcg_gen_shri_tl(ret, arg1, -arg2);
}
-/* XXX: add faster immediate case */
static void gen_rot_rm_T1(DisasContext *s, int ot, int op1,
int is_right)
{
@@ -1648,6 +1647,83 @@ static void gen_rot_rm_T1(DisasContext *s, int ot, int op1,
tcg_temp_free(a0);
}
+static void gen_rot_rm_im(DisasContext *s, int ot, int op1, int op2,
+ int is_right)
+{
+ int mask;
+ int data_bits;
+ TCGv t0, t1, a0;
+
+ /* XXX: inefficient, but we must use local temps */
+ t0 = tcg_temp_local_new();
+ t1 = tcg_temp_local_new();
+ a0 = tcg_temp_local_new();
+
+ if (ot == OT_QUAD)
+ mask = 0x3f;
+ else
+ mask = 0x1f;
+
+ /* load */
+ if (op1 == OR_TMP0) {
+ tcg_gen_mov_tl(a0, cpu_A0);
+ gen_op_ld_v(ot + s->mem_index, t0, a0);
+ } else {
+ gen_op_mov_v_reg(ot, t0, op1);
+ }
+
+ gen_extu(ot, t0);
+ tcg_gen_mov_tl(t1, t0);
+
+ op2 &= mask;
+ data_bits = 8 << ot;
+ if (op2 != 0) {
+ int shift = op2 & ((1 << (3 + ot)) - 1);
+ if (is_right) {
+ tcg_gen_shri_tl(cpu_tmp4, t0, shift);
+ tcg_gen_shli_tl(t0, t0, data_bits - shift);
+ }
+ else {
+ tcg_gen_shli_tl(cpu_tmp4, t0, shift);
+ tcg_gen_shri_tl(t0, t0, data_bits - shift);
+ }
+ tcg_gen_or_tl(t0, t0, cpu_tmp4);
+ }
+
+ /* store */
+ if (op1 == OR_TMP0) {
+ gen_op_st_v(ot + s->mem_index, t0, a0);
+ } else {
+ gen_op_mov_reg_v(ot, op1, t0);
+ }
+
+ if (op2 != 0) {
+ /* update eflags */
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+
+ gen_compute_eflags(cpu_cc_src);
+ tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~(CC_O | CC_C));
+ tcg_gen_xor_tl(cpu_tmp0, t1, t0);
+ tcg_gen_lshift(cpu_tmp0, cpu_tmp0, 11 - (data_bits - 1));
+ tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_O);
+ tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_tmp0);
+ if (is_right) {
+ tcg_gen_shri_tl(t0, t0, data_bits - 1);
+ }
+ tcg_gen_andi_tl(t0, t0, CC_C);
+ tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0);
+
+ tcg_gen_discard_tl(cpu_cc_dst);
+ tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS);
+ s->cc_op = CC_OP_EFLAGS;
+ }
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ tcg_temp_free(a0);
+}
+
/* XXX: add faster immediate = 1 case */
static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1,
int is_right)
@@ -1862,6 +1938,12 @@ static void gen_shift(DisasContext *s1, int op, int ot, int d, int s)
static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c)
{
switch(op) {
+ case OP_ROL:
+ gen_rot_rm_im(s1, ot, d, c, 0);
+ break;
+ case OP_ROR:
+ gen_rot_rm_im(s1, ot, d, c, 1);
+ break;
case OP_SHL:
case OP_SHL1:
gen_shift_rm_im(s1, ot, d, c, 0, 0);
@@ -7651,6 +7733,11 @@ static inline void gen_intermediate_code_internal(CPUState *env,
gen_eob(dc);
break;
}
+ if (singlestep) {
+ gen_jmp_im(pc_ptr - dc->cs_base);
+ gen_eob(dc);
+ break;
+ }
}
if (tb->cflags & CF_LAST_IO)
gen_io_end();
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 4e3cf4aa2..f9b36c963 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3031,6 +3031,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
num_insns++;
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
!env->singlestep_enabled &&
+ !singlestep &&
(pc_offset) < (TARGET_PAGE_SIZE - 32) &&
num_insns < max_insns);
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 8adc89cff..47a3062f8 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -38,7 +38,6 @@
//#define MIPS_DEBUG_DISAS
//#define MIPS_DEBUG_SIGN_EXTENSIONS
-//#define MIPS_SINGLE_STEP
/* MIPS major opcodes */
#define MASK_OP_MAJOR(op) (op & (0x3F << 26))
@@ -8140,9 +8139,9 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
if (num_insns >= max_insns)
break;
-#if defined (MIPS_SINGLE_STEP)
- break;
-#endif
+
+ if (singlestep)
+ break;
}
if (tb->cflags & CF_LAST_IO)
gen_io_end();
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 870aec5ec..9ba493749 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -39,7 +39,6 @@
#define GDBSTUB_SINGLE_STEP 0x4
/* Include definitions for instructions classes and implementations flags */
-//#define DO_SINGLE_STEP
//#define PPC_DEBUG_DISAS
//#define DO_PPC_STATISTICS
@@ -8288,15 +8287,13 @@ static always_inline void gen_intermediate_code_internal (CPUState *env,
gen_exception(ctxp, POWERPC_EXCP_TRACE);
} else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
(env->singlestep_enabled) ||
+ singlestep ||
num_insns >= max_insns)) {
/* if we reach a page boundary or are single stepping, stop
* generation
*/
break;
}
-#if defined (DO_SINGLE_STEP)
- break;
-#endif
}
if (tb->cflags & CF_LAST_IO)
gen_io_end();
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index aea7108fc..e597f653a 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -100,6 +100,12 @@ enum sh_features {
SH_FEATURE_BCR3_AND_BCR4 = 2,
};
+typedef struct memory_content {
+ uint32_t address;
+ uint32_t value;
+ struct memory_content *next;
+} memory_content;
+
typedef struct CPUSH4State {
int id; /* CPU model */
@@ -148,6 +154,8 @@ typedef struct CPUSH4State {
tlb_t itlb[ITLB_SIZE]; /* instruction translation table */
void *intc_handle;
int intr_at_halt; /* SR_BL ignored during sleep */
+ memory_content *movcal_backup;
+ memory_content **movcal_backup_tail;
} CPUSH4State;
CPUSH4State *cpu_sh4_init(const char *cpu_model);
@@ -162,6 +170,8 @@ void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
uint32_t mem_value);
+int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr);
+
static inline void cpu_set_tls(CPUSH4State *env, target_ulong newtls)
{
env->gbr = newtls;
@@ -293,6 +303,8 @@ static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
env->flags = tb->flags;
}
+#define TB_FLAG_PENDING_MOVCA (1 << 4)
+
static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
{
@@ -302,7 +314,8 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
| DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME)) /* Bits 0- 3 */
| (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR)) /* Bits 19-21 */
| (env->sr & (SR_MD | SR_RB)) /* Bits 29-30 */
- | (env->sr & SR_FD); /* Bit 15 */
+ | (env->sr & SR_FD) /* Bit 15 */
+ | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 4 */
}
#endif /* _CPU_SH4_H */
diff --git a/target-sh4/helper.c b/target-sh4/helper.c
index c50608661..d8e08e305 100644
--- a/target-sh4/helper.c
+++ b/target-sh4/helper.c
@@ -60,6 +60,12 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
return addr;
}
+int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr)
+{
+ /* For user mode, only U0 area is cachable. */
+ return !(addr & 0x80000000);
+}
+
#else /* !CONFIG_USER_ONLY */
#define MMU_OK 0
@@ -644,4 +650,48 @@ void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
}
}
+int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr)
+{
+ int n;
+ int use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0;
+
+ /* check area */
+ if (env->sr & SR_MD) {
+ /* For previledged mode, P2 and P4 area is not cachable. */
+ if ((0xA0000000 <= addr && addr < 0xC0000000) || 0xE0000000 <= addr)
+ return 0;
+ } else {
+ /* For user mode, only U0 area is cachable. */
+ if (0x80000000 <= addr)
+ return 0;
+ }
+
+ /*
+ * TODO : Evaluate CCR and check if the cache is on or off.
+ * Now CCR is not in CPUSH4State, but in SH7750State.
+ * When you move the ccr inot CPUSH4State, the code will be
+ * as follows.
+ */
+#if 0
+ /* check if operand cache is enabled or not. */
+ if (!(env->ccr & 1))
+ return 0;
+#endif
+
+ /* if MMU is off, no check for TLB. */
+ if (env->mmucr & MMUCR_AT)
+ return 1;
+
+ /* check TLB */
+ n = find_tlb_entry(env, addr, env->itlb, ITLB_SIZE, use_asid);
+ if (n >= 0)
+ return env->itlb[n].c;
+
+ n = find_tlb_entry(env, addr, env->utlb, UTLB_SIZE, use_asid);
+ if (n >= 0)
+ return env->utlb[n].c;
+
+ return 0;
+}
+
#endif
diff --git a/target-sh4/helper.h b/target-sh4/helper.h
index e66518558..4b2fcdd53 100644
--- a/target-sh4/helper.h
+++ b/target-sh4/helper.h
@@ -9,6 +9,10 @@ DEF_HELPER_0(debug, void)
DEF_HELPER_1(sleep, void, i32)
DEF_HELPER_1(trapa, void, i32)
+DEF_HELPER_2(movcal, void, i32, i32)
+DEF_HELPER_0(discard_movcal_backup, void)
+DEF_HELPER_1(ocbi, void, i32)
+
DEF_HELPER_2(addv, i32, i32, i32)
DEF_HELPER_2(addc, i32, i32, i32)
DEF_HELPER_2(subv, i32, i32, i32)
diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c
index 84e1ad331..616b4f9a4 100644
--- a/target-sh4/op_helper.c
+++ b/target-sh4/op_helper.c
@@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
*/
#include <assert.h>
+#include <stdlib.h>
#include "exec.h"
#include "helper.h"
@@ -122,6 +123,57 @@ void helper_trapa(uint32_t tra)
cpu_loop_exit();
}
+void helper_movcal(uint32_t address, uint32_t value)
+{
+ if (cpu_sh4_is_cached (env, address))
+ {
+ memory_content *r = malloc (sizeof(memory_content));
+ r->address = address;
+ r->value = value;
+ r->next = NULL;
+
+ *(env->movcal_backup_tail) = r;
+ env->movcal_backup_tail = &(r->next);
+ }
+}
+
+void helper_discard_movcal_backup(void)
+{
+ memory_content *current = env->movcal_backup;
+
+ while(current)
+ {
+ memory_content *next = current->next;
+ free (current);
+ env->movcal_backup = current = next;
+ if (current == 0)
+ env->movcal_backup_tail = &(env->movcal_backup);
+ }
+}
+
+void helper_ocbi(uint32_t address)
+{
+ memory_content **current = &(env->movcal_backup);
+ while (*current)
+ {
+ uint32_t a = (*current)->address;
+ if ((a & ~0x1F) == (address & ~0x1F))
+ {
+ memory_content *next = (*current)->next;
+ stl(a, (*current)->value);
+
+ if (next == 0)
+ {
+ env->movcal_backup_tail = current;
+ }
+
+ free (*current);
+ *current = next;
+ break;
+ }
+ }
+}
+
uint32_t helper_addc(uint32_t arg0, uint32_t arg1)
{
uint32_t tmp0, tmp1;
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index cc9f88681..aa3b9d439 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -50,6 +50,7 @@ typedef struct DisasContext {
uint32_t delayed_pc;
int singlestep_enabled;
uint32_t features;
+ int has_movcal;
} DisasContext;
#if defined(CONFIG_USER_ONLY)
@@ -283,6 +284,7 @@ CPUSH4State *cpu_sh4_init(const char *cpu_model)
env = qemu_mallocz(sizeof(CPUSH4State));
env->features = def->features;
cpu_exec_init(env);
+ env->movcal_backup_tail = &(env->movcal_backup);
sh4_translate_init();
env->cpu_model_str = cpu_model;
cpu_sh4_reset(env);
@@ -495,6 +497,37 @@ static inline void gen_store_fpr64 (TCGv_i64 t, int reg)
static void _decode_opc(DisasContext * ctx)
{
+ /* This code tries to make movcal emulation sufficiently
+ accurate for Linux purposes. This instruction writes
+ memory, and prior to that, always allocates a cache line.
+ It is used in two contexts:
+ - in memcpy, where data is copied in blocks, the first write
+ of to a block uses movca.l for performance.
+ - in arch/sh/mm/cache-sh4.c, movcal.l + ocbi combination is used
+ to flush the cache. Here, the data written by movcal.l is never
+ written to memory, and the data written is just bogus.
+
+ To simulate this, we simulate movcal.l, we store the value to memory,
+ but we also remember the previous content. If we see ocbi, we check
+ if movcal.l for that address was done previously. If so, the write should
+ not have hit the memory, so we restore the previous content.
+ When we see an instruction that is neither movca.l
+ nor ocbi, the previous content is discarded.
+
+ To optimize, we only try to flush stores when we're at the start of
+ TB, or if we already saw movca.l in this TB and did not flush stores
+ yet. */
+ if (ctx->has_movcal)
+ {
+ int opcode = ctx->opcode & 0xf0ff;
+ if (opcode != 0x0093 /* ocbi */
+ && opcode != 0x00c3 /* movca.l */)
+ {
+ gen_helper_discard_movcal_backup ();
+ ctx->has_movcal = 0;
+ }
+ }
+
#if 0
fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode);
#endif
@@ -1545,7 +1578,13 @@ static void _decode_opc(DisasContext * ctx)
}
return;
case 0x00c3: /* movca.l R0,@Rm */
- tcg_gen_qemu_st32(REG(0), REG(B11_8), ctx->memidx);
+ {
+ TCGv val = tcg_temp_new();
+ tcg_gen_qemu_ld32u(val, REG(B11_8), ctx->memidx);
+ gen_helper_movcal (REG(B11_8), val);
+ tcg_gen_qemu_st32(REG(0), REG(B11_8), ctx->memidx);
+ }
+ ctx->has_movcal = 1;
return;
case 0x40a9:
/* MOVUA.L @Rm,R0 (Rm) -> R0
@@ -1594,9 +1633,7 @@ static void _decode_opc(DisasContext * ctx)
break;
case 0x0093: /* ocbi @Rn */
{
- TCGv dummy = tcg_temp_new();
- tcg_gen_qemu_ld32s(dummy, REG(B11_8), ctx->memidx);
- tcg_temp_free(dummy);
+ gen_helper_ocbi (REG(B11_8));
}
return;
case 0x00a3: /* ocbp @Rn */
@@ -1876,6 +1913,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
ctx.tb = tb;
ctx.singlestep_enabled = env->singlestep_enabled;
ctx.features = env->features;
+ ctx.has_movcal = (tb->flags & TB_FLAG_PENDING_MOVCA);
#ifdef DEBUG_DISAS
qemu_log_mask(CPU_LOG_TB_CPU,
@@ -1929,9 +1967,8 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
break;
if (num_insns >= max_insns)
break;
-#ifdef SH4_SINGLE_STEP
- break;
-#endif
+ if (singlestep)
+ break;
}
if (tb->cflags & CF_LAST_IO)
gen_io_end();
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index d059408ba..86319a704 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -4838,7 +4838,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb,
break;
/* if single step mode, we generate only one instruction and
generate an exception */
- if (env->singlestep_enabled) {
+ if (env->singlestep_enabled || singlestep) {
tcg_gen_movi_tl(cpu_pc, dc->pc);
tcg_gen_exit_tb(0);
break;
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index 2c571a782..23cd9cdbe 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -117,6 +117,13 @@ static void patch_reloc(uint8_t *code_ptr, int type,
tcg_abort();
*(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x3fffff) | value;
break;
+ case R_SPARC_WDISP19:
+ value -= (long)code_ptr;
+ value >>= 2;
+ if (!check_fit_tl(value, 19))
+ tcg_abort();
+ *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x7ffff) | value;
+ break;
default:
tcg_abort();
}
@@ -185,6 +192,7 @@ static inline int tcg_target_const_match(tcg_target_long val,
#define INSN_ASI(x) ((x) << 5)
#define INSN_IMM13(x) ((1 << 13) | ((x) & 0x1fff))
+#define INSN_OFF19(x) (((x) >> 2) & 0x07ffff)
#define INSN_OFF22(x) (((x) >> 2) & 0x3fffff)
#define INSN_COND(x, a) (((x) << 25) | ((a) << 29))
@@ -421,7 +429,7 @@ static inline void tcg_out_nop(TCGContext *s)
tcg_out_sethi(s, TCG_REG_G0, 0);
}
-static void tcg_out_branch(TCGContext *s, int opc, int label_index)
+static void tcg_out_branch_i32(TCGContext *s, int opc, int label_index)
{
int32_t val;
TCGLabel *l = &s->labels[label_index];
@@ -436,6 +444,25 @@ static void tcg_out_branch(TCGContext *s, int opc, int label_index)
}
}
+#if defined(__sparc_v9__) && !defined(__sparc_v8plus__)
+static void tcg_out_branch_i64(TCGContext *s, int opc, int label_index)
+{
+ int32_t val;
+ TCGLabel *l = &s->labels[label_index];
+
+ if (l->has_value) {
+ val = l->u.value - (tcg_target_long)s->code_ptr;
+ tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) |
+ (0x5 << 19) |
+ INSN_OFF19(l->u.value - (unsigned long)s->code_ptr)));
+ } else {
+ tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP19, label_index, 0);
+ tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) |
+ (0x5 << 19) | 0));
+ }
+}
+#endif
+
static const uint8_t tcg_cond_to_bcond[10] = {
[TCG_COND_EQ] = COND_E,
[TCG_COND_NE] = COND_NE,
@@ -449,9 +476,9 @@ static const uint8_t tcg_cond_to_bcond[10] = {
[TCG_COND_GTU] = COND_GU,
};
-static void tcg_out_brcond(TCGContext *s, int cond,
- TCGArg arg1, TCGArg arg2, int const_arg2,
- int label_index)
+static void tcg_out_brcond_i32(TCGContext *s, int cond,
+ TCGArg arg1, TCGArg arg2, int const_arg2,
+ int label_index)
{
if (const_arg2 && arg2 == 0)
/* orcc %g0, r, %g0 */
@@ -459,10 +486,26 @@ static void tcg_out_brcond(TCGContext *s, int cond,
else
/* subcc r1, r2, %g0 */
tcg_out_arith(s, TCG_REG_G0, arg1, arg2, ARITH_SUBCC);
- tcg_out_branch(s, tcg_cond_to_bcond[cond], label_index);
+ tcg_out_branch_i32(s, tcg_cond_to_bcond[cond], label_index);
tcg_out_nop(s);
}
+#if defined(__sparc_v9__) && !defined(__sparc_v8plus__)
+static void tcg_out_brcond_i64(TCGContext *s, int cond,
+ TCGArg arg1, TCGArg arg2, int const_arg2,
+ int label_index)
+{
+ if (const_arg2 && arg2 == 0)
+ /* orcc %g0, r, %g0 */
+ tcg_out_arith(s, TCG_REG_G0, TCG_REG_G0, arg1, ARITH_ORCC);
+ else
+ /* subcc r1, r2, %g0 */
+ tcg_out_arith(s, TCG_REG_G0, arg1, arg2, ARITH_SUBCC);
+ tcg_out_branch_i64(s, tcg_cond_to_bcond[cond], label_index);
+ tcg_out_nop(s);
+}
+#endif
+
/* Generate global QEMU prologue and epilogue code */
void tcg_target_qemu_prologue(TCGContext *s)
{
@@ -559,7 +602,9 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC);
/* will become:
- be label1 */
+ be label1
+ or
+ be,pt %xcc label1 */
label1_ptr = (uint32_t *)s->code_ptr;
tcg_out32(s, 0);
@@ -578,9 +623,11 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
global registers */
// delay slot
tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
- TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_ST_OP);
+ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+ sizeof(long), HOST_ST_OP);
tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
- TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_LD_OP);
+ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+ sizeof(long), HOST_LD_OP);
/* data_reg = sign_extend(arg0) */
switch(opc) {
@@ -625,9 +672,17 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
tcg_out_nop(s);
/* label1: */
+#if TARGET_LONG_BITS == 32
+ /* be label1 */
*label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) |
INSN_OFF22((unsigned long)s->code_ptr -
(unsigned long)label1_ptr));
+#else
+ /* be,pt %xcc label1 */
+ *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) |
+ (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr -
+ (unsigned long)label1_ptr));
+#endif
/* ld [arg1 + x], arg1 */
tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) -
@@ -759,7 +814,9 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC);
/* will become:
- be label1 */
+ be label1
+ or
+ be,pt %xcc label1 */
label1_ptr = (uint32_t *)s->code_ptr;
tcg_out32(s, 0);
@@ -781,9 +838,11 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
global registers */
// delay slot
tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
- TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_ST_OP);
+ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+ sizeof(long), HOST_ST_OP);
tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
- TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_LD_OP);
+ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+ sizeof(long), HOST_LD_OP);
/* will become:
ba label2 */
@@ -793,10 +852,17 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
/* nop (delay slot) */
tcg_out_nop(s);
- /* label1: */
+#if TARGET_LONG_BITS == 32
+ /* be label1 */
*label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) |
INSN_OFF22((unsigned long)s->code_ptr -
(unsigned long)label1_ptr));
+#else
+ /* be,pt %xcc label1 */
+ *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) |
+ (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr -
+ (unsigned long)label1_ptr));
+#endif
/* ld [arg1 + x], arg1 */
tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) -
@@ -905,13 +971,15 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
global registers */
// delay slot
tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
- TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_ST_OP);
+ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+ sizeof(long), HOST_ST_OP);
tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
- TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_LD_OP);
+ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+ sizeof(long), HOST_LD_OP);
break;
case INDEX_op_jmp:
case INDEX_op_br:
- tcg_out_branch(s, COND_A, args[0]);
+ tcg_out_branch_i32(s, COND_A, args[0]);
tcg_out_nop(s);
break;
case INDEX_op_movi_i32:
@@ -1003,8 +1071,8 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
#endif
case INDEX_op_brcond_i32:
- tcg_out_brcond(s, args[2], args[0], args[1], const_args[1],
- args[3]);
+ tcg_out_brcond_i32(s, args[2], args[0], args[1], const_args[1],
+ args[3]);
break;
case INDEX_op_qemu_ld8u:
@@ -1068,8 +1136,8 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
goto gen_arith32;
case INDEX_op_brcond_i64:
- tcg_out_brcond(s, args[2], args[0], args[1], const_args[1],
- args[3]);
+ tcg_out_brcond_i64(s, args[2], args[0], args[1], const_args[1],
+ args[3]);
break;
case INDEX_op_qemu_ld64:
tcg_out_qemu_ld(s, args, 3);
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
index 43ec8180f..97f353305 100644
--- a/tcg/sparc/tcg-target.h
+++ b/tcg/sparc/tcg-target.h
@@ -75,12 +75,14 @@ enum {
#define TCG_REG_CALL_STACK TCG_REG_I6
#ifdef __arch64__
// Reserve space for AREG0
-#define TCG_TARGET_STACK_MINFRAME (176 + 2 * (int)sizeof(long))
-#define TCG_TARGET_CALL_STACK_OFFSET (2047 + TCG_TARGET_STACK_MINFRAME)
+#define TCG_TARGET_STACK_MINFRAME (176 + 4 * (int)sizeof(long) + \
+ TCG_STATIC_CALL_ARGS_SIZE)
+#define TCG_TARGET_CALL_STACK_OFFSET (2047 - 16)
#define TCG_TARGET_STACK_ALIGN 16
#else
// AREG0 + one word for alignment
-#define TCG_TARGET_STACK_MINFRAME (92 + (2 + 1) * (int)sizeof(long))
+#define TCG_TARGET_STACK_MINFRAME (92 + (2 + 1) * (int)sizeof(long) + \
+ TCG_STATIC_CALL_ARGS_SIZE)
#define TCG_TARGET_CALL_STACK_OFFSET TCG_TARGET_STACK_MINFRAME
#define TCG_TARGET_STACK_ALIGN 8
#endif
diff --git a/tcg/x86_64/tcg-target.c b/tcg/x86_64/tcg-target.c
index 92f0733ef..5378e8510 100644
--- a/tcg/x86_64/tcg-target.c
+++ b/tcg/x86_64/tcg-target.c
@@ -44,22 +44,21 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
#endif
static const int tcg_target_reg_alloc_order[] = {
- TCG_REG_RDI,
- TCG_REG_RSI,
- TCG_REG_RDX,
- TCG_REG_RCX,
- TCG_REG_R8,
- TCG_REG_R9,
- TCG_REG_RAX,
- TCG_REG_R10,
- TCG_REG_R11,
-
TCG_REG_RBP,
TCG_REG_RBX,
TCG_REG_R12,
TCG_REG_R13,
TCG_REG_R14,
TCG_REG_R15,
+ TCG_REG_R10,
+ TCG_REG_R11,
+ TCG_REG_R9,
+ TCG_REG_R8,
+ TCG_REG_RCX,
+ TCG_REG_RDX,
+ TCG_REG_RSI,
+ TCG_REG_RDI,
+ TCG_REG_RAX,
};
static const int tcg_target_call_iarg_regs[6] = {
diff --git a/vl.c b/vl.c
index b3da7ad42..8aa9ebc12 100644
--- a/vl.c
+++ b/vl.c
@@ -241,6 +241,7 @@ int win2k_install_hack = 0;
int rtc_td_hack = 0;
#endif
int usb_enabled = 0;
+int singlestep = 0;
const char *assigned_devices[MAX_DEV_ASSIGN_CMDLINE];
int assigned_devices_index;
int smp_cpus = 1;
@@ -252,8 +253,9 @@ int no_reboot = 0;
int no_shutdown = 0;
int cursor_hide = 1;
int graphic_rotate = 0;
+#ifndef _WIN32
int daemonize = 0;
-const char *incoming;
+#endif
const char *option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
int semihosting_enabled = 0;
@@ -1324,8 +1326,9 @@ static int timer_load(QEMUFile *f, void *opaque, int version_id)
}
#ifdef _WIN32
-void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
- DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
+static void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
+ DWORD_PTR dwUser, DWORD_PTR dw1,
+ DWORD_PTR dw2)
#else
static void host_alarm_handler(int host_signum)
#endif
@@ -3295,10 +3298,10 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque)
/* try transferring iterative blocks of memory */
if (stage == 3) {
- cpu_physical_memory_set_dirty_tracking(0);
/* flush all remaining blocks regardless of rate limiting */
while (ram_save_block(f) != 0);
+ cpu_physical_memory_set_dirty_tracking(0);
}
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
@@ -4296,13 +4299,14 @@ static int qemu_uuid_parse(const char *str, uint8_t *uuid)
static int saved_argc;
static char **saved_argv;
+static const char *saved_incoming;
void qemu_get_launch_info(int *argc, char ***argv, int *opt_daemonize, const char **opt_incoming)
{
*argc = saved_argc;
*argv = saved_argv;
*opt_daemonize = daemonize;
- *opt_incoming = incoming;
+ *opt_incoming = saved_incoming;
}
#ifdef USE_KVM
@@ -4430,8 +4434,7 @@ static void termsig_setup(void)
int main(int argc, char **argv, char **envp)
{
#ifdef CONFIG_GDBSTUB
- int use_gdbstub;
- const char *gdbstub_port;
+ const char *gdbstub_dev = NULL;
#endif
uint32_t boot_devices_bitmap = 0;
int i;
@@ -4462,14 +4465,18 @@ int main(int argc, char **argv, char **envp)
const char *cpu_model;
const char *usb_devices[MAX_USB_CMDLINE];
int usb_devices_index;
+#ifndef _WIN32
int fds[2];
+#endif
int tb_size;
const char *pid_file = NULL;
const char *incoming = NULL;
+#ifndef _WIN32
int fd = 0;
struct passwd *pwd = NULL;
const char *chroot_dir = NULL;
const char *run_as = NULL;
+#endif
qemu_cache_utils_init(envp);
@@ -4510,10 +4517,6 @@ int main(int argc, char **argv, char **envp)
initrd_filename = NULL;
ram_size = 0;
vga_ram_size = VGA_RAM_SIZE;
-#ifdef CONFIG_GDBSTUB
- use_gdbstub = 0;
- gdbstub_port = DEFAULT_GDBSTUB_PORT;
-#endif
snapshot = 0;
nographic = 0;
curses = 0;
@@ -4847,10 +4850,10 @@ int main(int argc, char **argv, char **envp)
break;
#ifdef CONFIG_GDBSTUB
case QEMU_OPTION_s:
- use_gdbstub = 1;
+ gdbstub_dev = "tcp::" DEFAULT_GDBSTUB_PORT;
break;
- case QEMU_OPTION_p:
- gdbstub_port = optarg;
+ case QEMU_OPTION_gdb:
+ gdbstub_dev = optarg;
break;
#endif
case QEMU_OPTION_L:
@@ -4859,6 +4862,9 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_bios:
bios_name = optarg;
break;
+ case QEMU_OPTION_singlestep:
+ singlestep = 1;
+ break;
case QEMU_OPTION_S:
autostart = 0;
break;
@@ -5184,6 +5190,7 @@ int main(int argc, char **argv, char **envp)
break;
case QEMU_OPTION_incoming:
incoming = optarg;
+ saved_incoming = incoming;
break;
#ifndef _WIN32
case QEMU_OPTION_chroot:
@@ -5268,7 +5275,6 @@ int main(int argc, char **argv, char **envp)
signal(SIGTTOU, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
}
-#endif
#ifdef USE_KVM
if (kvm_enabled()) {
@@ -5291,6 +5297,7 @@ int main(int argc, char **argv, char **envp)
fprintf(stderr, "Could not acquire pid file\n");
exit(1);
}
+#endif
#ifdef USE_KQEMU
if (smp_cpus > 1)
@@ -5650,14 +5657,10 @@ int main(int argc, char **argv, char **envp)
}
#ifdef CONFIG_GDBSTUB
- if (use_gdbstub) {
- /* XXX: use standard host:port notation and modify options
- accordingly. */
- if (gdbserver_start(gdbstub_port) < 0) {
- fprintf(stderr, "qemu: could not open gdbstub device on port '%s'\n",
- gdbstub_port);
- exit(1);
- }
+ if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) {
+ fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n",
+ gdbstub_dev);
+ exit(1);
}
#endif
@@ -5672,6 +5675,7 @@ int main(int argc, char **argv, char **envp)
if (autostart)
vm_start();
+#ifndef _WIN32
if (daemonize) {
uint8_t status = 0;
ssize_t len;
@@ -5690,7 +5694,6 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
-#ifndef _WIN32
if (run_as) {
pwd = getpwnam(run_as);
if (!pwd) {
@@ -5721,7 +5724,6 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
}
-#endif
if (daemonize) {
dup2(fd, 0);
@@ -5730,6 +5732,7 @@ int main(int argc, char **argv, char **envp)
close(fd);
}
+#endif
main_loop();
quit_timers();