diff options
author | Avi Kivity <avi@redhat.com> | 2009-04-06 10:47:06 +0300 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-04-06 10:47:06 +0300 |
commit | 67afa42dada0e8eab8b88bcc12447bddfccad5f7 (patch) | |
tree | 25d0be082487757dd67a932345bc293c75f87eed | |
parent | 1f28c06981a34f279cc90fa2b72a91bc6884af4e (diff) | |
parent | c20d7afb366e5d969858fcdcd4b5d5250fa3be91 (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>
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. @@ -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; @@ -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 */ @@ -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 @@ -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); +} @@ -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__ */ @@ -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 @@ -19,7 +19,6 @@ */ #include "config.h" #ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN #include <windows.h> #else #include <sys/types.h> @@ -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 @@ -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 @@ -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; @@ -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; } } @@ -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, @@ -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; @@ -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 Binary files differindex d0fa6c930..00d9a78eb 100644 --- a/pc-bios/openbios-ppc +++ b/pc-bios/openbios-ppc diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 Binary files differindex 8f6289e05..7c84965b7 100644 --- a/pc-bios/openbios-sparc32 +++ b/pc-bios/openbios-sparc32 diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 Binary files differindex b23d3bbb2..76886f49c 100644 --- a/pc-bios/openbios-sparc64 +++ b/pc-bios/openbios-sparc64 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 @@ -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] = { @@ -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(); |