aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--Makefile.target1
-rw-r--r--block.c83
-rw-r--r--block/qcow2-cluster.c8
-rw-r--r--block_int.h2
-rw-r--r--bswap.h6
-rw-r--r--cache-utils.c21
-rwxr-xr-xconfigure12
-rw-r--r--console.c176
-rw-r--r--console.h4
-rw-r--r--cpu-exec.c33
-rw-r--r--gdbstub.c36
-rw-r--r--hostregs_helper.h61
-rw-r--r--hw/apb_pci.c80
-rw-r--r--hw/ide/core.c62
-rw-r--r--hw/ide/internal.h5
-rw-r--r--hw/mac_dbdma.c10
-rw-r--r--hw/pc.c73
-rw-r--r--hw/pc.h10
-rw-r--r--hw/pci-hotplug.c30
-rw-r--r--hw/pci.h1
-rw-r--r--hw/pci_host.c172
-rw-r--r--hw/pci_host.h4
-rw-r--r--hw/pci_host_template.h109
-rw-r--r--hw/pci_ids.h1
-rw-r--r--hw/pl181.c29
-rw-r--r--hw/ppc.h2
-rw-r--r--hw/ppc_mac.h1
-rw-r--r--hw/ppc_newworld.c73
-rw-r--r--hw/ppc_oldworld.c9
-rw-r--r--hw/qdev.c7
-rw-r--r--hw/serial.c28
-rw-r--r--hw/unin_pci.c151
-rw-r--r--hw/usb-hid.c12
-rw-r--r--hw/versatile_pci.c10
-rw-r--r--hw/virtio-pci.c6
-rw-r--r--hw/virtio-serial-bus.c6
-rw-r--r--linux-user/main.c8
-rw-r--r--linux-user/strace.c4
-rw-r--r--migration.c43
-rw-r--r--migration.h10
-rw-r--r--monitor.c258
-rw-r--r--monitor.h6
-rw-r--r--net.c64
-rw-r--r--net.h3
-rw-r--r--net/slirp.c4
-rw-r--r--net/socket.c4
-rw-r--r--net/tap-win32.c4
-rw-r--r--net/tap.c4
-rw-r--r--net/vde.c4
-rw-r--r--pc-bios/README4
-rw-r--r--pc-bios/openbios-ppcbin312124 -> 307924 bytes
-rw-r--r--pc-bios/openbios-sparc32bin217668 -> 217668 bytes
-rw-r--r--pc-bios/openbios-sparc64bin1065880 -> 1065880 bytes
-rw-r--r--qemu-char.c17
-rw-r--r--qemu-common.h4
-rw-r--r--qemu-config.c49
-rw-r--r--qemu-config.h1
-rw-r--r--qemu-img.c4
-rw-r--r--qemu-option.c6
-rw-r--r--qemu-option.h2
-rw-r--r--rwhandler.c87
-rw-r--r--rwhandler.h27
-rw-r--r--sdl.c4
-rw-r--r--sysconfigs/target/target-x86_64.conf86
-rw-r--r--sysemu.h8
-rw-r--r--target-arm/helper.c5
-rw-r--r--target-arm/translate.c14
-rw-r--r--target-cris/translate_v10.c4
-rw-r--r--target-i386/cpu.h9
-rw-r--r--target-i386/helper.c460
-rw-r--r--target-i386/kvm.c8
-rw-r--r--target-m68k/exec.h4
-rw-r--r--target-microblaze/op_helper.c6
-rw-r--r--target-microblaze/translate.c19
-rw-r--r--target-ppc/helper.c9
-rw-r--r--target-ppc/kvm.c69
-rw-r--r--target-ppc/kvm_ppc.h2
-rw-r--r--target-sparc/translate.c22
-rw-r--r--tcg/arm/tcg-target.h14
-rw-r--r--tcg/hppa/tcg-target.c1
-rw-r--r--tcg/i386/tcg-target.h12
-rw-r--r--tcg/mips/tcg-target.h4
-rw-r--r--tcg/ppc/tcg-target.c106
-rw-r--r--tcg/ppc/tcg-target.h16
-rw-r--r--tcg/ppc64/tcg-target.h25
-rw-r--r--tcg/s390/tcg-target.h30
-rw-r--r--tcg/sparc/tcg-target.c161
-rw-r--r--tcg/sparc/tcg-target.h31
-rw-r--r--tcg/tcg-op.h22
-rw-r--r--tcg/tcg-opc.h17
-rw-r--r--tcg/tcg.c21
-rw-r--r--tcg/tcg.h11
-rw-r--r--tcg/x86_64/tcg-target.h6
-rw-r--r--vl.c58
95 files changed, 2382 insertions, 839 deletions
diff --git a/Makefile b/Makefile
index c72a05940f..c6629d6643 100644
--- a/Makefile
+++ b/Makefile
@@ -191,7 +191,11 @@ ifdef CONFIG_POSIX
$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
endif
-install: all $(if $(BUILD_DOCS),install-doc)
+install-sysconfig:
+ $(INSTALL_DIR) "$(sysconfdir)/qemu"
+ $(INSTALL_DATA) sysconfigs/target/target-x86_64.conf "$(sysconfdir)/qemu"
+
+install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig
$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
ifneq ($(TOOLS),)
$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
diff --git a/Makefile.target b/Makefile.target
index f498574696..4c4d397627 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -173,6 +173,7 @@ obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o
# virtio has to be here due to weird dependency between PCI and virtio-net.
# need to fix this properly
obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-pci.o virtio-serial-bus.o
+obj-y += rwhandler.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
LIBS+=-lz
diff --git a/block.c b/block.c
index af56ea7372..31d1ba4bfd 100644
--- a/block.c
+++ b/block.c
@@ -363,6 +363,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
bs->is_temporary = 0;
bs->encrypted = 0;
bs->valid_key = 0;
+ bs->open_flags = flags;
/* buffer_alignment defaulted to 512, drivers can change this value */
bs->buffer_alignment = 512;
@@ -450,8 +451,6 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
bs->enable_write_cache = 1;
- bs->read_only = (flags & BDRV_O_RDWR) == 0;
-
/*
* Clear flags that are internal to the block layer before opening the
* image.
@@ -472,6 +471,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
goto free_and_fail;
}
+ bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
if (drv->bdrv_getlength) {
bs->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
}
@@ -488,13 +488,22 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
filename, bs->backing_file);
if (bs->backing_format[0] != '\0')
back_drv = bdrv_find_format(bs->backing_format);
+
+ /* backing files always opened read-only */
+ open_flags &= ~BDRV_O_RDWR;
+
ret = bdrv_open2(bs->backing_hd, backing_filename, open_flags,
back_drv);
- bs->backing_hd->read_only = (open_flags & BDRV_O_RDWR) == 0;
if (ret < 0) {
bdrv_close(bs);
return ret;
}
+ if (bs->is_temporary) {
+ bs->backing_hd->keep_read_only = !(flags & BDRV_O_RDWR);
+ } else {
+ /* base image inherits from "parent" */
+ bs->backing_hd->keep_read_only = bs->keep_read_only;
+ }
}
if (!bdrv_key_required(bs)) {
@@ -570,19 +579,48 @@ int bdrv_commit(BlockDriverState *bs)
{
BlockDriver *drv = bs->drv;
int64_t i, total_sectors;
- int n, j;
- int ret = 0;
+ int n, j, ro, open_flags;
+ int ret = 0, rw_ret = 0;
unsigned char sector[512];
+ char filename[1024];
+ BlockDriverState *bs_rw, *bs_ro;
if (!drv)
return -ENOMEDIUM;
-
- if (bs->read_only) {
- return -EACCES;
+
+ if (!bs->backing_hd) {
+ return -ENOTSUP;
}
- if (!bs->backing_hd) {
- return -ENOTSUP;
+ if (bs->backing_hd->keep_read_only) {
+ return -EACCES;
+ }
+
+ ro = bs->backing_hd->read_only;
+ strncpy(filename, bs->backing_hd->filename, sizeof(filename));
+ open_flags = bs->backing_hd->open_flags;
+
+ if (ro) {
+ /* re-open as RW */
+ bdrv_delete(bs->backing_hd);
+ bs->backing_hd = NULL;
+ bs_rw = bdrv_new("");
+ rw_ret = bdrv_open2(bs_rw, filename, open_flags | BDRV_O_RDWR, NULL);
+ if (rw_ret < 0) {
+ bdrv_delete(bs_rw);
+ /* try to re-open read-only */
+ bs_ro = bdrv_new("");
+ ret = bdrv_open2(bs_ro, filename, open_flags & ~BDRV_O_RDWR, NULL);
+ if (ret < 0) {
+ bdrv_delete(bs_ro);
+ /* drive not functional anymore */
+ bs->drv = NULL;
+ return ret;
+ }
+ bs->backing_hd = bs_ro;
+ return rw_ret;
+ }
+ bs->backing_hd = bs_rw;
}
total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
@@ -590,11 +628,13 @@ int bdrv_commit(BlockDriverState *bs)
if (drv->bdrv_is_allocated(bs, i, 65536, &n)) {
for(j = 0; j < n; j++) {
if (bdrv_read(bs, i, sector, 1) != 0) {
- return -EIO;
+ ret = -EIO;
+ goto ro_cleanup;
}
if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {
- return -EIO;
+ ret = -EIO;
+ goto ro_cleanup;
}
i++;
}
@@ -614,6 +654,25 @@ int bdrv_commit(BlockDriverState *bs)
*/
if (bs->backing_hd)
bdrv_flush(bs->backing_hd);
+
+ro_cleanup:
+
+ if (ro) {
+ /* re-open as RO */
+ bdrv_delete(bs->backing_hd);
+ bs->backing_hd = NULL;
+ bs_ro = bdrv_new("");
+ ret = bdrv_open2(bs_ro, filename, open_flags & ~BDRV_O_RDWR, NULL);
+ if (ret < 0) {
+ bdrv_delete(bs_ro);
+ /* drive not functional anymore */
+ bs->drv = NULL;
+ return ret;
+ }
+ bs->backing_hd = bs_ro;
+ bs->backing_hd->keep_read_only = 0;
+ }
+
return ret;
}
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 3501a94296..b13b6935f8 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -750,12 +750,15 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
while (i < nb_clusters) {
i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
&l2_table[l2_index], i, 0);
-
- if(be64_to_cpu(l2_table[l2_index + i]))
+ if ((i >= nb_clusters) || be64_to_cpu(l2_table[l2_index + i])) {
break;
+ }
i += count_contiguous_free_clusters(nb_clusters - i,
&l2_table[l2_index + i]);
+ if (i >= nb_clusters) {
+ break;
+ }
cluster_offset = be64_to_cpu(l2_table[l2_index + i]);
@@ -763,6 +766,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
(cluster_offset & QCOW_OFLAG_COMPRESSED))
break;
}
+ assert(i <= nb_clusters);
nb_clusters = i;
/*
diff --git a/block_int.h b/block_int.h
index 930a5a4d11..50e1a0b770 100644
--- a/block_int.h
+++ b/block_int.h
@@ -130,6 +130,8 @@ struct BlockDriverState {
int64_t total_sectors; /* if we are reading a disk image, give its
size in sectors */
int read_only; /* if true, the media is read only */
+ int keep_read_only; /* if true, the media was requested to stay read only */
+ int open_flags; /* flags used to open the file, re-used for re-open */
int removable; /* if true, the media can be removed */
int locked; /* if true, the media cannot temporarily be ejected */
int encrypted; /* if true, the media is encrypted */
diff --git a/bswap.h b/bswap.h
index 4558704290..aace9b76e9 100644
--- a/bswap.h
+++ b/bswap.h
@@ -214,4 +214,10 @@ static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
#undef le_bswaps
#undef be_bswaps
+/* len must be one of 1, 2, 4 */
+static inline uint32_t qemu_bswap_len(uint32_t value, int len)
+{
+ return bswap32(value) >> (32 - 8 * len);
+}
+
#endif /* BSWAP_H */
diff --git a/cache-utils.c b/cache-utils.c
index 45d62c91c5..8bbd68054d 100644
--- a/cache-utils.c
+++ b/cache-utils.c
@@ -57,6 +57,27 @@ static void ppc_init_cacheline_sizes(void)
}
#endif
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+static void ppc_init_cacheline_sizes(void)
+{
+ size_t len = 4;
+ unsigned cacheline;
+
+ if (sysctlbyname ("machdep.cacheline_size", &cacheline, &len, NULL, 0)) {
+ fprintf(stderr, "sysctlbyname machdep.cacheline_size failed: %s\n",
+ strerror(errno));
+ exit(1);
+ }
+
+ qemu_cache_conf.dcache_bsize = cacheline;
+ qemu_cache_conf.icache_bsize = cacheline;
+}
+#endif
+
#ifdef __linux__
void qemu_cache_utils_init(char **envp)
{
diff --git a/configure b/configure
index 0a84b0ebcf..8eb5f5be9d 100755
--- a/configure
+++ b/configure
@@ -266,6 +266,7 @@ linux_aio=""
gprof="no"
debug_tcg="no"
+debug_mon="no"
debug="no"
strip_opt="yes"
bigendian="no"
@@ -440,6 +441,8 @@ fi
if test "$mingw32" = "yes" ; then
EXESUF=".exe"
QEMU_CFLAGS="-DWIN32_LEAN_AND_MEAN -DWINVER=0x501 $QEMU_CFLAGS"
+ # enable C99/POSIX format strings (needs mingw32-runtime 3.15 or later)
+ QEMU_CFLAGS="-D__USE_MINGW_ANSI_STDIO=1 $QEMU_CFLAGS"
LIBS="-lwinmm -lws2_32 -liphlpapi $LIBS"
fi
@@ -514,9 +517,14 @@ for opt do
;;
--disable-debug-tcg) debug_tcg="no"
;;
+ --enable-debug-mon) debug_mon="yes"
+ ;;
+ --disable-debug-mon) debug_mon="no"
+ ;;
--enable-debug)
# Enable debugging options that aren't excessively noisy
debug_tcg="yes"
+ debug_mon="yes"
debug="yes"
strip_opt="no"
;;
@@ -1918,6 +1926,7 @@ echo "host CPU $cpu"
echo "host big endian $bigendian"
echo "target list $target_list"
echo "tcg debug enabled $debug_tcg"
+echo "Mon debug enabled $debug_mon"
echo "gprof enabled $gprof"
echo "sparse enabled $sparse"
echo "strip binaries $strip_opt"
@@ -1995,6 +2004,9 @@ echo "ARCH=$ARCH" >> $config_host_mak
if test "$debug_tcg" = "yes" ; then
echo "CONFIG_DEBUG_TCG=y" >> $config_host_mak
fi
+if test "$debug_mon" = "yes" ; then
+ echo "CONFIG_DEBUG_MONITOR=y" >> $config_host_mak
+fi
if test "$debug" = "yes" ; then
echo "CONFIG_DEBUG_EXEC=y" >> $config_host_mak
fi
diff --git a/console.c b/console.c
index 8086bd6f20..8bcd00b470 100644
--- a/console.c
+++ b/console.c
@@ -154,6 +154,7 @@ struct TextConsole {
QEMUTimer *kbd_timer;
};
+static DisplayState *display_state;
static TextConsole *active_console;
static TextConsole *consoles[MAX_CONSOLES];
static int nb_consoles = 0;
@@ -1265,6 +1266,117 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
return s;
}
+static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
+{
+ DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
+
+ surface->width = width;
+ surface->height = height;
+ surface->linesize = width * 4;
+ surface->pf = qemu_default_pixelformat(32);
+#ifdef HOST_WORDS_BIGENDIAN
+ surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
+#else
+ surface->flags = QEMU_ALLOCATED_FLAG;
+#endif
+ surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
+
+ return surface;
+}
+
+static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
+ int width, int height)
+{
+ surface->width = width;
+ surface->height = height;
+ surface->linesize = width * 4;
+ surface->pf = qemu_default_pixelformat(32);
+ if (surface->flags & QEMU_ALLOCATED_FLAG)
+ surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
+ else
+ surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
+#ifdef HOST_WORDS_BIGENDIAN
+ surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
+#else
+ surface->flags = QEMU_ALLOCATED_FLAG;
+#endif
+
+ return surface;
+}
+
+DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
+ int linesize, uint8_t *data)
+{
+ DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
+
+ surface->width = width;
+ surface->height = height;
+ surface->linesize = linesize;
+ surface->pf = qemu_default_pixelformat(bpp);
+#ifdef HOST_WORDS_BIGENDIAN
+ surface->flags = QEMU_BIG_ENDIAN_FLAG;
+#endif
+ surface->data = data;
+
+ return surface;
+}
+
+static void defaultallocator_free_displaysurface(DisplaySurface *surface)
+{
+ if (surface == NULL)
+ return;
+ if (surface->flags & QEMU_ALLOCATED_FLAG)
+ qemu_free(surface->data);
+ qemu_free(surface);
+}
+
+static struct DisplayAllocator default_allocator = {
+ defaultallocator_create_displaysurface,
+ defaultallocator_resize_displaysurface,
+ defaultallocator_free_displaysurface
+};
+
+static void dumb_display_init(void)
+{
+ DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
+ ds->allocator = &default_allocator;
+ ds->surface = qemu_create_displaysurface(ds, 640, 480);
+ register_displaystate(ds);
+}
+
+/***********************************************************/
+/* register display */
+
+void register_displaystate(DisplayState *ds)
+{
+ DisplayState **s;
+ s = &display_state;
+ while (*s != NULL)
+ s = &(*s)->next;
+ ds->next = NULL;
+ *s = ds;
+}
+
+DisplayState *get_displaystate(void)
+{
+ if (!display_state) {
+ dumb_display_init ();
+ }
+ return display_state;
+}
+
+DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
+{
+ if(ds->allocator == &default_allocator) {
+ DisplaySurface *surf;
+ surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
+ defaultallocator_free_displaysurface(ds->surface);
+ ds->surface = surf;
+ ds->allocator = da;
+ }
+ return ds->allocator;
+}
+
DisplayState *graphic_console_init(vga_hw_update_ptr update,
vga_hw_invalidate_ptr invalidate,
vga_hw_screen_dump_ptr screen_dump,
@@ -1559,67 +1671,3 @@ PixelFormat qemu_default_pixelformat(int bpp)
}
return pf;
}
-
-DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
-{
- DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
-
- surface->width = width;
- surface->height = height;
- surface->linesize = width * 4;
- surface->pf = qemu_default_pixelformat(32);
-#ifdef HOST_WORDS_BIGENDIAN
- surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
-#else
- surface->flags = QEMU_ALLOCATED_FLAG;
-#endif
- surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
-
- return surface;
-}
-
-DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
- int width, int height)
-{
- surface->width = width;
- surface->height = height;
- surface->linesize = width * 4;
- surface->pf = qemu_default_pixelformat(32);
- if (surface->flags & QEMU_ALLOCATED_FLAG)
- surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
- else
- surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
-#ifdef HOST_WORDS_BIGENDIAN
- surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
-#else
- surface->flags = QEMU_ALLOCATED_FLAG;
-#endif
-
- return surface;
-}
-
-DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
- int linesize, uint8_t *data)
-{
- DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
-
- surface->width = width;
- surface->height = height;
- surface->linesize = linesize;
- surface->pf = qemu_default_pixelformat(bpp);
-#ifdef HOST_WORDS_BIGENDIAN
- surface->flags = QEMU_BIG_ENDIAN_FLAG;
-#endif
- surface->data = data;
-
- return surface;
-}
-
-void defaultallocator_free_displaysurface(DisplaySurface *surface)
-{
- if (surface == NULL)
- return;
- if (surface->flags & QEMU_ALLOCATED_FLAG)
- qemu_free(surface->data);
- qemu_free(surface);
-}
diff --git a/console.h b/console.h
index dfc8ae41d6..916859d5bc 100644
--- a/console.h
+++ b/console.h
@@ -144,11 +144,7 @@ DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
PixelFormat qemu_different_endianness_pixelformat(int bpp);
PixelFormat qemu_default_pixelformat(int bpp);
-extern struct DisplayAllocator default_allocator;
DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da);
-DisplaySurface* defaultallocator_create_displaysurface(int width, int height);
-DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface, int width, int height);
-void defaultallocator_free_displaysurface(DisplaySurface *surface);
static inline DisplaySurface* qemu_create_displaysurface(DisplayState *ds, int width, int height)
{
diff --git a/cpu-exec.c b/cpu-exec.c
index 4029ea25ff..184bddea31 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -210,8 +210,7 @@ static void cpu_handle_debug_exception(CPUState *env)
int cpu_exec(CPUState *env1)
{
-#define DECLARE_HOST_REGS 1
-#include "hostregs_helper.h"
+ host_reg_t saved_env_reg;
int ret, interrupt_request;
TranslationBlock *tb;
uint8_t *tc_ptr;
@@ -222,9 +221,12 @@ int cpu_exec(CPUState *env1)
cpu_single_env = env1;
- /* first we save global registers */
-#define SAVE_HOST_REGS 1
-#include "hostregs_helper.h"
+ /* the access to env below is actually saving the global register's
+ value, so that files not including target-xyz/exec.h are free to
+ use it. */
+ QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env));
+ saved_env_reg = (host_reg_t) env;
+ asm("");
env = env1;
#if defined(TARGET_I386)
@@ -671,7 +673,8 @@ int cpu_exec(CPUState *env1)
#endif
/* restore global registers */
-#include "hostregs_helper.h"
+ asm("");
+ env = (void *) saved_env_reg;
/* fail safe : never use cpu_single_env outside cpu_exec() */
cpu_single_env = NULL;
@@ -923,6 +926,20 @@ int cpu_signal_handler(int host_signum, void *pinfo,
# define TRAP_sig(context) REG_sig(trap, context)
#endif /* linux */
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <ucontext.h>
+# define IAR_sig(context) ((context)->uc_mcontext.mc_srr0)
+# define MSR_sig(context) ((context)->uc_mcontext.mc_srr1)
+# define CTR_sig(context) ((context)->uc_mcontext.mc_ctr)
+# define XER_sig(context) ((context)->uc_mcontext.mc_xer)
+# define LR_sig(context) ((context)->uc_mcontext.mc_lr)
+# define CR_sig(context) ((context)->uc_mcontext.mc_cr)
+/* Exception Registers access */
+# define DAR_sig(context) ((context)->uc_mcontext.mc_dar)
+# define DSISR_sig(context) ((context)->uc_mcontext.mc_dsisr)
+# define TRAP_sig(context) ((context)->uc_mcontext.mc_exc)
+#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
+
#ifdef __APPLE__
# include <sys/ucontext.h>
typedef struct ucontext SIGCONTEXT;
@@ -952,7 +969,11 @@ int cpu_signal_handler(int host_signum, void *pinfo,
void *puc)
{
siginfo_t *info = pinfo;
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ ucontext_t *uc = puc;
+#else
struct ucontext *uc = puc;
+#endif
unsigned long pc;
int is_write;
diff --git a/gdbstub.c b/gdbstub.c
index 80477be6a6..91c5f689d8 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1249,10 +1249,46 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
#define NUM_CORE_REGS 49
+static int
+read_register_crisv10(CPUState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 15) {
+ GET_REG32(env->regs[n]);
+ }
+
+ if (n == 15) {
+ GET_REG32(env->pc);
+ }
+
+ if (n < 32) {
+ switch (n) {
+ case 16:
+ GET_REG8(env->pregs[n - 16]);
+ break;
+ case 17:
+ GET_REG8(env->pregs[n - 16]);
+ break;
+ case 20:
+ case 21:
+ GET_REG16(env->pregs[n - 16]);
+ break;
+ default:
+ if (n >= 23) {
+ GET_REG32(env->pregs[n - 16]);
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
{
uint8_t srs;
+ if (env->pregs[PR_VR] < 32)
+ return read_register_crisv10(env, mem_buf, n);
+
srs = env->pregs[PR_SRS];
if (n < 16) {
GET_REG32(env->regs[n]);
diff --git a/hostregs_helper.h b/hostregs_helper.h
deleted file mode 100644
index 3a0bece81c..0000000000
--- a/hostregs_helper.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Save/restore host registers.
- *
- * Copyright (c) 2007 CodeSourcery
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/* The GCC global register variable extension is used to reserve some
- host registers for use by generated code. However only the core parts of
- the translation engine are compiled with these settings. We must manually
- save/restore these registers when called from regular code.
- It is not sufficient to save/restore T0 et. al. as these may be declared
- with a datatype smaller than the actual register. */
-
-#if defined(DECLARE_HOST_REGS)
-
-#define DO_REG(REG) \
- register host_reg_t reg_AREG##REG asm(AREG##REG); \
- volatile host_reg_t saved_AREG##REG;
-
-#elif defined(SAVE_HOST_REGS)
-
-#define DO_REG(REG) \
- __asm__ __volatile__ ("" : "=r" (reg_AREG##REG)); \
- saved_AREG##REG = reg_AREG##REG;
-
-#else
-
-#define DO_REG(REG) \
- reg_AREG##REG = saved_AREG##REG; \
- __asm__ __volatile__ ("" : : "r" (reg_AREG##REG));
-
-#endif
-
-#ifdef AREG0
-DO_REG(0)
-#endif
-
-#ifdef AREG1
-DO_REG(1)
-#endif
-
-#ifdef AREG2
-DO_REG(2)
-#endif
-
-#undef SAVE_HOST_REGS
-#undef DECLARE_HOST_REGS
-#undef DO_REG
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index ebfcd4153f..324e74eec4 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -29,6 +29,7 @@
#include "sysbus.h"
#include "pci.h"
#include "pci_host.h"
+#include "rwhandler.h"
#include "apb_pci.h"
/* debug APB */
@@ -65,6 +66,7 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
typedef struct APBState {
SysBusDevice busdev;
PCIHostState host_state;
+ ReadWriteHandler pci_config_handler;
uint32_t iommu[4];
uint32_t pci_control[16];
uint32_t pci_irq_map[8];
@@ -183,82 +185,28 @@ static CPUReadMemoryFunc * const apb_config_read[] = {
&apb_config_readl,
};
-static void apb_pci_config_write(APBState *s, target_phys_addr_t addr,
+static void apb_pci_config_write(ReadWriteHandler *h, pcibus_t addr,
uint32_t val, int size)
{
+ APBState *s = container_of(h, APBState, pci_config_handler);
+
+ val = qemu_bswap_len(val, size);
APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
- pci_data_write(s->host_state.bus, (addr & 0x00ffffff) | (1u << 31), val,
- size);
+ pci_data_write(s->host_state.bus, addr, val, size);
}
-static uint32_t apb_pci_config_read(APBState *s, target_phys_addr_t addr,
+static uint32_t apb_pci_config_read(ReadWriteHandler *h, pcibus_t addr,
int size)
{
uint32_t ret;
+ APBState *s = container_of(h, APBState, pci_config_handler);
- ret = pci_data_read(s->host_state.bus, (addr & 0x00ffffff) | (1u << 31),
- size);
+ ret = pci_data_read(s->host_state.bus, addr, size);
+ ret = qemu_bswap_len(ret, size);
APB_DPRINTF("%s: addr " TARGET_FMT_lx " -> %x\n", __func__, addr, ret);
return ret;
}
-static void apb_pci_config_writel(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- APBState *s = opaque;
-
- apb_pci_config_write(s, addr, bswap32(val), 4);
-}
-
-static void apb_pci_config_writew(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- APBState *s = opaque;
-
- apb_pci_config_write(s, addr, bswap16(val), 2);
-}
-
-static void apb_pci_config_writeb(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- APBState *s = opaque;
-
- apb_pci_config_write(s, addr, val, 1);
-}
-
-static uint32_t apb_pci_config_readl(void *opaque, target_phys_addr_t addr)
-{
- APBState *s = opaque;
-
- return bswap32(apb_pci_config_read(s, addr, 4));
-}
-
-static uint32_t apb_pci_config_readw(void *opaque, target_phys_addr_t addr)
-{
- APBState *s = opaque;
-
- return bswap16(apb_pci_config_read(s, addr, 2));
-}
-
-static uint32_t apb_pci_config_readb(void *opaque, target_phys_addr_t addr)
-{
- APBState *s = opaque;
-
- return apb_pci_config_read(s, addr, 1);
-}
-
-static CPUWriteMemoryFunc * const apb_pci_config_writes[] = {
- &apb_pci_config_writeb,
- &apb_pci_config_writew,
- &apb_pci_config_writel,
-};
-
-static CPUReadMemoryFunc * const apb_pci_config_reads[] = {
- &apb_pci_config_readb,
- &apb_pci_config_readw,
- &apb_pci_config_readl,
-};
-
static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
@@ -455,8 +403,10 @@ static int pci_pbm_init_device(SysBusDevice *dev)
pci_apb_iowrite, s);
sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
/* pci_config */
- pci_config = cpu_register_io_memory(apb_pci_config_reads,
- apb_pci_config_writes, s);
+ s->pci_config_handler.read = apb_pci_config_read;
+ s->pci_config_handler.write = apb_pci_config_write;
+ pci_config = cpu_register_io_memory_simple(&s->pci_config_handler);
+ assert(pci_config >= 0);
sysbus_init_mmio(dev, 0x1000000ULL, pci_config);
/* mem_data */
pci_mem_data = pci_host_data_register_mmio(&s->host_state);
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 37a5151570..2e0971ddeb 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -2650,6 +2650,7 @@ void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1,
s->unit = i;
s->drive_serial = drive_serial++;
s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4);
+ s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
s->smart_selftest_data = qemu_blockalign(s->bs, 512);
s->sector_write_timer = qemu_new_timer(vm_clock,
ide_sector_write_timer_cb, s);
@@ -2684,6 +2685,25 @@ static bool is_identify_set(void *opaque, int version_id)
return s->identify_set != 0;
}
+static EndTransferFunc* transfer_end_table[] = {
+ ide_sector_read,
+ ide_sector_write,
+ ide_transfer_stop,
+ ide_atapi_cmd_reply_end,
+ ide_atapi_cmd,
+};
+
+static int transfer_end_table_idx(EndTransferFunc *fn)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(transfer_end_table); i++)
+ if (transfer_end_table[i] == fn)
+ return i;
+
+ return -1;
+}
+
static int ide_drive_post_load(void *opaque, int version_id)
{
IDEState *s = opaque;
@@ -2694,14 +2714,45 @@ static int ide_drive_post_load(void *opaque, int version_id)
s->cdrom_changed = 1;
}
}
+
+ if (s->cur_io_buffer_len) {
+ s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
+ s->data_ptr = s->io_buffer + s->cur_io_buffer_offset;
+ s->data_end = s->data_ptr + s->cur_io_buffer_len;
+ }
+
return 0;
}
+static void ide_drive_pre_save(void *opaque)
+{
+ IDEState *s = opaque;
+ int idx;
+
+ s->cur_io_buffer_len = 0;
+
+ if (!(s->status & DRQ_STAT))
+ return;
+
+ s->cur_io_buffer_offset = s->data_ptr - s->io_buffer;
+ s->cur_io_buffer_len = s->data_end - s->data_ptr;
+
+ idx = transfer_end_table_idx(s->end_transfer_func);
+ if (idx == -1) {
+ fprintf(stderr, "%s: invalid end_transfer_func for DRQ_STAT\n",
+ __func__);
+ s->end_transfer_fn_idx = 2;
+ } else {
+ s->end_transfer_fn_idx = idx;
+ }
+}
+
const VMStateDescription vmstate_ide_drive = {
.name = "ide_drive",
- .version_id = 3,
+ .version_id = 4,
.minimum_version_id = 0,
.minimum_version_id_old = 0,
+ .pre_save = ide_drive_pre_save,
.post_load = ide_drive_post_load,
.fields = (VMStateField []) {
VMSTATE_INT32(mult_sectors, IDEState),
@@ -2724,7 +2775,14 @@ const VMStateDescription vmstate_ide_drive = {
VMSTATE_UINT8(sense_key, IDEState),
VMSTATE_UINT8(asc, IDEState),
VMSTATE_UINT8_V(cdrom_changed, IDEState, 3),
- /* XXX: if a transfer is pending, we do not save it yet */
+ VMSTATE_INT32_V(req_nb_sectors, IDEState, 4),
+ VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 4,
+ vmstate_info_uint8, uint8_t),
+ VMSTATE_INT32_V(cur_io_buffer_offset, IDEState, 4),
+ VMSTATE_INT32_V(cur_io_buffer_len, IDEState, 4),
+ VMSTATE_UINT8_V(end_transfer_fn_idx, IDEState, 4),
+ VMSTATE_INT32_V(elementary_transfer_size, IDEState, 4),
+ VMSTATE_INT32_V(packet_transfer_size, IDEState, 4),
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 9945993655..027029ecec 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -419,6 +419,11 @@ struct IDEState {
uint8_t *data_ptr;
uint8_t *data_end;
uint8_t *io_buffer;
+ /* PIO save/restore */
+ int32_t io_buffer_total_len;
+ int cur_io_buffer_offset;
+ int cur_io_buffer_len;
+ uint8_t end_transfer_fn_idx;
QEMUTimer *sector_write_timer; /* only used for win2k install hack */
uint32_t irq_count; /* counts IRQs when using win2k install hack */
/* CF-ATA extended error */
diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c
index 8ec3d99314..8f94c35ac3 100644
--- a/hw/mac_dbdma.c
+++ b/hw/mac_dbdma.c
@@ -402,7 +402,9 @@ static void start_output(DBDMA_channel *ch, int key, uint32_t addr,
ch->io.dma_end = dbdma_end;
ch->io.is_dma_out = 1;
ch->processing = 1;
- ch->rw(&ch->io);
+ if (ch->rw) {
+ ch->rw(&ch->io);
+ }
}
static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
@@ -425,7 +427,9 @@ static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
ch->io.dma_end = dbdma_end;
ch->io.is_dma_out = 0;
ch->processing = 1;
- ch->rw(&ch->io);
+ if (ch->rw) {
+ ch->rw(&ch->io);
+ }
}
static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
@@ -688,7 +692,7 @@ dbdma_control_write(DBDMA_channel *ch)
if (status & ACTIVE)
qemu_bh_schedule(dbdma_bh);
- if (status & FLUSH)
+ if ((status & FLUSH) && ch->flush)
ch->flush(&ch->io);
}
diff --git a/hw/pc.c b/hw/pc.c
index 6fbe98bb64..4f6a5228fd 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -59,6 +59,7 @@
#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
+#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
#define MAX_IDE_BUS 2
@@ -67,6 +68,21 @@ static RTCState *rtc_state;
static PITState *pit;
static PCII440FXState *i440fx_state;
+#define E820_NR_ENTRIES 16
+
+struct e820_entry {
+ uint64_t address;
+ uint64_t length;
+ uint32_t type;
+};
+
+struct e820_table {
+ uint32_t count;
+ struct e820_entry entry[E820_NR_ENTRIES];
+};
+
+static struct e820_table e820_table;
+
typedef struct isa_irq_state {
qemu_irq *i8259;
qemu_irq *ioapic;
@@ -435,6 +451,23 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
}
}
+int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
+{
+ int index = e820_table.count;
+ struct e820_entry *entry;
+
+ if (index >= E820_NR_ENTRIES)
+ return -EBUSY;
+ entry = &e820_table.entry[index];
+
+ entry->address = address;
+ entry->length = length;
+ entry->type = type;
+
+ e820_table.count++;
+ return e820_table.count;
+}
+
static void *bochs_bios_init(void)
{
void *fw_cfg;
@@ -466,6 +499,8 @@ static void *bochs_bios_init(void)
if (smbios_table)
fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
smbios_table, smbios_len);
+ fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, (uint8_t *)&e820_table,
+ sizeof(struct e820_table));
/* allocate memory for the NUMA channel: one (64bit) word for the number
* of nodes, one word for each VCPU->node and one word for each node to
@@ -1052,7 +1087,7 @@ void cmos_set_s3_resume(void)
}
static QEMUMachine pc_machine = {
- .name = "pc-0.12",
+ .name = "pc-0.13",
.alias = "pc",
.desc = "Standard PC",
.init = pc_init_pci,
@@ -1060,6 +1095,25 @@ static QEMUMachine pc_machine = {
.is_default = 1,
};
+static QEMUMachine pc_machine_v0_12 = {
+ .name = "pc-0.12",
+ .desc = "Standard PC",
+ .init = pc_init_pci,
+ .max_cpus = 255,
+ .compat_props = (GlobalProperty[]) {
+ {
+ .driver = "virtio-serial-pci",
+ .property = "max_nr_ports",
+ .value = stringify(1),
+ },{
+ .driver = "virtio-serial-pci",
+ .property = "vectors",
+ .value = stringify(0),
+ },
+ { /* end of list */ }
+ }
+};
+
static QEMUMachine pc_machine_v0_11 = {
.name = "pc-0.11",
.desc = "Standard PC, qemu 0.11",
@@ -1071,6 +1125,14 @@ static QEMUMachine pc_machine_v0_11 = {
.property = "vectors",
.value = stringify(0),
},{
+ .driver = "virtio-serial-pci",
+ .property = "max_nr_ports",
+ .value = stringify(1),
+ },{
+ .driver = "virtio-serial-pci",
+ .property = "vectors",
+ .value = stringify(0),
+ },{
.driver = "ide-drive",
.property = "ver",
.value = "0.11",
@@ -1102,6 +1164,14 @@ static QEMUMachine pc_machine_v0_10 = {
.property = "class",
.value = stringify(PCI_CLASS_DISPLAY_OTHER),
},{
+ .driver = "virtio-serial-pci",
+ .property = "max_nr_ports",
+ .value = stringify(1),
+ },{
+ .driver = "virtio-serial-pci",
+ .property = "vectors",
+ .value = stringify(0),
+ },{
.driver = "virtio-net-pci",
.property = "vectors",
.value = stringify(0),
@@ -1136,6 +1206,7 @@ static QEMUMachine isapc_machine = {
static void pc_machine_init(void)
{
qemu_register_machine(&pc_machine);
+ qemu_register_machine(&pc_machine_v0_12);
qemu_register_machine(&pc_machine_v0_11);
qemu_register_machine(&pc_machine_v0_10);
qemu_register_machine(&isapc_machine);
diff --git a/hw/pc.h b/hw/pc.h
index 03ffc91536..92f8563609 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -150,4 +150,14 @@ void isa_cirrus_vga_init(void);
void isa_ne2000_init(int base, int irq, NICInfo *nd);
int cpu_is_bsp(CPUState *env);
+
+/* e820 types */
+#define E820_RAM 1
+#define E820_RESERVED 2
+#define E820_ACPI 3
+#define E820_NVS 4
+#define E820_UNUSABLE 5
+
+int e820_add_entry(uint64_t, uint64_t, uint32_t);
+
#endif
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index 0fb96f06fd..bd82c6aab7 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -254,7 +254,7 @@ void pci_device_hot_add_print(Monitor *mon, const QObject *data)
*
* { "domain": 0, "bus": 0, "slot": 5, "function": 0 }
*/
-void pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
+int pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
PCIDevice *dev = NULL;
const char *pci_addr = qdict_get_str(qdict, "pci_addr");
@@ -273,43 +273,49 @@ void pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
if (!strcmp(pci_addr, "auto"))
pci_addr = NULL;
- if (strcmp(type, "nic") == 0)
+ if (strcmp(type, "nic") == 0) {
dev = qemu_pci_hot_add_nic(mon, pci_addr, opts);
- else if (strcmp(type, "storage") == 0)
+ } else if (strcmp(type, "storage") == 0) {
dev = qemu_pci_hot_add_storage(mon, pci_addr, opts);
- else
+ } else {
monitor_printf(mon, "invalid type: %s\n", type);
+ return -1;
+ }
if (dev) {
*ret_data =
qobject_from_jsonf("{ 'domain': 0, 'bus': %d, 'slot': %d, "
"'function': %d }", pci_bus_num(dev->bus),
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
- } else
+ } else {
monitor_printf(mon, "failed to add %s\n", opts);
+ return -1;
+ }
+
+ return 0;
}
#endif
-void pci_device_hot_remove(Monitor *mon, const char *pci_addr)
+int pci_device_hot_remove(Monitor *mon, const char *pci_addr)
{
PCIDevice *d;
int dom, bus;
unsigned slot;
if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) {
- return;
+ return -1;
}
d = pci_find_device(pci_find_root_bus(0), bus, slot, 0);
if (!d) {
monitor_printf(mon, "slot %d empty\n", slot);
- return;
+ return -1;
}
- qdev_unplug(&d->qdev);
+ return qdev_unplug(&d->qdev);
}
-void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict,
- QObject **ret_data)
+int do_pci_device_hot_remove(Monitor *mon, const QDict *qdict,
+ QObject **ret_data)
{
- pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr"));
+ return pci_device_hot_remove(mon, qdict_get_str(qdict, "pci_addr"));
}
diff --git a/hw/pci.h b/hw/pci.h
index 8b511d243c..37ebdc423c 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -70,7 +70,6 @@
#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002
#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003
-typedef uint64_t pcibus_t;
#define FMT_PCIBUS PRIx64
typedef void PCIConfigWriteFunc(PCIDevice *pci_dev,
diff --git a/hw/pci_host.c b/hw/pci_host.c
index 6289ead3b3..b15d5faef7 100644
--- a/hw/pci_host.c
+++ b/hw/pci_host.c
@@ -79,152 +79,120 @@ uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len)
return val;
}
-static void pci_host_config_writel(void *opaque, target_phys_addr_t addr,
- uint32_t val)
+static void pci_host_config_write(ReadWriteHandler *handler,
+ pcibus_t addr, uint32_t val, int len)
{
- PCIHostState *s = opaque;
+ PCIHostState *s = container_of(handler, PCIHostState, conf_handler);
+ PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n",
+ __func__, addr, len, val);
#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
+ val = qemu_bswap_len(val, len);
#endif
- PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n",
- __func__, addr, val);
s->config_reg = val;
}
-static uint32_t pci_host_config_readl(void *opaque, target_phys_addr_t addr)
+static uint32_t pci_host_config_read(ReadWriteHandler *handler,
+ pcibus_t addr, int len)
{
- PCIHostState *s = opaque;
+ PCIHostState *s = container_of(handler, PCIHostState, conf_handler);
uint32_t val = s->config_reg;
-
#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
+ val = qemu_bswap_len(val, len);
#endif
- PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n",
- __func__, addr, val);
+ PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n",
+ __func__, addr, len, val);
return val;
}
-static CPUWriteMemoryFunc * const pci_host_config_write[] = {
- &pci_host_config_writel,
- &pci_host_config_writel,
- &pci_host_config_writel,
-};
-
-static CPUReadMemoryFunc * const pci_host_config_read[] = {
- &pci_host_config_readl,
- &pci_host_config_readl,
- &pci_host_config_readl,
-};
-
-int pci_host_conf_register_mmio(PCIHostState *s)
-{
- return cpu_register_io_memory(pci_host_config_read,
- pci_host_config_write, s);
-}
-
-static void pci_host_config_writel_noswap(void *opaque,
- target_phys_addr_t addr,
- uint32_t val)
+static void pci_host_config_write_noswap(ReadWriteHandler *handler,
+ pcibus_t addr, uint32_t val, int len)
{
- PCIHostState *s = opaque;
+ PCIHostState *s = container_of(handler, PCIHostState, conf_noswap_handler);
- PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n",
- __func__, addr, val);
+ PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n",
+ __func__, addr, len, val);
s->config_reg = val;
}
-static uint32_t pci_host_config_readl_noswap(void *opaque,
- target_phys_addr_t addr)
+static uint32_t pci_host_config_read_noswap(ReadWriteHandler *handler,
+ pcibus_t addr, int len)
{
- PCIHostState *s = opaque;
+ PCIHostState *s = container_of(handler, PCIHostState, conf_noswap_handler);
uint32_t val = s->config_reg;
- PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n",
- __func__, addr, val);
+ PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n",
+ __func__, addr, len, val);
return val;
}
-static CPUWriteMemoryFunc * const pci_host_config_write_noswap[] = {
- &pci_host_config_writel_noswap,
- &pci_host_config_writel_noswap,
- &pci_host_config_writel_noswap,
-};
-
-static CPUReadMemoryFunc * const pci_host_config_read_noswap[] = {
- &pci_host_config_readl_noswap,
- &pci_host_config_readl_noswap,
- &pci_host_config_readl_noswap,
-};
-
-int pci_host_conf_register_mmio_noswap(PCIHostState *s)
+static void pci_host_data_write(ReadWriteHandler *handler,
+ pcibus_t addr, uint32_t val, int len)
{
- return cpu_register_io_memory(pci_host_config_read_noswap,
- pci_host_config_write_noswap, s);
+ PCIHostState *s = container_of(handler, PCIHostState, data_handler);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = qemu_bswap_len(val, len);
+#endif
+ PCI_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n",
+ addr, len, val);
+ if (s->config_reg & (1u << 31))
+ pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
}
-static void pci_host_config_writel_ioport(void *opaque,
- uint32_t addr, uint32_t val)
+static uint32_t pci_host_data_read(ReadWriteHandler *handler,
+ pcibus_t addr, int len)
{
- PCIHostState *s = opaque;
+ PCIHostState *s = container_of(handler, PCIHostState, data_handler);
+ uint32_t val;
+ if (!(s->config_reg & (1 << 31)))
+ return 0xffffffff;
+ val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
+ PCI_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n",
+ addr, len, val);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = qemu_bswap_len(val, len);
+#endif
+ return val;
+}
- PCI_DPRINTF("%s addr %"PRIx32 " val %"PRIx32"\n", __func__, addr, val);
- s->config_reg = val;
+static void pci_host_init(PCIHostState *s)
+{
+ s->conf_handler.write = pci_host_config_write;
+ s->conf_handler.read = pci_host_config_read;
+ s->conf_noswap_handler.write = pci_host_config_write_noswap;
+ s->conf_noswap_handler.read = pci_host_config_read_noswap;
+ s->data_handler.write = pci_host_data_write;
+ s->data_handler.read = pci_host_data_read;
}
-static uint32_t pci_host_config_readl_ioport(void *opaque, uint32_t addr)
+int pci_host_conf_register_mmio(PCIHostState *s)
{
- PCIHostState *s = opaque;
- uint32_t val = s->config_reg;
+ pci_host_init(s);
+ return cpu_register_io_memory_simple(&s->conf_handler);
+}
- PCI_DPRINTF("%s addr %"PRIx32" val %"PRIx32"\n", __func__, addr, val);
- return val;
+int pci_host_conf_register_mmio_noswap(PCIHostState *s)
+{
+ pci_host_init(s);
+ return cpu_register_io_memory_simple(&s->conf_noswap_handler);
}
void pci_host_conf_register_ioport(pio_addr_t ioport, PCIHostState *s)
{
- register_ioport_write(ioport, 4, 4, pci_host_config_writel_ioport, s);
- register_ioport_read(ioport, 4, 4, pci_host_config_readl_ioport, s);
+ pci_host_init(s);
+ register_ioport_simple(&s->conf_noswap_handler, ioport, 4, 4);
}
-#define PCI_ADDR_T target_phys_addr_t
-#define PCI_HOST_SUFFIX _mmio
-
-#include "pci_host_template.h"
-
-static CPUWriteMemoryFunc * const pci_host_data_write_mmio[] = {
- pci_host_data_writeb_mmio,
- pci_host_data_writew_mmio,
- pci_host_data_writel_mmio,
-};
-
-static CPUReadMemoryFunc * const pci_host_data_read_mmio[] = {
- pci_host_data_readb_mmio,
- pci_host_data_readw_mmio,
- pci_host_data_readl_mmio,
-};
-
int pci_host_data_register_mmio(PCIHostState *s)
{
- return cpu_register_io_memory(pci_host_data_read_mmio,
- pci_host_data_write_mmio,
- s);
+ pci_host_init(s);
+ return cpu_register_io_memory_simple(&s->data_handler);
}
-#undef PCI_ADDR_T
-#undef PCI_HOST_SUFFIX
-
-#define PCI_ADDR_T uint32_t
-#define PCI_HOST_SUFFIX _ioport
-
-#include "pci_host_template.h"
-
void pci_host_data_register_ioport(pio_addr_t ioport, PCIHostState *s)
{
- register_ioport_write(ioport, 4, 1, pci_host_data_writeb_ioport, s);
- register_ioport_write(ioport, 4, 2, pci_host_data_writew_ioport, s);
- register_ioport_write(ioport, 4, 4, pci_host_data_writel_ioport, s);
- register_ioport_read(ioport, 4, 1, pci_host_data_readb_ioport, s);
- register_ioport_read(ioport, 4, 2, pci_host_data_readw_ioport, s);
- register_ioport_read(ioport, 4, 4, pci_host_data_readl_ioport, s);
+ pci_host_init(s);
+ register_ioport_simple(&s->data_handler, ioport, 4, 1);
+ register_ioport_simple(&s->data_handler, ioport, 4, 2);
+ register_ioport_simple(&s->data_handler, ioport, 4, 4);
}
diff --git a/hw/pci_host.h b/hw/pci_host.h
index a006687f8b..5ff64430ed 100644
--- a/hw/pci_host.h
+++ b/hw/pci_host.h
@@ -29,9 +29,13 @@
#define PCI_HOST_H
#include "sysbus.h"
+#include "rwhandler.h"
struct PCIHostState {
SysBusDevice busdev;
+ ReadWriteHandler conf_noswap_handler;
+ ReadWriteHandler conf_handler;
+ ReadWriteHandler data_handler;
uint32_t config_reg;
PCIBus *bus;
};
diff --git a/hw/pci_host_template.h b/hw/pci_host_template.h
deleted file mode 100644
index 11e6c88fd7..0000000000
--- a/hw/pci_host_template.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * QEMU Common PCI Host bridge configuration data space access routines.
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* Worker routines for a PCI host controller that uses an {address,data}
- register pair to access PCI configuration space. */
-
-static void glue(pci_host_data_writeb, PCI_HOST_SUFFIX)(
- void* opaque, PCI_ADDR_T addr, uint32_t val)
-{
- PCIHostState *s = opaque;
-
- PCI_DPRINTF("writeb addr " TARGET_FMT_plx " val %x\n",
- (target_phys_addr_t)addr, val);
- if (s->config_reg & (1u << 31))
- pci_data_write(s->bus, s->config_reg | (addr & 3), val, 1);
-}
-
-static void glue(pci_host_data_writew, PCI_HOST_SUFFIX)(
- void* opaque, PCI_ADDR_T addr, uint32_t val)
-{
- PCIHostState *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- PCI_DPRINTF("writew addr " TARGET_FMT_plx " val %x\n",
- (target_phys_addr_t)addr, val);
- if (s->config_reg & (1u << 31))
- pci_data_write(s->bus, s->config_reg | (addr & 3), val, 2);
-}
-
-static void glue(pci_host_data_writel, PCI_HOST_SUFFIX)(
- void* opaque, PCI_ADDR_T addr, uint32_t val)
-{
- PCIHostState *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- PCI_DPRINTF("writel addr " TARGET_FMT_plx " val %x\n",
- (target_phys_addr_t)addr, val);
- if (s->config_reg & (1u << 31))
- pci_data_write(s->bus, s->config_reg, val, 4);
-}
-
-static uint32_t glue(pci_host_data_readb, PCI_HOST_SUFFIX)(
- void* opaque, PCI_ADDR_T addr)
-{
- PCIHostState *s = opaque;
- uint32_t val;
-
- if (!(s->config_reg & (1 << 31)))
- return 0xff;
- val = pci_data_read(s->bus, s->config_reg | (addr & 3), 1);
- PCI_DPRINTF("readb addr " TARGET_FMT_plx " val %x\n",
- (target_phys_addr_t)addr, val);
- return val;
-}
-
-static uint32_t glue(pci_host_data_readw, PCI_HOST_SUFFIX)(
- void* opaque, PCI_ADDR_T addr)
-{
- PCIHostState *s = opaque;
- uint32_t val;
- if (!(s->config_reg & (1 << 31)))
- return 0xffff;
- val = pci_data_read(s->bus, s->config_reg | (addr & 3), 2);
- PCI_DPRINTF("readw addr " TARGET_FMT_plx " val %x\n",
- (target_phys_addr_t)addr, val);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- return val;
-}
-
-static uint32_t glue(pci_host_data_readl, PCI_HOST_SUFFIX)(
- void* opaque, PCI_ADDR_T addr)
-{
- PCIHostState *s = opaque;
- uint32_t val;
- if (!(s->config_reg & (1 << 31)))
- return 0xffffffff;
- val = pci_data_read(s->bus, s->config_reg | (addr & 3), 4);
- PCI_DPRINTF("readl addr " TARGET_FMT_plx " val %x\n",
- (target_phys_addr_t)addr, val);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- return val;
-}
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index 63379c234a..fe7a121562 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -63,6 +63,7 @@
#define PCI_VENDOR_ID_APPLE 0x106b
#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020
+#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b
#define PCI_VENDOR_ID_SUN 0x108e
#define PCI_DEVICE_ID_SUN_EBUS 0x1000
diff --git a/hw/pl181.c b/hw/pl181.c
index 7282053053..1924053330 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -182,39 +182,40 @@ error:
static void pl181_fifo_run(pl181_state *s)
{
uint32_t bits;
- uint32_t value;
+ uint32_t value = 0;
int n;
- int limit;
int is_read;
is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
&& !s->linux_hack) {
- limit = is_read ? PL181_FIFO_LEN : 0;
- n = 0;
- value = 0;
- while (s->datacnt && s->fifo_len != limit) {
- if (is_read) {
+ if (is_read) {
+ n = 0;
+ while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
value |= (uint32_t)sd_read_data(s->card) << (n * 8);
+ s->datacnt--;
n++;
if (n == 4) {
pl181_fifo_push(s, value);
- value = 0;
n = 0;
+ value = 0;
}
- } else {
+ }
+ if (n != 0) {
+ pl181_fifo_push(s, value);
+ }
+ } else { /* write */
+ n = 0;
+ while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) {
if (n == 0) {
value = pl181_fifo_pop(s);
n = 4;
}
+ n--;
+ s->datacnt--;
sd_write_data(s->card, value & 0xff);
value >>= 8;
- n--;
}
- s->datacnt--;
- }
- if (n && is_read) {
- pl181_fifo_push(s, value);
}
}
s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
diff --git a/hw/ppc.h b/hw/ppc.h
index bbf3a986b6..de13092ae4 100644
--- a/hw/ppc.h
+++ b/hw/ppc.h
@@ -40,10 +40,12 @@ enum {
ARCH_PREP = 0,
ARCH_MAC99,
ARCH_HEATHROW,
+ ARCH_MAC99_U3,
};
#define FW_CFG_PPC_WIDTH (FW_CFG_ARCH_LOCAL + 0x00)
#define FW_CFG_PPC_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
#define FW_CFG_PPC_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
+#define FW_CFG_PPC_TBFREQ (FW_CFG_ARCH_LOCAL + 0x03)
#define PPC_SERIAL_MM_BAUDBASE 399193
diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
index a04dffea84..89f96bbc34 100644
--- a/hw/ppc_mac.h
+++ b/hw/ppc_mac.h
@@ -58,6 +58,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic);
/* UniNorth PCI */
PCIBus *pci_pmac_init(qemu_irq *pic);
+PCIBus *pci_pmac_u3_init(qemu_irq *pic);
/* Mac NVRAM */
typedef struct MacIONVRAMState MacIONVRAMState;
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index a4c714ae7f..bc86c851e7 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -21,6 +21,30 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
+ *
+ * PCI bus layout on a real G5 (U3 based):
+ *
+ * 0000:f0:0b.0 Host bridge [0600]: Apple Computer Inc. U3 AGP [106b:004b]
+ * 0000:f0:10.0 VGA compatible controller [0300]: ATI Technologies Inc RV350 AP [Radeon 9600] [1002:4150]
+ * 0001:00:00.0 Host bridge [0600]: Apple Computer Inc. CPC945 HT Bridge [106b:004a]
+ * 0001:00:01.0 PCI bridge [0604]: Advanced Micro Devices [AMD] AMD-8131 PCI-X Bridge [1022:7450] (rev 12)
+ * 0001:00:02.0 PCI bridge [0604]: Advanced Micro Devices [AMD] AMD-8131 PCI-X Bridge [1022:7450] (rev 12)
+ * 0001:00:03.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0045]
+ * 0001:00:04.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0046]
+ * 0001:00:05.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0047]
+ * 0001:00:06.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0048]
+ * 0001:00:07.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0049]
+ * 0001:01:07.0 Class [ff00]: Apple Computer Inc. K2 KeyLargo Mac/IO [106b:0041] (rev 20)
+ * 0001:01:08.0 USB Controller [0c03]: Apple Computer Inc. K2 KeyLargo USB [106b:0040]
+ * 0001:01:09.0 USB Controller [0c03]: Apple Computer Inc. K2 KeyLargo USB [106b:0040]
+ * 0001:02:0b.0 USB Controller [0c03]: NEC Corporation USB [1033:0035] (rev 43)
+ * 0001:02:0b.1 USB Controller [0c03]: NEC Corporation USB [1033:0035] (rev 43)
+ * 0001:02:0b.2 USB Controller [0c03]: NEC Corporation USB 2.0 [1033:00e0] (rev 04)
+ * 0001:03:0d.0 Class [ff00]: Apple Computer Inc. K2 ATA/100 [106b:0043]
+ * 0001:03:0e.0 FireWire (IEEE 1394) [0c00]: Apple Computer Inc. K2 FireWire [106b:0042]
+ * 0001:04:0f.0 Ethernet controller [0200]: Apple Computer Inc. K2 GMAC (Sun GEM) [106b:004c]
+ * 0001:05:0c.0 IDE interface [0101]: Broadcom K2 SATA [1166:0240]
+ *
*/
#include "hw.h"
#include "ppc.h"
@@ -40,6 +64,8 @@
#include "loader.h"
#include "elf.h"
#include "kvm.h"
+#include "kvm_ppc.h"
+#include "hw/usb.h"
#define MAX_IDE_BUS 2
#define VGA_BIOS_SIZE 65536
@@ -109,11 +135,13 @@ static void ppc_core99_init (ram_addr_t ram_size,
int nvram_mem_index;
int vga_bios_size, bios_size;
int pic_mem_index, dbdma_mem_index, cuda_mem_index, escc_mem_index;
+ int ide_mem_index[3];
int ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
void *fw_cfg;
void *dbdma;
uint8_t *vga_bios_ptr;
+ int machine_arch;
linux_boot = (kernel_filename != NULL);
@@ -317,7 +345,14 @@ static void ppc_core99_init (ram_addr_t ram_size,
}
}
pic = openpic_init(NULL, &pic_mem_index, smp_cpus, openpic_irqs, NULL);
- pci_bus = pci_pmac_init(pic);
+ if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
+ /* 970 gets a U3 bus */
+ pci_bus = pci_pmac_u3_init(pic);
+ machine_arch = ARCH_MAC99_U3;
+ } else {
+ pci_bus = pci_pmac_init(pic);
+ machine_arch = ARCH_MAC99;
+ }
/* init basic PC hardware */
pci_vga_init(pci_bus, vga_bios_offset, vga_bios_size);
@@ -331,27 +366,41 @@ static void ppc_core99_init (ram_addr_t ram_size,
fprintf(stderr, "qemu: too many IDE bus\n");
exit(1);
}
- for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
- hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
- }
dbdma = DBDMA_init(&dbdma_mem_index);
- pci_cmd646_ide_init(pci_bus, hd, 0);
+
+ /* We only emulate 2 out of 3 IDE controllers for now */
+ ide_mem_index[0] = -1;
+ hd[0] = drive_get(IF_IDE, 0, 0);
+ hd[1] = drive_get(IF_IDE, 0, 1);
+ ide_mem_index[1] = pmac_ide_init(hd, pic[0x0d], dbdma, 0x16, pic[0x02]);
+ hd[0] = drive_get(IF_IDE, 1, 0);
+ hd[1] = drive_get(IF_IDE, 1, 1);
+ ide_mem_index[2] = pmac_ide_init(hd, pic[0x0e], dbdma, 0x1a, pic[0x02]);
/* cuda also initialize ADB */
+ if (machine_arch == ARCH_MAC99_U3) {
+ usb_enabled = 1;
+ }
cuda_init(&cuda_mem_index, pic[0x19]);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
-
macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem_index,
- dbdma_mem_index, cuda_mem_index, NULL, 0, NULL,
+ dbdma_mem_index, cuda_mem_index, NULL, 3, ide_mem_index,
escc_mem_index);
if (usb_enabled) {
usb_ohci_init_pci(pci_bus, -1);
}
+ /* U3 needs to use USB for input because Linux doesn't support via-cuda
+ on PPC64 */
+ if (machine_arch == ARCH_MAC99_U3) {
+ usbdevice_create("keyboard");
+ usbdevice_create("mouse");
+ }
+
if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
graphic_depth = 15;
@@ -364,7 +413,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
- fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, ARCH_MAC99);
+ fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, machine_arch);
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base);
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
if (kernel_cmdline) {
@@ -381,6 +430,14 @@ static void ppc_core99_init (ram_addr_t ram_size,
fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
+ if (kvm_enabled()) {
+#ifdef CONFIG_KVM
+ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
+#endif
+ } else {
+ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());
+ }
+
qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
}
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 7ccc6a1471..04a78358dd 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -40,6 +40,7 @@
#include "loader.h"
#include "elf.h"
#include "kvm.h"
+#include "kvm_ppc.h"
#define MAX_IDE_BUS 2
#define VGA_BIOS_SIZE 65536
@@ -401,6 +402,14 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
+ if (kvm_enabled()) {
+#ifdef CONFIG_KVM
+ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
+#endif
+ } else {
+ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());
+ }
+
qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
}
diff --git a/hw/qdev.c b/hw/qdev.c
index 539b5a2009..d0052d436c 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -749,8 +749,11 @@ void do_device_add(Monitor *mon, const QDict *qdict)
opts = qemu_opts_parse(&qemu_device_opts,
qdict_get_str(qdict, "config"), "driver");
- if (opts && !qdev_device_help(opts))
- qdev_device_add(opts);
+ if (opts) {
+ if (qdev_device_help(opts) || qdev_device_add(opts) == NULL) {
+ qemu_opts_del(opts);
+ }
+ }
}
void do_device_del(Monitor *mon, const QDict *qdict)
diff --git a/hw/serial.c b/hw/serial.c
index e7538ac8ca..df67383d06 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -169,11 +169,19 @@ static int fifo_put(SerialState *s, int fifo, uint8_t chr)
{
SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
- f->data[f->head++] = chr;
+ /* Receive overruns do not overwrite FIFO contents. */
+ if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH) {
- if (f->head == UART_FIFO_LENGTH)
- f->head = 0;
- f->count++;
+ f->data[f->head++] = chr;
+
+ if (f->head == UART_FIFO_LENGTH)
+ f->head = 0;
+ }
+
+ if (f->count < UART_FIFO_LENGTH)
+ f->count++;
+ else if (fifo == RECV_FIFO)
+ s->lsr |= UART_LSR_OE;
return 1;
}
@@ -533,8 +541,10 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
break;
case 2:
ret = s->iir;
+ if (ret & UART_IIR_THRI) {
s->thr_ipending = 0;
- serial_update_irq(s);
+ serial_update_irq(s);
+ }
break;
case 3:
ret = s->lcr;
@@ -544,9 +554,9 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
break;
case 5:
ret = s->lsr;
- /* Clear break interrupt */
- if (s->lsr & UART_LSR_BI) {
- s->lsr &= ~UART_LSR_BI;
+ /* Clear break and overrun interrupts */
+ if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) {
+ s->lsr &= ~(UART_LSR_BI|UART_LSR_OE);
serial_update_irq(s);
}
break;
@@ -629,6 +639,8 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size)
/* call the timeout receive callback in 4 char transmit time */
qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock (vm_clock) + s->char_transmit_time * 4);
} else {
+ if (s->lsr & UART_LSR_DR)
+ s->lsr |= UART_LSR_OE;
s->rbr = buf[0];
s->lsr |= UART_LSR_DR;
}
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 19eb5e0ad7..7bdf430346 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -36,22 +36,31 @@
#define UNIN_DPRINTF(fmt, ...)
#endif
+static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
+
typedef struct UNINState {
SysBusDevice busdev;
PCIHostState host_state;
+ ReadWriteHandler data_handler;
} UNINState;
-/* Don't know if this matches real hardware, but it agrees with OHW. */
static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
{
- return (irq_num + (pci_dev->devfn >> 3)) & 3;
+ int retval;
+ int devfn = pci_dev->devfn & 0x00FFFFFF;
+
+ retval = (((devfn >> 11) & 0x1F) + irq_num) & 3;
+
+ return retval;
}
static void pci_unin_set_irq(void *opaque, int irq_num, int level)
{
qemu_irq *pic = opaque;
- qemu_set_irq(pic[irq_num + 8], level);
+ UNIN_DPRINTF("%s: setting INT %d = %d\n", __func__,
+ unin_irq_line[irq_num], level);
+ qemu_set_irq(pic[unin_irq_line[irq_num]], level);
}
static void pci_unin_save(QEMUFile* f, void *opaque)
@@ -75,6 +84,68 @@ static void pci_unin_reset(void *opaque)
{
}
+static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
+{
+ uint32_t retval;
+
+ if (reg & (1u << 31)) {
+ /* XXX OpenBIOS compatibility hack */
+ retval = reg | (addr & 3);
+ } else if (reg & 1) {
+ /* CFA1 style */
+ retval = (reg & ~7u) | (addr & 7);
+ } else {
+ uint32_t slot, func;
+
+ /* Grab CFA0 style values */
+ slot = ffs(reg & 0xfffff800) - 1;
+ func = (reg >> 8) & 7;
+
+ /* ... and then convert them to x86 format */
+ /* config pointer */
+ retval = (reg & (0xff - 7)) | (addr & 7);
+ /* slot */
+ retval |= slot << 11;
+ /* fn */
+ retval |= func << 8;
+ }
+
+
+ UNIN_DPRINTF("Converted config space accessor %08x/%08x -> %08x\n",
+ reg, addr, retval);
+
+ return retval;
+}
+
+static void unin_data_write(ReadWriteHandler *handler,
+ pcibus_t addr, uint32_t val, int len)
+{
+ UNINState *s = container_of(handler, UNINState, data_handler);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = qemu_bswap_len(val, len);
+#endif
+ UNIN_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val);
+ pci_data_write(s->host_state.bus,
+ unin_get_config_reg(s->host_state.config_reg, addr),
+ val, len);
+}
+
+static uint32_t unin_data_read(ReadWriteHandler *handler,
+ pcibus_t addr, int len)
+{
+ UNINState *s = container_of(handler, UNINState, data_handler);
+ uint32_t val;
+
+ val = pci_data_read(s->host_state.bus,
+ unin_get_config_reg(s->host_state.config_reg, addr),
+ len);
+ UNIN_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = qemu_bswap_len(val, len);
+#endif
+ return val;
+}
+
static int pci_unin_main_init_device(SysBusDevice *dev)
{
UNINState *s;
@@ -85,7 +156,9 @@ static int pci_unin_main_init_device(SysBusDevice *dev)
s = FROM_SYSBUS(UNINState, dev);
pci_mem_config = pci_host_conf_register_mmio(&s->host_state);
- pci_mem_data = pci_host_data_register_mmio(&s->host_state);
+ s->data_handler.read = unin_data_read;
+ s->data_handler.write = unin_data_write;
+ pci_mem_data = cpu_register_io_memory_simple(&s->data_handler);
sysbus_init_mmio(dev, 0x1000, pci_mem_config);
sysbus_init_mmio(dev, 0x1000, pci_mem_data);
@@ -94,6 +167,27 @@ static int pci_unin_main_init_device(SysBusDevice *dev)
return 0;
}
+static int pci_u3_agp_init_device(SysBusDevice *dev)
+{
+ UNINState *s;
+ int pci_mem_config, pci_mem_data;
+
+ /* Uninorth U3 AGP bus */
+ s = FROM_SYSBUS(UNINState, dev);
+
+ pci_mem_config = pci_host_conf_register_mmio(&s->host_state);
+ s->data_handler.read = unin_data_read;
+ s->data_handler.write = unin_data_write;
+ pci_mem_data = cpu_register_io_memory_simple(&s->data_handler);
+ sysbus_init_mmio(dev, 0x1000, pci_mem_config);
+ sysbus_init_mmio(dev, 0x1000, pci_mem_data);
+
+ register_savevm("uninorth", 0, 1, pci_unin_save, pci_unin_load, &s->host_state);
+ qemu_register_reset(pci_unin_reset, &s->host_state);
+
+ return 0;
+}
+
static int pci_unin_agp_init_device(SysBusDevice *dev)
{
UNINState *s;
@@ -175,6 +269,31 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
return d->host_state.bus;
}
+PCIBus *pci_pmac_u3_init(qemu_irq *pic)
+{
+ DeviceState *dev;
+ SysBusDevice *s;
+ UNINState *d;
+
+ /* Uninorth AGP bus */
+
+ dev = qdev_create(NULL, "u3-agp");
+ qdev_init_nofail(dev);
+ s = sysbus_from_qdev(dev);
+ d = FROM_SYSBUS(UNINState, s);
+
+ d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
+ pci_unin_set_irq, pci_unin_map_irq,
+ pic, 11 << 3, 4);
+
+ sysbus_mmio_map(s, 0, 0xf0800000);
+ sysbus_mmio_map(s, 1, 0xf0c00000);
+
+ pci_create_simple(d->host_state.bus, 11 << 3, "u3-agp");
+
+ return d->host_state.bus;
+}
+
static int unin_main_pci_host_init(PCIDevice *d)
{
pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
@@ -201,6 +320,21 @@ static int unin_agp_pci_host_init(PCIDevice *d)
return 0;
}
+static int u3_agp_pci_host_init(PCIDevice *d)
+{
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
+ pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_U3_AGP);
+ /* revision */
+ d->config[0x08] = 0x00;
+ pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
+ /* cache line size */
+ d->config[0x0C] = 0x08;
+ /* latency timer */
+ d->config[0x0D] = 0x10;
+ d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;
+ return 0;
+}
+
static int unin_internal_pci_host_init(PCIDevice *d)
{
pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
@@ -220,6 +354,12 @@ static PCIDeviceInfo unin_main_pci_host_info = {
.init = unin_main_pci_host_init,
};
+static PCIDeviceInfo u3_agp_pci_host_info = {
+ .qdev.name = "u3-agp",
+ .qdev.size = sizeof(PCIDevice),
+ .init = u3_agp_pci_host_init,
+};
+
static PCIDeviceInfo unin_agp_pci_host_info = {
.qdev.name = "uni-north-agp",
.qdev.size = sizeof(PCIDevice),
@@ -237,6 +377,9 @@ static void unin_register_devices(void)
sysbus_register_dev("uni-north", sizeof(UNINState),
pci_unin_main_init_device);
pci_qdev_register(&unin_main_pci_host_info);
+ sysbus_register_dev("u3-agp", sizeof(UNINState),
+ pci_u3_agp_init_device);
+ pci_qdev_register(&u3_agp_pci_host_info);
sysbus_register_dev("uni-north-agp", sizeof(UNINState),
pci_unin_agp_init_device);
pci_qdev_register(&unin_agp_pci_host_info);
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 4f320d7763..bf456bbadf 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -66,6 +66,7 @@ typedef struct USBHIDState {
int kind;
int protocol;
uint8_t idle;
+ int64_t next_idle_clock;
int changed;
void *datain_opaque;
void (*datain)(void *);
@@ -630,6 +631,11 @@ static void usb_keyboard_handle_reset(USBDevice *dev)
s->protocol = 1;
}
+static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
+{
+ s->next_idle_clock = curtime + (get_ticks_per_sec() * s->idle * 4) / 1000;
+}
+
static int usb_hid_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
{
@@ -795,6 +801,7 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value,
break;
case SET_IDLE:
s->idle = (uint8_t) (value >> 8);
+ usb_hid_set_next_idle(s, qemu_get_clock(vm_clock));
ret = 0;
break;
default:
@@ -813,9 +820,10 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
switch(p->pid) {
case USB_TOKEN_IN:
if (p->devep == 1) {
- /* TODO: Implement finite idle delays. */
- if (!(s->changed || s->idle))
+ int64_t curtime = qemu_get_clock(vm_clock);
+ if (!s->changed && (!s->idle || s->next_idle_clock - curtime > 0))
return USB_RET_NAK;
+ usb_hid_set_next_idle(s, curtime);
s->changed = 0;
if (s->kind == USB_MOUSE)
ret = usb_mouse_poll(s, p->data, p->len);
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index 153c6514f7..7048fb84d0 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -147,14 +147,10 @@ static int versatile_pci_host_init(PCIDevice *d)
pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_XILINX);
/* Both boards have the same device ID. Oh well. */
pci_config_set_device_id(d->config, PCI_DEVICE_ID_XILINX_XC2VP30);
- d->config[0x04] = 0x00;
- d->config[0x05] = 0x00;
- d->config[0x06] = 0x20;
- d->config[0x07] = 0x02;
- d->config[0x08] = 0x00; // revision
- d->config[0x09] = 0x00; // programming i/f
+ pci_set_word(d->config + PCI_STATUS,
+ PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM);
pci_config_set_class(d->config, PCI_CLASS_PROCESSOR_CO);
- d->config[0x0D] = 0x10; // latency_timer
+ pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10);
return 0;
}
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index f3373ae50e..bcd40f7b23 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -500,8 +500,8 @@ static int virtio_serial_init_pci(PCIDevice *pci_dev)
if (!vdev) {
return -1;
}
- vdev->nvectors = proxy->nvectors ? proxy->nvectors
- : proxy->max_virtserial_ports + 1;
+ vdev->nvectors = proxy->nvectors == -1 ? proxy->max_virtserial_ports + 1
+ : proxy->nvectors;
virtio_init_pci(proxy, vdev,
PCI_VENDOR_ID_REDHAT_QUMRANET,
PCI_DEVICE_ID_VIRTIO_CONSOLE,
@@ -585,7 +585,7 @@ static PCIDeviceInfo virtio_info[] = {
.init = virtio_serial_init_pci,
.exit = virtio_exit_pci,
.qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 0),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, -1),
DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, max_virtserial_ports,
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index ab456ea396..d0e021932c 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -335,8 +335,10 @@ static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
{
- features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
-
+ VirtIOSerial *vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+ if (vser->bus->max_nr_ports > 1) {
+ features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
+ }
return features;
}
diff --git a/linux-user/main.c b/linux-user/main.c
index a0d8ce734b..1189dda603 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2553,6 +2553,10 @@ int main(int argc, char **argv, char **envp)
}
cpu_model = NULL;
+#if defined(cpudef_setup)
+ cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
+#endif
+
optind = 1;
for(;;) {
if (optind >= argc)
@@ -2624,8 +2628,8 @@ int main(int argc, char **argv, char **envp)
cpu_model = argv[optind++];
if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
/* XXX: implement xxx_cpu_list for targets that still miss it */
-#if defined(cpu_list)
- cpu_list(stdout, &fprintf);
+#if defined(cpu_list_id)
+ cpu_list_id(stdout, &fprintf, "");
#endif
exit(1);
}
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 6090dcc65d..d77053b303 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1252,8 +1252,10 @@ if( cmd == val ) { \
int cmd = (int)tswap32(tflag);
#ifdef FUTEX_PRIVATE_FLAG
- if (cmd == FUTEX_PRIVATE_FLAG)
+ if (cmd & FUTEX_PRIVATE_FLAG) {
gemu_log("FUTEX_PRIVATE_FLAG|");
+ cmd &= ~FUTEX_PRIVATE_FLAG;
+ }
#endif
print_op(FUTEX_WAIT)
print_op(FUTEX_WAKE)
diff --git a/migration.c b/migration.c
index 2320c5fdf4..05f6cc5a0f 100644
--- a/migration.c
+++ b/migration.c
@@ -54,7 +54,7 @@ void qemu_start_incoming_migration(const char *uri)
fprintf(stderr, "unknown migration protocol: %s\n", uri);
}
-void do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
+int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
MigrationState *s = NULL;
const char *p;
@@ -64,49 +64,56 @@ void do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
if (current_migration &&
current_migration->get_status(current_migration) == MIG_STATE_ACTIVE) {
monitor_printf(mon, "migration already in progress\n");
- return;
+ return -1;
}
- if (strstart(uri, "tcp:", &p))
+ if (strstart(uri, "tcp:", &p)) {
s = tcp_start_outgoing_migration(mon, p, max_throttle, detach,
(int)qdict_get_int(qdict, "blk"),
(int)qdict_get_int(qdict, "inc"));
#if !defined(WIN32)
- else if (strstart(uri, "exec:", &p))
+ } else if (strstart(uri, "exec:", &p)) {
s = exec_start_outgoing_migration(mon, p, max_throttle, detach,
(int)qdict_get_int(qdict, "blk"),
(int)qdict_get_int(qdict, "inc"));
- else if (strstart(uri, "unix:", &p))
+ } else if (strstart(uri, "unix:", &p)) {
s = unix_start_outgoing_migration(mon, p, max_throttle, detach,
(int)qdict_get_int(qdict, "blk"),
(int)qdict_get_int(qdict, "inc"));
- else if (strstart(uri, "fd:", &p))
+ } else if (strstart(uri, "fd:", &p)) {
s = fd_start_outgoing_migration(mon, p, max_throttle, detach,
(int)qdict_get_int(qdict, "blk"),
(int)qdict_get_int(qdict, "inc"));
#endif
- else
+ } else {
monitor_printf(mon, "unknown migration protocol: %s\n", uri);
+ return -1;
+ }
- if (s == NULL)
+ if (s == NULL) {
monitor_printf(mon, "migration failed\n");
- else {
- if (current_migration)
- current_migration->release(current_migration);
+ return -1;
+ }
- current_migration = s;
+ if (current_migration) {
+ current_migration->release(current_migration);
}
+
+ current_migration = s;
+ return 0;
}
-void do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data)
+int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
MigrationState *s = current_migration;
if (s)
s->cancel(s);
+
+ return 0;
}
-void do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
+int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
double d;
FdMigrationState *s;
@@ -119,6 +126,8 @@ void do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
if (s && s->file) {
qemu_file_set_rate_limit(s->file, max_throttle);
}
+
+ return 0;
}
/* amount of nanoseconds we are willing to wait for migration to be down.
@@ -132,14 +141,16 @@ uint64_t migrate_max_downtime(void)
return max_downtime;
}
-void do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
- QObject **ret_data)
+int do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
+ QObject **ret_data)
{
double d;
d = qdict_get_double(qdict, "value") * 1e9;
d = MAX(0, MIN(UINT64_MAX, d));
max_downtime = (uint64_t)d;
+
+ return 0;
}
static void migrate_print_status(Monitor *mon, const char *name,
diff --git a/migration.h b/migration.h
index 65572c147c..385423f11d 100644
--- a/migration.h
+++ b/migration.h
@@ -52,16 +52,16 @@ struct FdMigrationState
void qemu_start_incoming_migration(const char *uri);
-void do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data);
-void do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data);
-void do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data);
uint64_t migrate_max_downtime(void);
-void do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
- QObject **ret_data);
+int do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
+ QObject **ret_data);
void do_info_migrate_print(Monitor *mon, const QObject *data);
diff --git a/monitor.c b/monitor.c
index ae125b8230..b1a6edccff 100644
--- a/monitor.c
+++ b/monitor.c
@@ -103,7 +103,7 @@ typedef struct mon_cmd_t {
void (*info_new)(Monitor *mon, QObject **ret_data);
int (*info_async)(Monitor *mon, MonitorCompletion *cb, void *opaque);
void (*cmd)(Monitor *mon, const QDict *qdict);
- void (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
+ int (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
int (*cmd_async)(Monitor *mon, const QDict *params,
MonitorCompletion *cb, void *opaque);
} mhandler;
@@ -120,7 +120,6 @@ struct mon_fd_t {
typedef struct MonitorControl {
QObject *id;
- int print_enabled;
JSONMessageParser parser;
int command_mode;
} MonitorControl;
@@ -138,11 +137,41 @@ struct Monitor {
CPUState *mon_cpu;
BlockDriverCompletionFunc *password_completion_cb;
void *password_opaque;
+#ifdef CONFIG_DEBUG_MONITOR
+ int print_calls_nr;
+#endif
QError *error;
QLIST_HEAD(,mon_fd_t) fds;
QLIST_ENTRY(Monitor) entry;
};
+#ifdef CONFIG_DEBUG_MONITOR
+#define MON_DEBUG(fmt, ...) do { \
+ fprintf(stderr, "Monitor: "); \
+ fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+
+static inline void mon_print_count_inc(Monitor *mon)
+{
+ mon->print_calls_nr++;
+}
+
+static inline void mon_print_count_init(Monitor *mon)
+{
+ mon->print_calls_nr = 0;
+}
+
+static inline int mon_print_count_get(const Monitor *mon)
+{
+ return mon->print_calls_nr;
+}
+
+#else /* !CONFIG_DEBUG_MONITOR */
+#define MON_DEBUG(fmt, ...) do { } while (0)
+static inline void mon_print_count_inc(Monitor *mon) { }
+static inline void mon_print_count_init(Monitor *mon) { }
+static inline int mon_print_count_get(const Monitor *mon) { return 0; }
+#endif /* CONFIG_DEBUG_MONITOR */
+
static QLIST_HEAD(mon_list, Monitor) mon_list;
static const mon_cmd_t mon_cmds[];
@@ -218,16 +247,19 @@ static void monitor_puts(Monitor *mon, const char *str)
void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
{
+ char buf[4096];
+
if (!mon)
return;
- if (mon->mc && !mon->mc->print_enabled) {
- qemu_error_new(QERR_UNDEFINED_ERROR);
- } else {
- char buf[4096];
- vsnprintf(buf, sizeof(buf), fmt, ap);
- monitor_puts(mon, buf);
+ mon_print_count_inc(mon);
+
+ if (monitor_ctrl_mode(mon)) {
+ return;
}
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ monitor_puts(mon, buf);
}
void monitor_printf(Monitor *mon, const char *fmt, ...)
@@ -298,9 +330,8 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data)
json = qobject_to_json(data);
assert(json != NULL);
- mon->mc->print_enabled = 1;
- monitor_printf(mon, "%s\n", qstring_get_str(json));
- mon->mc->print_enabled = 0;
+ qstring_append_chr(json, '\n');
+ monitor_puts(mon, qstring_get_str(json));
QDECREF(json);
}
@@ -416,13 +447,15 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
QDECREF(qmp);
}
-static void do_qmp_capabilities(Monitor *mon, const QDict *params,
- QObject **ret_data)
+static int do_qmp_capabilities(Monitor *mon, const QDict *params,
+ QObject **ret_data)
{
/* Will setup QMP capabilities in the future */
if (monitor_ctrl_mode(mon)) {
mon->mc->command_mode = 1;
}
+
+ return 0;
}
static int compare_cmd(const char *name, const char *list)
@@ -553,7 +586,7 @@ static void user_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
}
}
-static void do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const mon_cmd_t *cmd;
const char *item = qdict_get_try_str(qdict, "item");
@@ -571,7 +604,7 @@ static void do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
if (cmd->name == NULL) {
if (monitor_ctrl_mode(mon)) {
qemu_error_new(QERR_COMMAND_NOT_FOUND, item);
- return;
+ return -1;
}
goto help;
}
@@ -603,15 +636,17 @@ static void do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
if (monitor_ctrl_mode(mon)) {
/* handler not converted yet */
qemu_error_new(QERR_COMMAND_NOT_FOUND, item);
+ return -1;
} else {
cmd->mhandler.info(mon);
}
}
- return;
+ return 0;
help:
help_cmd(mon, "info");
+ return 0;
}
static void do_info_version_print(Monitor *mon, const QObject *data)
@@ -918,11 +953,14 @@ static void do_info_cpus(Monitor *mon, QObject **ret_data)
*ret_data = QOBJECT(cpu_list);
}
-static void do_cpu_set(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_cpu_set(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
int index = qdict_get_int(qdict, "index");
- if (mon_set_cpu(index) < 0)
+ if (mon_set_cpu(index) < 0) {
qemu_error_new(QERR_INVALID_PARAMETER, "index");
+ return -1;
+ }
+ return 0;
}
static void do_info_jit(Monitor *mon)
@@ -961,9 +999,10 @@ static void do_info_cpu_stats(Monitor *mon)
/**
* do_quit(): Quit QEMU execution
*/
-static void do_quit(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_quit(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
exit(0);
+ return 0;
}
static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
@@ -985,7 +1024,7 @@ static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
return 0;
}
-static void do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
BlockDriverState *bs;
int force = qdict_get_int(qdict, "force");
@@ -994,12 +1033,12 @@ static void do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
bs = bdrv_find(filename);
if (!bs) {
qemu_error_new(QERR_DEVICE_NOT_FOUND, filename);
- return;
+ return -1;
}
- eject_device(mon, bs, force);
+ return eject_device(mon, bs, force);
}
-static void do_block_set_passwd(Monitor *mon, const QDict *qdict,
+static int do_block_set_passwd(Monitor *mon, const QDict *qdict,
QObject **ret_data)
{
BlockDriverState *bs;
@@ -1007,16 +1046,19 @@ static void do_block_set_passwd(Monitor *mon, const QDict *qdict,
bs = bdrv_find(qdict_get_str(qdict, "device"));
if (!bs) {
qemu_error_new(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device"));
- return;
+ return -1;
}
if (bdrv_set_key(bs, qdict_get_str(qdict, "password")) < 0) {
qemu_error_new(QERR_INVALID_PASSWORD);
+ return -1;
}
+
+ return 0;
}
-static void do_change_block(Monitor *mon, const char *device,
- const char *filename, const char *fmt)
+static int do_change_block(Monitor *mon, const char *device,
+ const char *filename, const char *fmt)
{
BlockDriverState *bs;
BlockDriver *drv = NULL;
@@ -1024,26 +1066,32 @@ static void do_change_block(Monitor *mon, const char *device,
bs = bdrv_find(device);
if (!bs) {
qemu_error_new(QERR_DEVICE_NOT_FOUND, device);
- return;
+ return -1;
}
if (fmt) {
drv = bdrv_find_whitelisted_format(fmt);
if (!drv) {
qemu_error_new(QERR_INVALID_BLOCK_FORMAT, fmt);
- return;
+ return -1;
}
}
- if (eject_device(mon, bs, 0) < 0)
- return;
- bdrv_open2(bs, filename, BDRV_O_RDWR, drv);
- monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
+ if (eject_device(mon, bs, 0) < 0) {
+ return -1;
+ }
+ if (bdrv_open2(bs, filename, BDRV_O_RDWR, drv) < 0) {
+ return -1;
+ }
+ return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
}
-static void change_vnc_password(const char *password)
+static int change_vnc_password(const char *password)
{
- if (vnc_display_password(NULL, password) < 0)
+ if (vnc_display_password(NULL, password) < 0) {
qemu_error_new(QERR_SET_PASSWD_FAILED);
+ return -1;
+ }
+ return 0;
}
static void change_vnc_password_cb(Monitor *mon, const char *password,
@@ -1053,7 +1101,7 @@ static void change_vnc_password_cb(Monitor *mon, const char *password,
monitor_read_command(mon, 1);
}
-static void do_change_vnc(Monitor *mon, const char *target, const char *arg)
+static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
{
if (strcmp(target, "passwd") == 0 ||
strcmp(target, "password") == 0) {
@@ -1061,29 +1109,37 @@ static void do_change_vnc(Monitor *mon, const char *target, const char *arg)
char password[9];
strncpy(password, arg, sizeof(password));
password[sizeof(password) - 1] = '\0';
- change_vnc_password(password);
+ return change_vnc_password(password);
} else {
- monitor_read_password(mon, change_vnc_password_cb, NULL);
+ return monitor_read_password(mon, change_vnc_password_cb, NULL);
}
} else {
- if (vnc_display_open(NULL, target) < 0)
+ if (vnc_display_open(NULL, target) < 0) {
qemu_error_new(QERR_VNC_SERVER_FAILED, target);
+ return -1;
+ }
}
+
+ return 0;
}
/**
* do_change(): Change a removable medium, or VNC configuration
*/
-static void do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *device = qdict_get_str(qdict, "device");
const char *target = qdict_get_str(qdict, "target");
const char *arg = qdict_get_try_str(qdict, "arg");
+ int ret;
+
if (strcmp(device, "vnc") == 0) {
- do_change_vnc(mon, target, arg);
+ ret = do_change_vnc(mon, target, arg);
} else {
- do_change_block(mon, device, target, arg);
+ ret = do_change_block(mon, device, target, arg);
}
+
+ return ret;
}
static void do_screen_dump(Monitor *mon, const QDict *qdict)
@@ -1128,9 +1184,10 @@ static void do_singlestep(Monitor *mon, const QDict *qdict)
/**
* do_stop(): Stop VM execution
*/
-static void do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
vm_stop(EXCP_INTERRUPT);
+ return 0;
}
static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs);
@@ -1143,14 +1200,18 @@ struct bdrv_iterate_context {
/**
* do_cont(): Resume emulation.
*/
-static void do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
struct bdrv_iterate_context context = { mon, 0 };
bdrv_iterate(encrypted_bdrv_it, &context);
/* only resume the vm if all keys are set and valid */
- if (!context.err)
+ if (!context.err) {
vm_start();
+ return 0;
+ } else {
+ return -1;
+ }
}
static void bdrv_key_cb(void *opaque, int err)
@@ -1413,7 +1474,7 @@ static void do_print(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "\n");
}
-static void do_memory_save(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_memory_save(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
FILE *f;
uint32_t size = qdict_get_int(qdict, "size");
@@ -1422,13 +1483,14 @@ static void do_memory_save(Monitor *mon, const QDict *qdict, QObject **ret_data)
uint32_t l;
CPUState *env;
uint8_t buf[1024];
+ int ret = -1;
env = mon_get_cpu();
f = fopen(filename, "wb");
if (!f) {
qemu_error_new(QERR_OPEN_FILE_FAILED, filename);
- return;
+ return -1;
}
while (size != 0) {
l = sizeof(buf);
@@ -1442,11 +1504,15 @@ static void do_memory_save(Monitor *mon, const QDict *qdict, QObject **ret_data)
addr += l;
size -= l;
}
+
+ ret = 0;
+
exit:
fclose(f);
+ return ret;
}
-static void do_physical_memory_save(Monitor *mon, const QDict *qdict,
+static int do_physical_memory_save(Monitor *mon, const QDict *qdict,
QObject **ret_data)
{
FILE *f;
@@ -1455,11 +1521,12 @@ static void do_physical_memory_save(Monitor *mon, const QDict *qdict,
uint32_t size = qdict_get_int(qdict, "size");
const char *filename = qdict_get_str(qdict, "filename");
target_phys_addr_t addr = qdict_get_int(qdict, "val");
+ int ret = -1;
f = fopen(filename, "wb");
if (!f) {
qemu_error_new(QERR_OPEN_FILE_FAILED, filename);
- return;
+ return -1;
}
while (size != 0) {
l = sizeof(buf);
@@ -1474,8 +1541,12 @@ static void do_physical_memory_save(Monitor *mon, const QDict *qdict,
addr += l;
size -= l;
}
+
+ ret = 0;
+
exit:
fclose(f);
+ return ret;
}
static void do_sum(Monitor *mon, const QDict *qdict)
@@ -1828,19 +1899,21 @@ static void do_boot_set(Monitor *mon, const QDict *qdict)
/**
* do_system_reset(): Issue a machine reset
*/
-static void do_system_reset(Monitor *mon, const QDict *qdict,
- QObject **ret_data)
+static int do_system_reset(Monitor *mon, const QDict *qdict,
+ QObject **ret_data)
{
qemu_system_reset_request();
+ return 0;
}
/**
* do_system_powerdown(): Issue a machine powerdown
*/
-static void do_system_powerdown(Monitor *mon, const QDict *qdict,
- QObject **ret_data)
+static int do_system_powerdown(Monitor *mon, const QDict *qdict,
+ QObject **ret_data)
{
qemu_system_powerdown_request();
+ return 0;
}
#if defined(TARGET_I386)
@@ -2236,6 +2309,7 @@ static int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque)
return -1;
}
+ cb(opaque, NULL);
return 0;
}
@@ -2386,7 +2460,7 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict)
}
#endif
-static void do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *fdname = qdict_get_str(qdict, "fdname");
mon_fd_t *monfd;
@@ -2395,12 +2469,12 @@ static void do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data)
fd = qemu_chr_get_msgfd(mon->chr);
if (fd == -1) {
qemu_error_new(QERR_FD_NOT_SUPPLIED);
- return;
+ return -1;
}
if (qemu_isdigit(fdname[0])) {
qemu_error_new(QERR_INVALID_PARAMETER, "fdname");
- return;
+ return -1;
}
fd = dup(fd);
@@ -2409,7 +2483,7 @@ static void do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data)
qemu_error_new(QERR_TOO_MANY_FILES);
else
qemu_error_new(QERR_UNDEFINED_ERROR);
- return;
+ return -1;
}
QLIST_FOREACH(monfd, &mon->fds, next) {
@@ -2419,7 +2493,7 @@ static void do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data)
close(monfd->fd);
monfd->fd = fd;
- return;
+ return 0;
}
monfd = qemu_mallocz(sizeof(mon_fd_t));
@@ -2427,9 +2501,10 @@ static void do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data)
monfd->fd = fd;
QLIST_INSERT_HEAD(&mon->fds, monfd, next);
+ return 0;
}
-static void do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *fdname = qdict_get_str(qdict, "fdname");
mon_fd_t *monfd;
@@ -2443,10 +2518,11 @@ static void do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data)
close(monfd->fd);
qemu_free(monfd->name);
qemu_free(monfd);
- return;
+ return 0;
}
qemu_error_new(QERR_FD_NOT_FOUND, fdname);
+ return -1;
}
static void do_loadvm(Monitor *mon, const QDict *qdict)
@@ -3796,12 +3872,59 @@ static int is_async_return(const QObject *data)
return 0;
}
+static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret)
+{
+ if (ret && !monitor_has_error(mon)) {
+ /*
+ * If it returns failure, it must have passed on error.
+ *
+ * Action: Report an internal error to the client if in QMP.
+ */
+ if (monitor_ctrl_mode(mon)) {
+ qemu_error_new(QERR_UNDEFINED_ERROR);
+ }
+ MON_DEBUG("command '%s' returned failure but did not pass an error\n",
+ cmd->name);
+ }
+
+#ifdef CONFIG_DEBUG_MONITOR
+ if (!ret && monitor_has_error(mon)) {
+ /*
+ * If it returns success, it must not have passed an error.
+ *
+ * Action: Report the passed error to the client.
+ */
+ MON_DEBUG("command '%s' returned success but passed an error\n",
+ cmd->name);
+ }
+
+ if (mon_print_count_get(mon) > 0 && strcmp(cmd->name, "info") != 0) {
+ /*
+ * Handlers should not call Monitor print functions.
+ *
+ * Action: Ignore them in QMP.
+ *
+ * (XXX: we don't check any 'info' or 'query' command here
+ * because the user print function _is_ called by do_info(), hence
+ * we will trigger this check. This problem will go away when we
+ * make 'query' commands real and kill do_info())
+ */
+ MON_DEBUG("command '%s' called print functions %d time(s)\n",
+ cmd->name, mon_print_count_get(mon));
+ }
+#endif
+}
+
static void monitor_call_handler(Monitor *mon, const mon_cmd_t *cmd,
const QDict *params)
{
+ int ret;
QObject *data = NULL;
- cmd->mhandler.cmd_new(mon, params, &data);
+ mon_print_count_init(mon);
+
+ ret = cmd->mhandler.cmd_new(mon, params, &data);
+ handler_audit(mon, cmd, ret);
if (is_async_return(data)) {
/*
@@ -4519,21 +4642,21 @@ static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
monitor_read_command(mon, 1);
}
-void monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
- BlockDriverCompletionFunc *completion_cb,
- void *opaque)
+int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
+ BlockDriverCompletionFunc *completion_cb,
+ void *opaque)
{
int err;
if (!bdrv_key_required(bs)) {
if (completion_cb)
completion_cb(opaque, 0);
- return;
+ return 0;
}
if (monitor_ctrl_mode(mon)) {
qemu_error_new(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs));
- return;
+ return -1;
}
monitor_printf(mon, "%s (%s) is encrypted.\n", bdrv_get_device_name(bs),
@@ -4546,6 +4669,8 @@ void monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
if (err && completion_cb)
completion_cb(opaque, err);
+
+ return err;
}
typedef struct QemuErrorSink QemuErrorSink;
@@ -4636,7 +4761,8 @@ void qemu_error_internal(const char *file, int linenr, const char *func,
if (!qemu_error_sink->mon->error) {
qemu_error_sink->mon->error = qerror;
} else {
- /* XXX: warn the programmer */
+ MON_DEBUG("Additional error report at %s:%d\n", qerror->file,
+ qerror->linenr);
QDECREF(qerror);
}
break;
diff --git a/monitor.h b/monitor.h
index e35f1e4c65..fc0950506f 100644
--- a/monitor.h
+++ b/monitor.h
@@ -33,9 +33,9 @@ void monitor_init(CharDriverState *chr, int flags);
int monitor_suspend(Monitor *mon);
void monitor_resume(Monitor *mon);
-void monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
- BlockDriverCompletionFunc *completion_cb,
- void *opaque);
+int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
+ BlockDriverCompletionFunc *completion_cb,
+ void *opaque);
int monitor_get_fd(Monitor *mon, const char *fdname);
diff --git a/net.c b/net.c
index 8e951ca9da..a1bf49fa9c 100644
--- a/net.c
+++ b/net.c
@@ -812,9 +812,6 @@ static int net_init_nic(QemuOpts *opts,
}
nd->used = 1;
- if (vlan) {
- nd->vlan->nb_guest_devs++;
- }
nb_nics++;
return idx;
@@ -843,7 +840,7 @@ typedef int (*net_client_init_func)(QemuOpts *opts,
/* magic number, but compiler will warn if too small */
#define NET_MAX_DESC 20
-static struct {
+static const struct {
const char *type;
net_client_init_func init;
QemuOptDesc desc[NET_MAX_DESC];
@@ -1128,20 +1125,6 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
return -1;
}
-void net_client_uninit(NICInfo *nd)
-{
- if (nd->vlan) {
- nd->vlan->nb_guest_devs--;
- }
- nb_nics--;
-
- qemu_free(nd->model);
- qemu_free(nd->name);
- qemu_free(nd->devaddr);
-
- nd->used = 0;
-}
-
static int net_host_check_device(const char *device)
{
int i;
@@ -1227,16 +1210,23 @@ void net_set_boot_mask(int net_boot_mask)
void do_info_network(Monitor *mon)
{
VLANState *vlan;
+ VLANClientState *vc;
QTAILQ_FOREACH(vlan, &vlans, next) {
- VLANClientState *vc;
-
monitor_printf(mon, "VLAN %d devices:\n", vlan->id);
QTAILQ_FOREACH(vc, &vlan->clients, next) {
monitor_printf(mon, " %s: %s\n", vc->name, vc->info_str);
}
}
+ monitor_printf(mon, "Devices not on any VLAN:\n");
+ QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+ monitor_printf(mon, " %s: %s", vc->name, vc->info_str);
+ if (vc->peer) {
+ monitor_printf(mon, " peer=%s", vc->peer->name);
+ }
+ monitor_printf(mon, "\n");
+ }
}
void do_set_link(Monitor *mon, const QDict *qdict)
@@ -1253,6 +1243,7 @@ void do_set_link(Monitor *mon, const QDict *qdict)
}
}
}
+ vc = qemu_find_netdev(name);
done:
if (!vc) {
@@ -1289,20 +1280,41 @@ void net_cleanup(void)
}
}
-static void net_check_clients(void)
+void net_check_clients(void)
{
VLANState *vlan;
+ VLANClientState *vc;
+ int has_nic = 0, has_host_dev = 0;
QTAILQ_FOREACH(vlan, &vlans, next) {
- if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0)
- continue;
- if (vlan->nb_guest_devs == 0)
+ QTAILQ_FOREACH(vc, &vlan->clients, next) {
+ switch (vc->info->type) {
+ case NET_CLIENT_TYPE_NIC:
+ has_nic = 1;
+ break;
+ case NET_CLIENT_TYPE_SLIRP:
+ case NET_CLIENT_TYPE_TAP:
+ case NET_CLIENT_TYPE_SOCKET:
+ case NET_CLIENT_TYPE_VDE:
+ has_host_dev = 1;
+ break;
+ default: ;
+ }
+ }
+ if (has_host_dev && !has_nic)
fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id);
- if (vlan->nb_host_devs == 0)
+ if (has_nic && !has_host_dev)
fprintf(stderr,
"Warning: vlan %d is not connected to host network\n",
vlan->id);
}
+ QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+ if (!vc->peer) {
+ fprintf(stderr, "Warning: %s %s has no peer\n",
+ vc->info->type == NET_CLIENT_TYPE_NIC ? "nic" : "netdev",
+ vc->name);
+ }
+ }
}
static int net_init_client(QemuOpts *opts, void *dummy)
@@ -1337,8 +1349,6 @@ int net_init_clients(void)
return -1;
}
- net_check_clients();
-
return 0;
}
diff --git a/net.h b/net.h
index 116bb80119..33a1eafaec 100644
--- a/net.h
+++ b/net.h
@@ -79,7 +79,6 @@ struct VLANState {
int id;
QTAILQ_HEAD(, VLANClientState) clients;
QTAILQ_ENTRY(VLANState) next;
- unsigned int nb_guest_devs, nb_host_devs;
NetQueue *send_queue;
};
@@ -163,9 +162,9 @@ extern const char *legacy_tftp_prefix;
extern const char *legacy_bootp_filename;
int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev);
-void net_client_uninit(NICInfo *nd);
int net_client_parse(QemuOptsList *opts_list, const char *str);
int net_init_clients(void);
+void net_check_clients(void);
void net_cleanup(void);
void net_set_boot_mask(int boot_mask);
void net_host_device_add(Monitor *mon, const QDict *qdict);
diff --git a/net/slirp.c b/net/slirp.c
index 361899b8f2..317cca7f63 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -738,10 +738,6 @@ int net_init_slirp(QemuOpts *opts,
qemu_free(config);
}
- if (ret != -1 && vlan) {
- vlan->nb_host_devs++;
- }
-
qemu_free(vnet);
return ret;
diff --git a/net/socket.c b/net/socket.c
index 5533737e4b..442a9c790c 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -569,9 +569,5 @@ int net_init_socket(QemuOpts *opts,
return -1;
}
- if (vlan) {
- vlan->nb_host_devs++;
- }
-
return 0;
}
diff --git a/net/tap-win32.c b/net/tap-win32.c
index b717c17243..8370c803bf 100644
--- a/net/tap-win32.c
+++ b/net/tap-win32.c
@@ -714,10 +714,6 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
return -1;
}
- if (vlan) {
- vlan->nb_host_devs++;
- }
-
return 0;
}
diff --git a/net/tap.c b/net/tap.c
index d3492de116..7a7320c1a2 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -449,9 +449,5 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
}
}
- if (vlan) {
- vlan->nb_host_devs++;
- }
-
return 0;
}
diff --git a/net/vde.c b/net/vde.c
index 42b4633501..0b46fa6405 100644
--- a/net/vde.c
+++ b/net/vde.c
@@ -127,9 +127,5 @@ int net_init_vde(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
return -1;
}
- if (vlan) {
- vlan->nb_host_devs++;
- }
-
return 0;
}
diff --git a/pc-bios/README b/pc-bios/README
index 057092269b..ee68723168 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -14,8 +14,8 @@
- OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable
firmware implementation. The goal is to implement a 100% IEEE
1275-1994 (referred to as Open Firmware) compliant firmware.
- The included images for PowerPC (for 32 and 64 bit PPC CPUs) are built from
- OpenBIOS SVN revision 640, Sparc64 images from r665 and Sparc32 from r666.
+ The included images for PowerPC (for 32 and 64 bit PPC CPUs),
+ Sparc32 and Sparc64 are built from OpenBIOS SVN revision 683.
- The PXE roms come from Rom-o-Matic gPXE 0.9.9 with BANNER_TIMEOUT=0
diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc
index 1bcfed3022..b82ce2c371 100644
--- a/pc-bios/openbios-ppc
+++ b/pc-bios/openbios-ppc
Binary files differ
diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32
index aafb04146a..4f2f45f2c4 100644
--- a/pc-bios/openbios-sparc32
+++ b/pc-bios/openbios-sparc32
Binary files differ
diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64
index 437d246351..632f9380da 100644
--- a/pc-bios/openbios-sparc64
+++ b/pc-bios/openbios-sparc64
Binary files differ
diff --git a/qemu-char.c b/qemu-char.c
index 75dbf66858..4169492213 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -1173,6 +1173,22 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
return 0;
}
+static void qemu_chr_close_tty(CharDriverState *chr)
+{
+ FDCharDriver *s = chr->opaque;
+ int fd = -1;
+
+ if (s) {
+ fd = s->fd_in;
+ }
+
+ fd_chr_close(chr);
+
+ if (fd >= 0) {
+ close(fd);
+ }
+}
+
static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
{
const char *filename = qemu_opt_get(opts, "path");
@@ -1190,6 +1206,7 @@ static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
return NULL;
}
chr->chr_ioctl = tty_serial_ioctl;
+ chr->chr_close = qemu_chr_close_tty;
return chr;
}
#else /* ! __linux__ && ! __sun__ */
diff --git a/qemu-common.h b/qemu-common.h
index c9410066e4..805be1a8cc 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -11,6 +11,8 @@
#define QEMU_WARN_UNUSED_RESULT
#endif
+#define QEMU_BUILD_BUG_ON(x) typedef char __build_bug_on__##__LINE__[(x)?-1:1];
+
/* Hack around the mess dyngen-exec.h causes: We need QEMU_NORETURN in files that
cannot include the following headers without conflicts. This condition has
to be removed once dyngen is gone. */
@@ -226,6 +228,8 @@ typedef struct I2SCodec I2SCodec;
typedef struct DeviceState DeviceState;
typedef struct SSIBus SSIBus;
+typedef uint64_t pcibus_t;
+
/* CPU save/load. */
void cpu_save(QEMUFile *f, void *opaque);
int cpu_load(QEMUFile *f, void *opaque, int version_id);
diff --git a/qemu-config.c b/qemu-config.c
index c3203c87f9..246fae6f99 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -242,6 +242,54 @@ QemuOptsList qemu_mon_opts = {
},
};
+QemuOptsList qemu_cpudef_opts = {
+ .name = "cpudef",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
+ .desc = {
+ {
+ .name = "name",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "level",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "vendor",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "family",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "model",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "stepping",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "feature_edx", /* cpuid 0000_0001.edx */
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "feature_ecx", /* cpuid 0000_0001.ecx */
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "extfeature_edx", /* cpuid 8000_0001.edx */
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "extfeature_ecx", /* cpuid 8000_0001.ecx */
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "xlevel",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "model_id",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "vendor_override",
+ .type = QEMU_OPT_NUMBER,
+ },
+ { /* end of list */ }
+ },
+};
+
static QemuOptsList *lists[] = {
&qemu_drive_opts,
&qemu_chardev_opts,
@@ -251,6 +299,7 @@ static QemuOptsList *lists[] = {
&qemu_rtc_opts,
&qemu_global_opts,
&qemu_mon_opts,
+ &qemu_cpudef_opts,
NULL,
};
diff --git a/qemu-config.h b/qemu-config.h
index dd89ae4683..b335c42926 100644
--- a/qemu-config.h
+++ b/qemu-config.h
@@ -9,6 +9,7 @@ extern QemuOptsList qemu_net_opts;
extern QemuOptsList qemu_rtc_opts;
extern QemuOptsList qemu_global_opts;
extern QemuOptsList qemu_mon_opts;
+extern QemuOptsList qemu_cpudef_opts;
int qemu_set_option(const char *str);
int qemu_global_option(const char *str);
diff --git a/qemu-img.c b/qemu-img.c
index 0db8d4f194..0c9f2d4d51 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1168,7 +1168,7 @@ static int img_rebase(int argc, char **argv)
if (bdrv_open2(bs_new_backing, out_baseimg, BRDV_O_FLAGS | BDRV_O_RDWR,
new_backing_drv))
{
- error("Could not open new backing file '%s'", backing_name);
+ error("Could not open new backing file '%s'", out_baseimg);
return -1;
}
}
@@ -1224,7 +1224,7 @@ static int img_rebase(int argc, char **argv)
int pnum;
if (compare_sectors(buf_old + written * 512,
- buf_new + written * 512, n, &pnum))
+ buf_new + written * 512, n - written, &pnum))
{
ret = bdrv_write(bs, sector + written,
buf_old + written * 512, pnum);
diff --git a/qemu-option.c b/qemu-option.c
index a52a4c4a08..de40bffc7d 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -470,7 +470,7 @@ struct QemuOpt {
const char *name;
const char *str;
- QemuOptDesc *desc;
+ const QemuOptDesc *desc;
union {
int boolean;
uint64_t uint;
@@ -565,7 +565,7 @@ static void qemu_opt_del(QemuOpt *opt)
int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
{
QemuOpt *opt;
- QemuOptDesc *desc = opts->list->desc;
+ const QemuOptDesc *desc = opts->list->desc;
int i;
for (i = 0; desc[i].name != NULL; i++) {
@@ -777,7 +777,7 @@ QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *fi
/* Validate parsed opts against descriptions where no
* descriptions were provided in the QemuOptsList.
*/
-int qemu_opts_validate(QemuOpts *opts, QemuOptDesc *desc)
+int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc)
{
QemuOpt *opt;
diff --git a/qemu-option.h b/qemu-option.h
index 666b666b33..f3f1de755d 100644
--- a/qemu-option.h
+++ b/qemu-option.h
@@ -115,7 +115,7 @@ int qemu_opts_set(QemuOptsList *list, const char *id,
const char *name, const char *value);
const char *qemu_opts_id(QemuOpts *opts);
void qemu_opts_del(QemuOpts *opts);
-int qemu_opts_validate(QemuOpts *opts, QemuOptDesc *desc);
+int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc);
int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname);
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *firstname);
diff --git a/rwhandler.c b/rwhandler.c
new file mode 100644
index 0000000000..1f9b6db4bc
--- /dev/null
+++ b/rwhandler.c
@@ -0,0 +1,87 @@
+#include "rwhandler.h"
+#include "ioport.h"
+#include "cpu-all.h"
+
+#define RWHANDLER_WRITE(name, len, type) \
+static void name(void *opaque, type addr, uint32_t value) \
+{\
+ struct ReadWriteHandler *handler = opaque;\
+ handler->write(handler, addr, value, len);\
+}
+
+#define RWHANDLER_READ(name, len, type) \
+static uint32_t name(void *opaque, type addr) \
+{ \
+ struct ReadWriteHandler *handler = opaque; \
+ return handler->read(handler, addr, len); \
+}
+
+RWHANDLER_WRITE(cpu_io_memory_simple_writeb, 1, target_phys_addr_t);
+RWHANDLER_READ(cpu_io_memory_simple_readb, 1, target_phys_addr_t);
+RWHANDLER_WRITE(cpu_io_memory_simple_writew, 2, target_phys_addr_t);
+RWHANDLER_READ(cpu_io_memory_simple_readw, 2, target_phys_addr_t);
+RWHANDLER_WRITE(cpu_io_memory_simple_writel, 4, target_phys_addr_t);
+RWHANDLER_READ(cpu_io_memory_simple_readl, 4, target_phys_addr_t);
+
+static CPUWriteMemoryFunc * const cpu_io_memory_simple_write[] = {
+ &cpu_io_memory_simple_writeb,
+ &cpu_io_memory_simple_writew,
+ &cpu_io_memory_simple_writel,
+};
+
+static CPUReadMemoryFunc * const cpu_io_memory_simple_read[] = {
+ &cpu_io_memory_simple_readb,
+ &cpu_io_memory_simple_readw,
+ &cpu_io_memory_simple_readl,
+};
+
+int cpu_register_io_memory_simple(struct ReadWriteHandler *handler)
+{
+ if (!handler->read || !handler->write) {
+ return -1;
+ }
+ return cpu_register_io_memory(cpu_io_memory_simple_read,
+ cpu_io_memory_simple_write,
+ handler);
+}
+
+RWHANDLER_WRITE(ioport_simple_writeb, 1, uint32_t);
+RWHANDLER_READ(ioport_simple_readb, 1, uint32_t);
+RWHANDLER_WRITE(ioport_simple_writew, 2, uint32_t);
+RWHANDLER_READ(ioport_simple_readw, 2, uint32_t);
+RWHANDLER_WRITE(ioport_simple_writel, 4, uint32_t);
+RWHANDLER_READ(ioport_simple_readl, 4, uint32_t);
+
+int register_ioport_simple(ReadWriteHandler* handler,
+ pio_addr_t start, int length, int size)
+{
+ IOPortWriteFunc *write;
+ IOPortReadFunc *read;
+ int r;
+ switch (size) {
+ case 1:
+ write = ioport_simple_writeb;
+ read = ioport_simple_readb;
+ break;
+ case 2:
+ write = ioport_simple_writew;
+ read = ioport_simple_readw;
+ break;
+ default:
+ write = ioport_simple_writel;
+ read = ioport_simple_readl;
+ }
+ if (handler->write) {
+ r = register_ioport_write(start, length, size, write, handler);
+ if (r < 0) {
+ return r;
+ }
+ }
+ if (handler->read) {
+ r = register_ioport_read(start, length, size, read, handler);
+ if (r < 0) {
+ return r;
+ }
+ }
+ return 0;
+}
diff --git a/rwhandler.h b/rwhandler.h
new file mode 100644
index 0000000000..bc11849572
--- /dev/null
+++ b/rwhandler.h
@@ -0,0 +1,27 @@
+#ifndef READ_WRITE_HANDLER_H
+#define READ_WRITE_HANDLER_H
+
+#include "qemu-common.h"
+#include "ioport.h"
+
+typedef struct ReadWriteHandler ReadWriteHandler;
+
+/* len is guaranteed to be one of 1, 2 or 4, addr is guaranteed to fit in an
+ * appropriate type (io/memory/etc). They do not need to be range checked. */
+typedef void WriteHandlerFunc(ReadWriteHandler *, pcibus_t addr,
+ uint32_t value, int len);
+typedef uint32_t ReadHandlerFunc(ReadWriteHandler *, pcibus_t addr, int len);
+
+struct ReadWriteHandler {
+ WriteHandlerFunc *write;
+ ReadHandlerFunc *read;
+};
+
+/* Helpers for when we want to use a single routine with length. */
+/* CPU memory handler: both read and write must be present. */
+int cpu_register_io_memory_simple(ReadWriteHandler *);
+/* io port handler: can supply only read or write handlers. */
+int register_ioport_simple(ReadWriteHandler *,
+ pio_addr_t start, int length, int size);
+
+#endif
diff --git a/sdl.c b/sdl.c
index cf27ad2c14..a9b4323900 100644
--- a/sdl.c
+++ b/sdl.c
@@ -872,10 +872,6 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
da->resize_displaysurface = sdl_resize_displaysurface;
da->free_displaysurface = sdl_free_displaysurface;
if (register_displayallocator(ds, da) == da) {
- DisplaySurface *surf;
- surf = sdl_create_displaysurface(ds_get_width(ds), ds_get_height(ds));
- defaultallocator_free_displaysurface(ds->surface);
- ds->surface = surf;
dpy_resize(ds);
}
diff --git a/sysconfigs/target/target-x86_64.conf b/sysconfigs/target/target-x86_64.conf
new file mode 100644
index 0000000000..43ad282b5c
--- /dev/null
+++ b/sysconfigs/target/target-x86_64.conf
@@ -0,0 +1,86 @@
+# x86 CPU MODELS
+
+[cpudef]
+ name = "Conroe"
+ level = "2"
+ vendor = "GenuineIntel"
+ family = "6"
+ model = "2"
+ stepping = "3"
+ feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36"
+ feature_ecx = "sse3 ssse3"
+ extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx"
+ extfeature_ecx = "lahf_lm"
+ xlevel = "0x8000000A"
+ model_id = "Intel Celeron_4x0 (Conroe/Merom Class Core 2)"
+
+[cpudef]
+ name = "Penryn"
+ level = "2"
+ vendor = "GenuineIntel"
+ family = "6"
+ model = "2"
+ stepping = "3"
+ feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36"
+ feature_ecx = "sse3 cx16 ssse3 sse4.1"
+ extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx"
+ extfeature_ecx = "lahf_lm"
+ xlevel = "0x8000000A"
+ model_id = "Intel Core 2 Duo P9xxx (Penryn Class Core 2)"
+
+[cpudef]
+ name = "Nehalem"
+ level = "2"
+ vendor = "GenuineIntel"
+ family = "6"
+ model = "2"
+ stepping = "3"
+ feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36"
+ feature_ecx = "sse3 cx16 ssse3 sse4.1 sse4.2 popcnt"
+ extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx"
+ extfeature_ecx = "lahf_lm"
+ xlevel = "0x8000000A"
+ model_id = "Intel Core i7 9xx (Nehalem Class Core i7)"
+
+[cpudef]
+ name = "Opteron_G1"
+ level = "5"
+ vendor = "AuthenticAMD"
+ family = "15"
+ model = "6"
+ stepping = "1"
+ feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36"
+ feature_ecx = "sse3"
+ extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx"
+# extfeature_ecx = ""
+ xlevel = "0x80000008"
+ model_id = "AMD Opteron 240 (Gen 1 Class Opteron)"
+
+[cpudef]
+ name = "Opteron_G2"
+ level = "5"
+ vendor = "AuthenticAMD"
+ family = "15"
+ model = "6"
+ stepping = "1"
+ feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36"
+ feature_ecx = "sse3 cx16"
+ extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx rdtscp"
+ extfeature_ecx = "svm lahf_lm"
+ xlevel = "0x80000008"
+ model_id = "AMD Opteron 22xx (Gen 2 Class Opteron)"
+
+[cpudef]
+ name = "Opteron_G3"
+ level = "5"
+ vendor = "AuthenticAMD"
+ family = "15"
+ model = "6"
+ stepping = "1"
+ feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36"
+ feature_ecx = "sse3 cx16 monitor popcnt"
+ extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx rdtscp"
+ extfeature_ecx = "svm sse4a abm misalignsse lahf_lm"
+ xlevel = "0x80000008"
+ model_id = "AMD Opteron 23xx (Gen 3 Class Opteron)"
+
diff --git a/sysemu.h b/sysemu.h
index 9c3b281091..8ba618e54f 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -213,11 +213,11 @@ DriveInfo *add_init_drive(const char *opts);
/* pci-hotplug */
void pci_device_hot_add_print(Monitor *mon, const QObject *data);
-void pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int pci_device_hot_add(Monitor *mon, const QDict *qdict, QObject **ret_data);
void drive_hot_add(Monitor *mon, const QDict *qdict);
-void pci_device_hot_remove(Monitor *mon, const char *pci_addr);
-void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict,
- QObject **ret_data);
+int pci_device_hot_remove(Monitor *mon, const char *pci_addr);
+int do_pci_device_hot_remove(Monitor *mon, const QDict *qdict,
+ QObject **ret_data);
/* serial ports */
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 27001e86a6..6f40084b23 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -824,11 +824,10 @@ void do_interrupt(CPUARMState *env)
env->spsr = cpsr_read(env);
/* Clear IT bits. */
env->condexec_bits = 0;
- /* Switch to the new mode, and switch to Arm mode. */
- /* ??? Thumb interrupt handlers not implemented. */
+ /* Switch to the new mode, and to the correct instruction set. */
env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
env->uncached_cpsr |= mask;
- env->thumb = 0;
+ env->thumb = (env->cp15.c1_sys & (1 << 30)) != 0;
env->regs[14] = env->regs[15] + offset;
env->regs[15] = addr;
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 786c3294da..8b3b12d67e 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -8001,8 +8001,16 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
gen_bx(s, tmp);
break;
case 5: /* Exception return. */
- /* Unpredictable in user mode. */
- goto illegal_op;
+ if (IS_USER(s)) {
+ goto illegal_op;
+ }
+ if (rn != 14 || rd != 15) {
+ goto illegal_op;
+ }
+ tmp = load_reg(s, rn);
+ tcg_gen_subi_i32(tmp, tmp, insn & 0xff);
+ gen_exception_return(s, tmp);
+ break;
case 6: /* mrs cpsr. */
tmp = new_tmp();
if (IS_M(env)) {
@@ -8898,7 +8906,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
shift = CPSR_A | CPSR_I | CPSR_F;
else
shift = 0;
- gen_set_psr_im(s, shift, 0, ((insn & 7) << 6) & shift);
+ gen_set_psr_im(s, ((insn & 7) << 6), 0, shift);
}
break;
diff --git a/target-cris/translate_v10.c b/target-cris/translate_v10.c
index 9a29c51171..9abf1a837c 100644
--- a/target-cris/translate_v10.c
+++ b/target-cris/translate_v10.c
@@ -1187,6 +1187,10 @@ static unsigned int crisv10_decoder(DisasContext *dc)
dc->cpustate_changed = 1;
}
+ /* CRISv10 locks out interrupts on dslots. */
+ if (dc->delayed_branch == 2) {
+ cris_lock_irq(dc);
+ }
return insn_len;
}
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 216b00e503..ef7d951fcc 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -723,8 +723,10 @@ typedef struct CPUX86State {
CPUX86State *cpu_x86_init(const char *cpu_model);
int cpu_x86_exec(CPUX86State *s);
void cpu_x86_close(CPUX86State *s);
-void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt,
- ...));
+void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+ const char *optarg);
+void x86_cpudef_setup(void);
+
int cpu_get_pic_interrupt(CPUX86State *s);
/* MSDOS compatibility mode FPU exception support */
void cpu_set_ferr(CPUX86State *s);
@@ -876,7 +878,8 @@ uint64_t cpu_get_tsc(CPUX86State *env);
#define cpu_exec cpu_x86_exec
#define cpu_gen_code cpu_x86_gen_code
#define cpu_signal_handler cpu_x86_signal_handler
-#define cpu_list x86_cpu_list
+#define cpu_list_id x86_cpu_list
+#define cpudef_setup x86_cpudef_setup
#define CPU_SAVE_VERSION 11
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 70762bb10a..7cda864b7b 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -29,33 +29,52 @@
#include "kvm.h"
//#define DEBUG_MMU
+#include "qemu-option.h"
+#include "qemu-config.h"
/* feature flags taken from "Intel Processor Identification and the CPUID
- * Instruction" and AMD's "CPUID Specification". In cases of disagreement
- * about feature names, the Linux name is used. */
+ * Instruction" and AMD's "CPUID Specification". In cases of disagreement
+ * between feature naming conventions, aliases may be added.
+ */
static const char *feature_name[] = {
- "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
- "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
- "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */, NULL, "ds" /* Intel dts */, "acpi", "mmx",
- "fxsr", "sse", "sse2", "ss", "ht" /* Intel htt */, "tm", "ia64", "pbe",
+ "fpu", "vme", "de", "pse",
+ "tsc", "msr", "pae", "mce",
+ "cx8", "apic", NULL, "sep",
+ "mtrr", "pge", "mca", "cmov",
+ "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */,
+ NULL, "ds" /* Intel dts */, "acpi", "mmx",
+ "fxsr", "sse", "sse2", "ss",
+ "ht" /* Intel htt */, "tm", "ia64", "pbe",
};
static const char *ext_feature_name[] = {
- "pni" /* Intel,AMD sse3 */, NULL, NULL, "monitor", "ds_cpl", "vmx", NULL /* Linux smx */, "est",
- "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
- NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt",
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, "hypervisor",
+ "pni|sse3" /* Intel,AMD sse3 */, NULL, NULL, "monitor",
+ "ds_cpl", "vmx", NULL /* Linux smx */, "est",
+ "tm2", "ssse3", "cid", NULL,
+ NULL, "cx16", "xtpr", NULL,
+ NULL, NULL, "dca", "sse4.1|sse4_1",
+ "sse4.2|sse4_2", "x2apic", NULL, "popcnt",
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "hypervisor",
};
static const char *ext2_feature_name[] = {
- "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
- "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall", "mtrr", "pge", "mca", "cmov",
- "pat", "pse36", NULL, NULL /* Linux mp */, "nx" /* Intel xd */, NULL, "mmxext", "mmx",
- "fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp", NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow",
+ "fpu", "vme", "de", "pse",
+ "tsc", "msr", "pae", "mce",
+ "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall",
+ "mtrr", "pge", "mca", "cmov",
+ "pat", "pse36", NULL, NULL /* Linux mp */,
+ "nx" /* Intel xd */, NULL, "mmxext", "mmx",
+ "fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp",
+ NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow",
};
static const char *ext3_feature_name[] = {
- "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */, "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
- "3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL, "skinit", "wdt", NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */,
+ "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
+ "3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL,
+ "skinit", "wdt", NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
};
static const char *kvm_feature_name[] = {
@@ -65,47 +84,99 @@ static const char *kvm_feature_name[] = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};
+/* collects per-function cpuid data
+ */
+typedef struct model_features_t {
+ uint32_t *guest_feat;
+ uint32_t *host_feat;
+ uint32_t check_feat;
+ const char **flag_names;
+ uint32_t cpuid;
+ } model_features_t;
+
+int check_cpuid = 0;
+int enforce_cpuid = 0;
+
+static void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax,
+ uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
+
+#define iswhite(c) ((c) && ((c) <= ' ' || '~' < (c)))
+
+/* general substring compare of *[s1..e1) and *[s2..e2). sx is start of
+ * a substring. ex if !NULL points to the first char after a substring,
+ * otherwise the string is assumed to sized by a terminating nul.
+ * Return lexical ordering of *s1:*s2.
+ */
+static int sstrcmp(const char *s1, const char *e1, const char *s2,
+ const char *e2)
+{
+ for (;;) {
+ if (!*s1 || !*s2 || *s1 != *s2)
+ return (*s1 - *s2);
+ ++s1, ++s2;
+ if (s1 == e1 && s2 == e2)
+ return (0);
+ else if (s1 == e1)
+ return (*s2);
+ else if (s2 == e2)
+ return (*s1);
+ }
+}
+
+/* compare *[s..e) to *altstr. *altstr may be a simple string or multiple
+ * '|' delimited (possibly empty) strings in which case search for a match
+ * within the alternatives proceeds left to right. Return 0 for success,
+ * non-zero otherwise.
+ */
+static int altcmp(const char *s, const char *e, const char *altstr)
+{
+ const char *p, *q;
+
+ for (q = p = altstr; ; ) {
+ while (*p && *p != '|')
+ ++p;
+ if ((q == p && !*s) || (q != p && !sstrcmp(s, e, q, p)))
+ return (0);
+ if (!*p)
+ return (1);
+ else
+ q = ++p;
+ }
+}
+
+/* search featureset for flag *[s..e), if found set corresponding bit in
+ * *pval and return success, otherwise return zero
+ */
+static int lookup_feature(uint32_t *pval, const char *s, const char *e,
+ const char **featureset)
+{
+ uint32_t mask;
+ const char **ppc;
+
+ for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc)
+ if (*ppc && !altcmp(s, e, *ppc)) {
+ *pval |= mask;
+ break;
+ }
+ return (mask ? 1 : 0);
+}
+
static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
uint32_t *ext_features,
uint32_t *ext2_features,
uint32_t *ext3_features,
uint32_t *kvm_features)
{
- int i;
- int found = 0;
-
- for ( i = 0 ; i < 32 ; i++ )
- if (feature_name[i] && !strcmp (flagname, feature_name[i])) {
- *features |= 1 << i;
- found = 1;
- }
- for ( i = 0 ; i < 32 ; i++ )
- if (ext_feature_name[i] && !strcmp (flagname, ext_feature_name[i])) {
- *ext_features |= 1 << i;
- found = 1;
- }
- for ( i = 0 ; i < 32 ; i++ )
- if (ext2_feature_name[i] && !strcmp (flagname, ext2_feature_name[i])) {
- *ext2_features |= 1 << i;
- found = 1;
- }
- for ( i = 0 ; i < 32 ; i++ )
- if (ext3_feature_name[i] && !strcmp (flagname, ext3_feature_name[i])) {
- *ext3_features |= 1 << i;
- found = 1;
- }
- for ( i = 0 ; i < 32 ; i++ )
- if (kvm_feature_name[i] && !strcmp (flagname, kvm_feature_name[i])) {
- *kvm_features |= 1 << i;
- found = 1;
- }
-
- if (!found) {
- fprintf(stderr, "CPU feature %s not found\n", flagname);
- }
+ if (!lookup_feature(features, flagname, NULL, feature_name) &&
+ !lookup_feature(ext_features, flagname, NULL, ext_feature_name) &&
+ !lookup_feature(ext2_features, flagname, NULL, ext2_feature_name) &&
+ !lookup_feature(ext3_features, flagname, NULL, ext3_feature_name) &&
+ !lookup_feature(kvm_features, flagname, NULL, kvm_feature_name))
+ fprintf(stderr, "CPU feature %s not found\n", flagname);
}
typedef struct x86_def_t {
+ struct x86_def_t *next;
const char *name;
uint32_t level;
uint32_t vendor1, vendor2, vendor3;
@@ -116,6 +187,7 @@ typedef struct x86_def_t {
uint32_t xlevel;
char model_id[48];
int vendor_override;
+ uint32_t flags;
} x86_def_t;
#define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -129,7 +201,14 @@ typedef struct x86_def_t {
CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \
CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \
CPUID_PAE | CPUID_SEP | CPUID_APIC)
-static x86_def_t x86_defs[] = {
+
+/* maintains list of cpu model definitions
+ */
+static x86_def_t *x86_defs = {NULL};
+
+/* built-in cpu model definitions (deprecated)
+ */
+static x86_def_t builtin_x86_defs[] = {
#ifdef TARGET_X86_64
{
.name = "qemu64",
@@ -334,9 +413,6 @@ static x86_def_t x86_defs[] = {
},
};
-static void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax,
- uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
-
static int cpu_x86_fill_model_id(char *str)
{
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
@@ -382,6 +458,51 @@ static int cpu_x86_fill_host(x86_def_t *x86_cpu_def)
return 0;
}
+static int unavailable_host_feature(struct model_features_t *f, uint32_t mask)
+{
+ int i;
+
+ for (i = 0; i < 32; ++i)
+ if (1 << i & mask) {
+ fprintf(stderr, "warning: host cpuid %04x_%04x lacks requested"
+ " flag '%s' [0x%08x]\n",
+ f->cpuid >> 16, f->cpuid & 0xffff,
+ f->flag_names[i] ? f->flag_names[i] : "[reserved]", mask);
+ break;
+ }
+ return 0;
+}
+
+/* best effort attempt to inform user requested cpu flags aren't making
+ * their way to the guest. Note: ft[].check_feat ideally should be
+ * specified via a guest_def field to suppress report of extraneous flags.
+ */
+static int check_features_against_host(x86_def_t *guest_def)
+{
+ x86_def_t host_def;
+ uint32_t mask;
+ int rv, i;
+ struct model_features_t ft[] = {
+ {&guest_def->features, &host_def.features,
+ ~0, feature_name, 0x00000000},
+ {&guest_def->ext_features, &host_def.ext_features,
+ ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001},
+ {&guest_def->ext2_features, &host_def.ext2_features,
+ ~PPRO_FEATURES, ext2_feature_name, 0x80000000},
+ {&guest_def->ext3_features, &host_def.ext3_features,
+ ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001}};
+
+ cpu_x86_fill_host(&host_def);
+ for (rv = 0, i = 0; i < sizeof (ft) / sizeof (ft[0]); ++i)
+ for (mask = 1; mask; mask <<= 1)
+ if (ft[i].check_feat & mask && *ft[i].guest_feat & mask &&
+ !(*ft[i].host_feat & mask)) {
+ unavailable_host_feature(&ft[i], mask);
+ rv = 1;
+ }
+ return rv;
+}
+
static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
{
unsigned int i;
@@ -393,13 +514,9 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
uint32_t minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0, minus_ext3_features = 0, minus_kvm_features = 0;
uint32_t numvalue;
- def = NULL;
- for (i = 0; i < ARRAY_SIZE(x86_defs); i++) {
- if (strcmp(name, x86_defs[i].name) == 0) {
- def = &x86_defs[i];
+ for (def = x86_defs; def; def = def->next)
+ if (!strcmp(name, def->name))
break;
- }
- }
if (kvm_enabled() && strcmp(name, "host") == 0) {
cpu_x86_fill_host(x86_cpu_def);
} else if (!def) {
@@ -488,6 +605,10 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
fprintf(stderr, "unrecognized feature %s\n", featurestr);
goto error;
}
+ } else if (!strcmp(featurestr, "check")) {
+ check_cpuid = 1;
+ } else if (!strcmp(featurestr, "enforce")) {
+ check_cpuid = enforce_cpuid = 1;
} else {
fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
goto error;
@@ -504,6 +625,10 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
x86_cpu_def->ext2_features &= ~minus_ext2_features;
x86_cpu_def->ext3_features &= ~minus_ext3_features;
x86_cpu_def->kvm_features &= ~minus_kvm_features;
+ if (check_cpuid) {
+ if (check_features_against_host(x86_cpu_def) && enforce_cpuid)
+ goto error;
+ }
free(s);
return 0;
@@ -512,12 +637,97 @@ error:
return -1;
}
-void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+/* generate a composite string into buf of all cpuid names in featureset
+ * selected by fbits. indicate truncation at bufsize in the event of overflow.
+ * if flags, suppress names undefined in featureset.
+ */
+static void listflags(char *buf, int bufsize, uint32_t fbits,
+ const char **featureset, uint32_t flags)
{
- unsigned int i;
+ const char **p = &featureset[31];
+ char *q, *b, bit;
+ int nc;
+
+ b = 4 <= bufsize ? buf + (bufsize -= 3) - 1 : NULL;
+ *buf = '\0';
+ for (q = buf, bit = 31; fbits && bufsize; --p, fbits &= ~(1 << bit), --bit)
+ if (fbits & 1 << bit && (*p || !flags)) {
+ if (*p)
+ nc = snprintf(q, bufsize, "%s%s", q == buf ? "" : " ", *p);
+ else
+ nc = snprintf(q, bufsize, "%s[%d]", q == buf ? "" : " ", bit);
+ if (bufsize <= nc) {
+ if (b)
+ sprintf(b, "...");
+ return;
+ }
+ q += nc;
+ bufsize -= nc;
+ }
+}
- for (i = 0; i < ARRAY_SIZE(x86_defs); i++)
- (*cpu_fprintf)(f, "x86 %16s\n", x86_defs[i].name);
+/* generate CPU information:
+ * -? list model names
+ * -?model list model names/IDs
+ * -?dump output all model (x86_def_t) data
+ * -?cpuid list all recognized cpuid flag names
+ */
+void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+ const char *optarg)
+{
+ unsigned char model = !strcmp("?model", optarg);
+ unsigned char dump = !strcmp("?dump", optarg);
+ unsigned char cpuid = !strcmp("?cpuid", optarg);
+ x86_def_t *def;
+ char buf[256];
+
+ if (cpuid) {
+ (*cpu_fprintf)(f, "Recognized CPUID flags:\n");
+ listflags(buf, sizeof (buf), (uint32_t)~0, feature_name, 1);
+ (*cpu_fprintf)(f, " f_edx: %s\n", buf);
+ listflags(buf, sizeof (buf), (uint32_t)~0, ext_feature_name, 1);
+ (*cpu_fprintf)(f, " f_ecx: %s\n", buf);
+ listflags(buf, sizeof (buf), (uint32_t)~0, ext2_feature_name, 1);
+ (*cpu_fprintf)(f, " extf_edx: %s\n", buf);
+ listflags(buf, sizeof (buf), (uint32_t)~0, ext3_feature_name, 1);
+ (*cpu_fprintf)(f, " extf_ecx: %s\n", buf);
+ return;
+ }
+ for (def = x86_defs; def; def = def->next) {
+ snprintf(buf, sizeof (buf), def->flags ? "[%s]": "%s", def->name);
+ if (model || dump) {
+ (*cpu_fprintf)(f, "x86 %16s %-48s\n", buf, def->model_id);
+ } else {
+ (*cpu_fprintf)(f, "x86 %16s\n", buf);
+ }
+ if (dump) {
+ memcpy(buf, &def->vendor1, sizeof (def->vendor1));
+ memcpy(buf + 4, &def->vendor2, sizeof (def->vendor2));
+ memcpy(buf + 8, &def->vendor3, sizeof (def->vendor3));
+ buf[12] = '\0';
+ (*cpu_fprintf)(f,
+ " family %d model %d stepping %d level %d xlevel 0x%x"
+ " vendor \"%s\"\n",
+ def->family, def->model, def->stepping, def->level,
+ def->xlevel, buf);
+ listflags(buf, sizeof (buf), def->features, feature_name, 0);
+ (*cpu_fprintf)(f, " feature_edx %08x (%s)\n", def->features,
+ buf);
+ listflags(buf, sizeof (buf), def->ext_features, ext_feature_name,
+ 0);
+ (*cpu_fprintf)(f, " feature_ecx %08x (%s)\n", def->ext_features,
+ buf);
+ listflags(buf, sizeof (buf), def->ext2_features, ext2_feature_name,
+ 0);
+ (*cpu_fprintf)(f, " extfeature_edx %08x (%s)\n",
+ def->ext2_features, buf);
+ listflags(buf, sizeof (buf), def->ext3_features, ext3_feature_name,
+ 0);
+ (*cpu_fprintf)(f, " extfeature_ecx %08x (%s)\n",
+ def->ext3_features, buf);
+ (*cpu_fprintf)(f, "\n");
+ }
+ }
}
static int cpu_x86_register (CPUX86State *env, const char *cpu_model)
@@ -566,6 +776,128 @@ static int cpu_x86_register (CPUX86State *env, const char *cpu_model)
return 0;
}
+#if !defined(CONFIG_LINUX_USER)
+/* copy vendor id string to 32 bit register, nul pad as needed
+ */
+static void cpyid(const char *s, uint32_t *id)
+{
+ char *d = (char *)id;
+ char i;
+
+ for (i = sizeof (*id); i--; )
+ *d++ = *s ? *s++ : '\0';
+}
+
+/* interpret radix and convert from string to arbitrary scalar,
+ * otherwise flag failure
+ */
+#define setscalar(pval, str, perr) \
+{ \
+ char *pend; \
+ unsigned long ul; \
+ \
+ ul = strtoul(str, &pend, 0); \
+ *str && !*pend ? (*pval = ul) : (*perr = 1); \
+}
+
+/* map cpuid options to feature bits, otherwise return failure
+ * (option tags in *str are delimited by whitespace)
+ */
+static void setfeatures(uint32_t *pval, const char *str,
+ const char **featureset, int *perr)
+{
+ const char *p, *q;
+
+ for (q = p = str; *p || *q; q = p) {
+ while (iswhite(*p))
+ q = ++p;
+ while (*p && !iswhite(*p))
+ ++p;
+ if (!*q && !*p)
+ return;
+ if (!lookup_feature(pval, q, p, featureset)) {
+ fprintf(stderr, "error: feature \"%.*s\" not available in set\n",
+ (int)(p - q), q);
+ *perr = 1;
+ return;
+ }
+ }
+}
+
+/* map config file options to x86_def_t form
+ */
+static int cpudef_setfield(const char *name, const char *str, void *opaque)
+{
+ x86_def_t *def = opaque;
+ int err = 0;
+
+ if (!strcmp(name, "name")) {
+ def->name = strdup(str);
+ } else if (!strcmp(name, "model_id")) {
+ strncpy(def->model_id, str, sizeof (def->model_id));
+ } else if (!strcmp(name, "level")) {
+ setscalar(&def->level, str, &err)
+ } else if (!strcmp(name, "vendor")) {
+ cpyid(&str[0], &def->vendor1);
+ cpyid(&str[4], &def->vendor2);
+ cpyid(&str[8], &def->vendor3);
+ } else if (!strcmp(name, "family")) {
+ setscalar(&def->family, str, &err)
+ } else if (!strcmp(name, "model")) {
+ setscalar(&def->model, str, &err)
+ } else if (!strcmp(name, "stepping")) {
+ setscalar(&def->stepping, str, &err)
+ } else if (!strcmp(name, "feature_edx")) {
+ setfeatures(&def->features, str, feature_name, &err);
+ } else if (!strcmp(name, "feature_ecx")) {
+ setfeatures(&def->ext_features, str, ext_feature_name, &err);
+ } else if (!strcmp(name, "extfeature_edx")) {
+ setfeatures(&def->ext2_features, str, ext2_feature_name, &err);
+ } else if (!strcmp(name, "extfeature_ecx")) {
+ setfeatures(&def->ext3_features, str, ext3_feature_name, &err);
+ } else if (!strcmp(name, "xlevel")) {
+ setscalar(&def->xlevel, str, &err)
+ } else {
+ fprintf(stderr, "error: unknown option [%s = %s]\n", name, str);
+ return (1);
+ }
+ if (err) {
+ fprintf(stderr, "error: bad option value [%s = %s]\n", name, str);
+ return (1);
+ }
+ return (0);
+}
+
+/* register config file entry as x86_def_t
+ */
+static int cpudef_register(QemuOpts *opts, void *opaque)
+{
+ x86_def_t *def = qemu_mallocz(sizeof (x86_def_t));
+
+ qemu_opt_foreach(opts, cpudef_setfield, def, 1);
+ def->next = x86_defs;
+ x86_defs = def;
+ return (0);
+}
+#endif /* !CONFIG_LINUX_USER */
+
+/* register "cpudef" models defined in configuration file. Here we first
+ * preload any built-in definitions
+ */
+void x86_cpudef_setup(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
+ builtin_x86_defs[i].next = x86_defs;
+ builtin_x86_defs[i].flags = 1;
+ x86_defs = &builtin_x86_defs[i];
+ }
+#if !defined(CONFIG_LINUX_USER)
+ qemu_opts_foreach(&qemu_cpudef_opts, cpudef_register, NULL, 0);
+#endif
+}
+
/* NOTE: must be called outside the CPU execute loop */
void cpu_reset(CPUX86State *env)
{
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 5d9aecc89d..6b741ba489 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -24,6 +24,7 @@
#include "cpu.h"
#include "gdbstub.h"
#include "host-utils.h"
+#include "hw/pc.h"
#ifdef CONFIG_KVM_PARA
#include <linux/kvm_para.h>
@@ -359,6 +360,13 @@ int kvm_arch_init(KVMState *s, int smp_cpus)
* as unavaible memory. FIXME, need to ensure the e820 map deals with
* this?
*/
+ /*
+ * Tell fw_cfg to notify the BIOS to reserve the range.
+ */
+ if (e820_add_entry(0xfffbc000, 0x4000, E820_RESERVED) < 0) {
+ perror("e820_add_entry() table is full");
+ exit(1);
+ }
return kvm_vm_ioctl(s, KVM_SET_TSS_ADDR, 0xfffbd000);
}
diff --git a/target-m68k/exec.h b/target-m68k/exec.h
index 1267bb600f..ece9aa09cd 100644
--- a/target-m68k/exec.h
+++ b/target-m68k/exec.h
@@ -20,10 +20,6 @@
#include "dyngen-exec.h"
register struct CPUM68KState *env asm(AREG0);
-/* This is only used for tb lookup. */
-register uint32_t T0 asm(AREG1);
-/* ??? We don't use T1, but common code expects it to exist */
-#define T1 env->t1
#include "cpu.h"
#include "exec-all.h"
diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c
index af89dcfa69..8a9cea2f27 100644
--- a/target-microblaze/op_helper.c
+++ b/target-microblaze/op_helper.c
@@ -251,6 +251,12 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
int is_asi, int size)
{
CPUState *saved_env;
+
+ if (!cpu_single_env) {
+ /* XXX: ??? */
+ return;
+ }
+
/* XXX: hack to restore env in all cases, even if not called from
generated code */
saved_env = env;
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index 583f09d7b4..ca54e2c30e 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -993,6 +993,7 @@ static void dec_bcc(DisasContext *dc)
static void dec_br(DisasContext *dc)
{
unsigned int dslot, link, abs;
+ int mem_index = cpu_mmu_index(dc->env);
dslot = dc->ir & (1 << 20);
abs = dc->ir & (1 << 19);
@@ -1016,11 +1017,19 @@ static void dec_br(DisasContext *dc)
if (abs) {
tcg_gen_movi_tl(env_btaken, 1);
tcg_gen_mov_tl(env_btarget, *(dec_alu_op_b(dc)));
- if (link && !(dc->tb_flags & IMM_FLAG)
- && (dc->imm == 8 || dc->imm == 0x18))
- t_gen_raise_exception(dc, EXCP_BREAK);
- if (dc->imm == 0)
- t_gen_raise_exception(dc, EXCP_DEBUG);
+ if (link && !dslot) {
+ if (!(dc->tb_flags & IMM_FLAG) && (dc->imm == 8 || dc->imm == 0x18))
+ t_gen_raise_exception(dc, EXCP_BREAK);
+ if (dc->imm == 0) {
+ if ((dc->tb_flags & MSR_EE_FLAG) && mem_index == MMU_USER_IDX) {
+ tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+ t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ return;
+ }
+
+ t_gen_raise_exception(dc, EXCP_DEBUG);
+ }
+ }
} else {
if (!dc->type_b || (dc->tb_flags & IMM_FLAG)) {
tcg_gen_movi_tl(env_btaken, 1);
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index a4fae31e38..cd1c9fea0e 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -736,14 +736,13 @@ static inline int slb_lookup(CPUPPCState *env, target_ulong eaddr,
PRIx32 "\n", __func__, n, slb->tmp64, slb->tmp);
if (slb_is_valid(slb)) {
/* SLB entry is valid */
+ mask = 0xFFFFFFFFF0000000ULL;
if (slb->tmp & 0x8) {
- /* 1 TB Segment */
- mask = 0xFFFF000000000000ULL;
+ /* 16 MB PTEs */
if (target_page_bits)
- *target_page_bits = 24; // XXX 16M pages?
+ *target_page_bits = 24;
} else {
- /* 256MB Segment */
- mask = 0xFFFFFFFFF0000000ULL;
+ /* 4 KB PTEs */
if (target_page_bits)
*target_page_bits = TARGET_PAGE_BITS;
}
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 0424a78422..8ad003799c 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -37,6 +37,22 @@
do { } while (0)
#endif
+/* XXX For some odd reason we sometimes hang inside KVM forever. I'd guess it's
+ * a race condition where we actually have a level triggered interrupt, but
+ * the infrastructure can't expose that yet, so the guest ACKs it, goes to
+ * sleep and never gets notified that there's still an interrupt pending.
+ *
+ * As a quick workaround, let's just wake up every 500 ms. That way we can
+ * assure that we're always reinjecting interrupts in time.
+ */
+static QEMUTimer *idle_timer;
+
+static void do_nothing(void *opaque)
+{
+ qemu_mod_timer(idle_timer, qemu_get_clock(vm_clock) +
+ (get_ticks_per_sec() / 2));
+}
+
int kvm_arch_init(KVMState *s, int smp_cpus)
{
return 0;
@@ -173,6 +189,12 @@ int kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
int r;
unsigned irq;
+ if (!idle_timer) {
+ idle_timer = qemu_new_timer(vm_clock, do_nothing, NULL);
+ qemu_mod_timer(idle_timer, qemu_get_clock(vm_clock) +
+ (get_ticks_per_sec() / 2));
+ }
+
/* PowerPC Qemu tracks the various core input pins (interrupt, critical
* interrupt, reset, etc) in PPC-specific env->irq_input_state. */
if (run->ready_for_interrupt_injection &&
@@ -252,3 +274,50 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
return ret;
}
+static int read_cpuinfo(const char *field, char *value, int len)
+{
+ FILE *f;
+ int ret = -1;
+ int field_len = strlen(field);
+ char line[512];
+
+ f = fopen("/proc/cpuinfo", "r");
+ if (!f) {
+ return -1;
+ }
+
+ do {
+ if(!fgets(line, sizeof(line), f)) {
+ break;
+ }
+ if (!strncmp(line, field, field_len)) {
+ strncpy(value, line, len);
+ ret = 0;
+ break;
+ }
+ } while(*line);
+
+ fclose(f);
+
+ return ret;
+}
+
+uint32_t kvmppc_get_tbfreq(void)
+{
+ char line[512];
+ char *ns;
+ uint32_t retval = get_ticks_per_sec();
+
+ if (read_cpuinfo("timebase", line, sizeof(line))) {
+ return retval;
+ }
+
+ if (!(ns = strchr(line, ':'))) {
+ return retval;
+ }
+
+ ns++;
+
+ retval = atoi(ns);
+ return retval;
+}
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index 3792ef7251..e8d66e88e4 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -14,4 +14,6 @@ void kvmppc_fdt_update(void *fdt);
int kvmppc_read_host_property(const char *node_path, const char *prop,
void *val, size_t len);
+uint32_t kvmppc_get_tbfreq(void);
+
#endif /* __KVM_PPC_H__ */
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 7e9f0cfe77..b7d2a324c2 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1663,27 +1663,27 @@ static inline TCGv get_src2(unsigned int insn, TCGv def)
#ifdef TARGET_SPARC64
static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_ptr cpu_env)
{
- TCGv r_tl = tcg_temp_new();
+ TCGv_i32 r_tl = tcg_temp_new_i32();
/* load env->tl into r_tl */
- {
- TCGv_i32 r_tl_tmp = tcg_temp_new_i32();
- tcg_gen_ld_i32(r_tl_tmp, cpu_env, offsetof(CPUSPARCState, tl));
- tcg_gen_ext_i32_tl(r_tl, r_tl_tmp);
- tcg_temp_free_i32(r_tl_tmp);
- }
+ tcg_gen_ld_i32(r_tl, cpu_env, offsetof(CPUSPARCState, tl));
/* tl = [0 ... MAXTL_MASK] where MAXTL_MASK must be power of 2 */
- tcg_gen_andi_tl(r_tl, r_tl, MAXTL_MASK);
+ tcg_gen_andi_i32(r_tl, r_tl, MAXTL_MASK);
/* calculate offset to current trap state from env->ts, reuse r_tl */
- tcg_gen_muli_tl(r_tl, r_tl, sizeof (trap_state));
+ tcg_gen_muli_i32(r_tl, r_tl, sizeof (trap_state));
tcg_gen_addi_ptr(r_tsptr, cpu_env, offsetof(CPUState, ts));
/* tsptr = env->ts[env->tl & MAXTL_MASK] */
- tcg_gen_add_ptr(r_tsptr, r_tsptr, r_tl);
+ {
+ TCGv_ptr r_tl_tmp = tcg_temp_new_ptr();
+ tcg_gen_ext_i32_ptr(r_tl_tmp, r_tl);
+ tcg_gen_add_ptr(r_tsptr, r_tsptr, r_tl_tmp);
+ tcg_temp_free_i32(r_tl_tmp);
+ }
- tcg_temp_free(r_tl);
+ tcg_temp_free_i32(r_tl);
}
#endif
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
index 71e1ec550a..5eac7bfbd9 100644
--- a/tcg/arm/tcg-target.h
+++ b/tcg/arm/tcg-target.h
@@ -63,6 +63,20 @@ enum {
#define TCG_TARGET_STACK_ALIGN 8
#define TCG_TARGET_CALL_STACK_OFFSET 0
+/* optional instructions */
+// #define TCG_TARGET_HAS_div_i32
+// #define TCG_TARGET_HAS_rot_i32
+// #define TCG_TARGET_HAS_ext8s_i32
+// #define TCG_TARGET_HAS_ext16s_i32
+// #define TCG_TARGET_HAS_ext8u_i32
+// #define TCG_TARGET_HAS_ext16u_i32
+// #define TCG_TARGET_HAS_bswap16_i32
+// #define TCG_TARGET_HAS_bswap32_i32
+// #define TCG_TARGET_HAS_not_i32
+// #define TCG_TARGET_HAS_neg_i32
+// #define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_orc_i32
+
#define TCG_TARGET_HAS_GUEST_BASE
enum {
diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c
index ddce60c81f..4677971e7b 100644
--- a/tcg/hppa/tcg-target.c
+++ b/tcg/hppa/tcg-target.c
@@ -936,7 +936,6 @@ static const TCGTargetOpDef hppa_op_defs[] = {
{ INDEX_op_qemu_ld16u, { "r", "L", "L" } },
{ INDEX_op_qemu_ld16s, { "r", "L", "L" } },
{ INDEX_op_qemu_ld32u, { "r", "L", "L" } },
- { INDEX_op_qemu_ld32s, { "r", "L", "L" } },
{ INDEX_op_qemu_ld64, { "r", "r", "L", "L" } },
{ INDEX_op_qemu_st8, { "L", "L", "L" } },
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index 69227c3bc5..f97034cd50 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -45,15 +45,17 @@ enum {
#define TCG_TARGET_CALL_STACK_OFFSET 0
/* optional instructions */
-#define TCG_TARGET_HAS_bswap16_i32
-#define TCG_TARGET_HAS_bswap32_i32
-#define TCG_TARGET_HAS_neg_i32
-#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_rot_i32
#define TCG_TARGET_HAS_ext8s_i32
#define TCG_TARGET_HAS_ext16s_i32
-#define TCG_TARGET_HAS_rot_i32
#define TCG_TARGET_HAS_ext8u_i32
#define TCG_TARGET_HAS_ext16u_i32
+#define TCG_TARGET_HAS_bswap16_i32
+#define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_neg_i32
+#define TCG_TARGET_HAS_not_i32
+// #define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_orc_i32
#define TCG_TARGET_HAS_GUEST_BASE
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
index 46760a50e1..377b0c8dc8 100644
--- a/tcg/mips/tcg-target.h
+++ b/tcg/mips/tcg-target.h
@@ -80,11 +80,13 @@ enum {
/* optional instructions */
#define TCG_TARGET_HAS_div_i32
#define TCG_TARGET_HAS_not_i32
+#undef TCG_TARGET_HAS_rot_i32
#undef TCG_TARGET_HAS_ext8s_i32
#undef TCG_TARGET_HAS_ext16s_i32
#undef TCG_TARGET_HAS_bswap32_i32
#undef TCG_TARGET_HAS_bswap16_i32
-#undef TCG_TARGET_HAS_rot_i32
+#undef TCG_TARGET_HAS_andc_i32
+#undef TCG_TARGET_HAS_orc_i32
/* optional instructions automatically implemented */
#undef TCG_TARGET_HAS_neg_i32 /* sub rd, zero, rt */
diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index 502df87ddc..96cc461900 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -24,10 +24,10 @@
static uint8_t *tb_ret_addr;
-#ifdef __APPLE__
+#ifdef _CALL_DARWIN
#define LINKAGE_AREA_SIZE 24
#define LR_OFFSET 8
-#elif defined _AIX
+#elif defined _CALL_AIX
#define LINKAGE_AREA_SIZE 52
#define LR_OFFSET 8
#else
@@ -104,7 +104,7 @@ static const int tcg_target_reg_alloc_order[] = {
TCG_REG_R29,
TCG_REG_R30,
TCG_REG_R31,
-#ifdef __APPLE__
+#ifdef _CALL_DARWIN
TCG_REG_R2,
#endif
TCG_REG_R3,
@@ -115,11 +115,11 @@ static const int tcg_target_reg_alloc_order[] = {
TCG_REG_R8,
TCG_REG_R9,
TCG_REG_R10,
-#ifndef __APPLE__
+#ifndef _CALL_DARWIN
TCG_REG_R11,
#endif
TCG_REG_R12,
-#ifndef __linux__
+#ifndef _CALL_SYSV
TCG_REG_R13,
#endif
TCG_REG_R24,
@@ -145,11 +145,11 @@ static const int tcg_target_call_oarg_regs[2] = {
};
static const int tcg_target_callee_save_regs[] = {
-#ifdef __APPLE__
+#ifdef _CALL_DARWIN
TCG_REG_R11,
TCG_REG_R13,
#endif
-#ifdef _AIX
+#ifdef _CALL_AIX
TCG_REG_R13,
#endif
TCG_REG_R14,
@@ -333,6 +333,7 @@ static int tcg_target_const_match(tcg_target_long val,
#define STWU OPCD(37)
#define RLWINM OPCD(21)
+#define RLWNM OPCD(23)
#define BCLR XO19( 16)
#define BCCTR XO19(528)
@@ -369,6 +370,9 @@ static int tcg_target_const_match(tcg_target_long val,
#define NEG XO31(104)
#define MFCR XO31( 19)
#define CNTLZW XO31( 26)
+#define NOR XO31(124)
+#define ANDC XO31( 60)
+#define ORC XO31(412)
#define LBZX XO31( 87)
#define LHZX XO31(279)
@@ -478,7 +482,7 @@ static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target)
static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg)
{
-#ifdef _AIX
+#ifdef _CALL_AIX
int reg;
if (const_arg) {
@@ -908,7 +912,7 @@ void tcg_target_qemu_prologue (TCGContext *s)
;
frame_size = (frame_size + 15) & ~15;
-#ifdef _AIX
+#ifdef _CALL_AIX
{
uint32_t addr;
@@ -1468,6 +1472,12 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
else
tcg_out32 (s, XOR | SAB (args[1], args[0], args[2]));
break;
+ case INDEX_op_andc_i32:
+ tcg_out32 (s, ANDC | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_orc_i32:
+ tcg_out32 (s, ORC | SAB (args[1], args[0], args[2]));
+ break;
case INDEX_op_mul_i32:
if (const_args[2]) {
@@ -1549,6 +1559,45 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
else
tcg_out32 (s, SRAW | SAB (args[1], args[0], args[2]));
break;
+ case INDEX_op_rotl_i32:
+ {
+ int op = 0
+ | RA (args[0])
+ | RS (args[1])
+ | MB (0)
+ | ME (31)
+ | (const_args[2] ? RLWINM | SH (args[2])
+ : RLWNM | RB (args[2]))
+ ;
+ tcg_out32 (s, op);
+ }
+ break;
+ case INDEX_op_rotr_i32:
+ if (const_args[2]) {
+ if (!args[2]) {
+ tcg_out_mov (s, args[0], args[1]);
+ }
+ else {
+ tcg_out32 (s, RLWINM
+ | RA (args[0])
+ | RS (args[1])
+ | SH (32 - args[2])
+ | MB (0)
+ | ME (31)
+ );
+ }
+ }
+ else {
+ tcg_out32 (s, ADDI | RT (0) | RA (args[2]) | 0xffe0);
+ tcg_out32 (s, RLWNM
+ | RA (args[0])
+ | RS (args[1])
+ | RB (0)
+ | MB (0)
+ | ME (31)
+ );
+ }
+ break;
case INDEX_op_add2_i32:
if (args[0] == args[3] || args[0] == args[5]) {
@@ -1591,6 +1640,10 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
tcg_out32 (s, NEG | RT (args[0]) | RA (args[1]));
break;
+ case INDEX_op_not_i32:
+ tcg_out32 (s, NOR | SAB (args[1], args[0], args[0]));
+ break;
+
case INDEX_op_qemu_ld8u:
tcg_out_qemu_ld(s, args, 0);
break;
@@ -1625,9 +1678,27 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
case INDEX_op_ext8s_i32:
tcg_out32 (s, EXTSB | RS (args[1]) | RA (args[0]));
break;
+ case INDEX_op_ext8u_i32:
+ tcg_out32 (s, RLWINM
+ | RA (args[0])
+ | RS (args[1])
+ | SH (0)
+ | MB (24)
+ | ME (31)
+ );
+ break;
case INDEX_op_ext16s_i32:
tcg_out32 (s, EXTSH | RS (args[1]) | RA (args[0]));
break;
+ case INDEX_op_ext16u_i32:
+ tcg_out32 (s, RLWINM
+ | RA (args[0])
+ | RS (args[1])
+ | SH (0)
+ | MB (16)
+ | ME (31)
+ );
+ break;
case INDEX_op_setcond_i32:
tcg_out_setcond (s, args[3], args[0], args[1], args[2], const_args[2]);
@@ -1676,6 +1747,9 @@ static const TCGTargetOpDef ppc_op_defs[] = {
{ INDEX_op_shr_i32, { "r", "r", "ri" } },
{ INDEX_op_sar_i32, { "r", "r", "ri" } },
+ { INDEX_op_rotl_i32, { "r", "r", "ri" } },
+ { INDEX_op_rotr_i32, { "r", "r", "ri" } },
+
{ INDEX_op_brcond_i32, { "r", "ri" } },
{ INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } },
@@ -1683,6 +1757,10 @@ static const TCGTargetOpDef ppc_op_defs[] = {
{ INDEX_op_brcond2_i32, { "r", "r", "r", "r" } },
{ INDEX_op_neg_i32, { "r", "r" } },
+ { INDEX_op_not_i32, { "r", "r" } },
+
+ { INDEX_op_andc_i32, { "r", "r", "r" } },
+ { INDEX_op_orc_i32, { "r", "r", "r" } },
{ INDEX_op_setcond_i32, { "r", "r", "ri" } },
{ INDEX_op_setcond2_i32, { "r", "r", "r", "ri", "ri" } },
@@ -1693,7 +1771,6 @@ static const TCGTargetOpDef ppc_op_defs[] = {
{ INDEX_op_qemu_ld16u, { "r", "L" } },
{ INDEX_op_qemu_ld16s, { "r", "L" } },
{ INDEX_op_qemu_ld32u, { "r", "L" } },
- { INDEX_op_qemu_ld32s, { "r", "L" } },
{ INDEX_op_qemu_ld64, { "r", "r", "L" } },
{ INDEX_op_qemu_st8, { "K", "K" } },
@@ -1706,7 +1783,6 @@ static const TCGTargetOpDef ppc_op_defs[] = {
{ INDEX_op_qemu_ld16u, { "r", "L", "L" } },
{ INDEX_op_qemu_ld16s, { "r", "L", "L" } },
{ INDEX_op_qemu_ld32u, { "r", "L", "L" } },
- { INDEX_op_qemu_ld32s, { "r", "L", "L" } },
{ INDEX_op_qemu_ld64, { "r", "L", "L", "L" } },
{ INDEX_op_qemu_st8, { "K", "K", "K" } },
@@ -1716,7 +1792,9 @@ static const TCGTargetOpDef ppc_op_defs[] = {
#endif
{ INDEX_op_ext8s_i32, { "r", "r" } },
+ { INDEX_op_ext8u_i32, { "r", "r" } },
{ INDEX_op_ext16s_i32, { "r", "r" } },
+ { INDEX_op_ext16u_i32, { "r", "r" } },
{ -1 },
};
@@ -1726,7 +1804,7 @@ void tcg_target_init(TCGContext *s)
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
tcg_regset_set32(tcg_target_call_clobber_regs, 0,
(1 << TCG_REG_R0) |
-#ifdef __APPLE__
+#ifdef _CALL_DARWIN
(1 << TCG_REG_R2) |
#endif
(1 << TCG_REG_R3) |
@@ -1744,10 +1822,10 @@ void tcg_target_init(TCGContext *s)
tcg_regset_clear(s->reserved_regs);
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0);
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1);
-#ifndef __APPLE__
+#ifndef _CALL_DARWIN
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R2);
#endif
-#ifdef __linux__
+#ifdef _CALL_SYSV
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13);
#endif
#ifdef CONFIG_USE_GUEST_BASE
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index 0197e79930..0c71a11038 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -65,11 +65,11 @@ enum {
/* used for function call generation */
#define TCG_REG_CALL_STACK TCG_REG_R1
#define TCG_TARGET_STACK_ALIGN 16
-#if defined __APPLE__
+#if defined _CALL_DARWIN
#define TCG_TARGET_CALL_STACK_OFFSET 24
-#elif defined _AIX
+#elif defined _CALL_AIX
#define TCG_TARGET_CALL_STACK_OFFSET 52
-#elif defined __linux__
+#elif defined _CALL_SYSV
#define TCG_TARGET_CALL_ALIGN_ARGS 1
#define TCG_TARGET_CALL_STACK_OFFSET 8
#else
@@ -77,10 +77,18 @@ enum {
#endif
/* optional instructions */
-#define TCG_TARGET_HAS_neg_i32
#define TCG_TARGET_HAS_div_i32
+#define TCG_TARGET_HAS_rot_i32
#define TCG_TARGET_HAS_ext8s_i32
#define TCG_TARGET_HAS_ext16s_i32
+#define TCG_TARGET_HAS_ext8u_i32
+#define TCG_TARGET_HAS_ext16u_i32
+/* #define TCG_TARGET_HAS_bswap16_i32 */
+/* #define TCG_TARGET_HAS_bswap32_i32 */
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_neg_i32
+#define TCG_TARGET_HAS_andc_i32
+#define TCG_TARGET_HAS_orc_i32
#define TCG_AREG0 TCG_REG_R27
#define TCG_AREG1 TCG_REG_R24
diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h
index 94b800fa6d..f5de6421fc 100644
--- a/tcg/ppc64/tcg-target.h
+++ b/tcg/ppc64/tcg-target.h
@@ -68,15 +68,34 @@ enum {
#define TCG_TARGET_CALL_STACK_OFFSET 48
/* optional instructions */
-#define TCG_TARGET_HAS_neg_i32
#define TCG_TARGET_HAS_div_i32
-#define TCG_TARGET_HAS_neg_i64
-#define TCG_TARGET_HAS_div_i64
+/* #define TCG_TARGET_HAS_rot_i32 */
#define TCG_TARGET_HAS_ext8s_i32
#define TCG_TARGET_HAS_ext16s_i32
+/* #define TCG_TARGET_HAS_ext8u_i32 */
+/* #define TCG_TARGET_HAS_ext16u_i32 */
+/* #define TCG_TARGET_HAS_bswap16_i32 */
+/* #define TCG_TARGET_HAS_bswap32_i32 */
+/* #define TCG_TARGET_HAS_not_i32 */
+#define TCG_TARGET_HAS_neg_i32
+/* #define TCG_TARGET_HAS_andc_i32 */
+/* #define TCG_TARGET_HAS_orc_i32 */
+
+#define TCG_TARGET_HAS_div_i64
+/* #define TCG_TARGET_HAS_rot_i64 */
#define TCG_TARGET_HAS_ext8s_i64
#define TCG_TARGET_HAS_ext16s_i64
#define TCG_TARGET_HAS_ext32s_i64
+/* #define TCG_TARGET_HAS_ext8u_i64 */
+/* #define TCG_TARGET_HAS_ext16u_i64 */
+/* #define TCG_TARGET_HAS_ext32u_i64 */
+/* #define TCG_TARGET_HAS_bswap16_i64 */
+/* #define TCG_TARGET_HAS_bswap32_i64 */
+/* #define TCG_TARGET_HAS_bswap64_i64 */
+/* #define TCG_TARGET_HAS_not_i64 */
+#define TCG_TARGET_HAS_neg_i64
+/* #define TCG_TARGET_HAS_andc_i64 */
+/* #define TCG_TARGET_HAS_orc_i64 */
#define TCG_AREG0 TCG_REG_R27
#define TCG_AREG1 TCG_REG_R24
diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
index 91b931d6be..e8034019c7 100644
--- a/tcg/s390/tcg-target.h
+++ b/tcg/s390/tcg-target.h
@@ -46,6 +46,36 @@ enum {
};
#define TCG_TARGET_NB_REGS 16
+/* optional instructions */
+// #define TCG_TARGET_HAS_div_i32
+// #define TCG_TARGET_HAS_rot_i32
+// #define TCG_TARGET_HAS_ext8s_i32
+// #define TCG_TARGET_HAS_ext16s_i32
+// #define TCG_TARGET_HAS_ext8u_i32
+// #define TCG_TARGET_HAS_ext16u_i32
+// #define TCG_TARGET_HAS_bswap16_i32
+// #define TCG_TARGET_HAS_bswap32_i32
+// #define TCG_TARGET_HAS_not_i32
+// #define TCG_TARGET_HAS_neg_i32
+// #define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_orc_i32
+
+// #define TCG_TARGET_HAS_div_i64
+// #define TCG_TARGET_HAS_rot_i64
+// #define TCG_TARGET_HAS_ext8s_i64
+// #define TCG_TARGET_HAS_ext16s_i64
+// #define TCG_TARGET_HAS_ext32s_i64
+// #define TCG_TARGET_HAS_ext8u_i64
+// #define TCG_TARGET_HAS_ext16u_i64
+// #define TCG_TARGET_HAS_ext32u_i64
+// #define TCG_TARGET_HAS_bswap16_i64
+// #define TCG_TARGET_HAS_bswap32_i64
+// #define TCG_TARGET_HAS_bswap64_i64
+// #define TCG_TARGET_HAS_not_i64
+// #define TCG_TARGET_HAS_neg_i64
+// #define TCG_TARGET_HAS_andc_i64
+// #define TCG_TARGET_HAS_orc_i64
+
/* used for function call generation */
#define TCG_REG_CALL_STACK TCG_REG_R15
#define TCG_TARGET_STACK_ALIGN 8
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index dd7a598bc8..d4ddaa79b3 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -194,6 +194,7 @@ static inline int tcg_target_const_match(tcg_target_long val,
#define INSN_RS2(x) (x)
#define INSN_ASI(x) ((x) << 5)
+#define INSN_IMM11(x) ((1 << 13) | ((x) & 0x7ff))
#define INSN_IMM13(x) ((1 << 13) | ((x) & 0x1fff))
#define INSN_OFF19(x) (((x) >> 2) & 0x07ffff)
#define INSN_OFF22(x) (((x) >> 2) & 0x3fffff)
@@ -217,11 +218,16 @@ static inline int tcg_target_const_match(tcg_target_long val,
#define COND_VC 0xf
#define BA (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2))
+#define MOVCC_ICC (1 << 18)
+#define MOVCC_XCC (1 << 18 | 1 << 12)
+
#define ARITH_ADD (INSN_OP(2) | INSN_OP3(0x00))
#define ARITH_ADDCC (INSN_OP(2) | INSN_OP3(0x10))
#define ARITH_AND (INSN_OP(2) | INSN_OP3(0x01))
+#define ARITH_ANDN (INSN_OP(2) | INSN_OP3(0x05))
#define ARITH_OR (INSN_OP(2) | INSN_OP3(0x02))
#define ARITH_ORCC (INSN_OP(2) | INSN_OP3(0x12))
+#define ARITH_ORN (INSN_OP(2) | INSN_OP3(0x06))
#define ARITH_XOR (INSN_OP(2) | INSN_OP3(0x03))
#define ARITH_SUB (INSN_OP(2) | INSN_OP3(0x04))
#define ARITH_SUBCC (INSN_OP(2) | INSN_OP3(0x14))
@@ -233,6 +239,7 @@ static inline int tcg_target_const_match(tcg_target_long val,
#define ARITH_MULX (INSN_OP(2) | INSN_OP3(0x09))
#define ARITH_UDIVX (INSN_OP(2) | INSN_OP3(0x0d))
#define ARITH_SDIVX (INSN_OP(2) | INSN_OP3(0x2d))
+#define ARITH_MOVCC (INSN_OP(2) | INSN_OP3(0x2c))
#define SHIFT_SLL (INSN_OP(2) | INSN_OP3(0x25))
#define SHIFT_SRL (INSN_OP(2) | INSN_OP3(0x26))
@@ -580,6 +587,109 @@ static void tcg_out_brcond2_i32(TCGContext *s, int cond,
}
#endif
+static void tcg_out_setcond_i32(TCGContext *s, int cond, TCGArg ret,
+ TCGArg c1, TCGArg c2, int c2const)
+{
+ TCGArg t;
+
+ /* For 32-bit comparisons, we can play games with ADDX/SUBX. */
+ switch (cond) {
+ case TCG_COND_EQ:
+ case TCG_COND_NE:
+ if (c2 != 0) {
+ tcg_out_arithc(s, ret, c1, c2, c2const, ARITH_XOR);
+ }
+ c1 = TCG_REG_G0, c2 = ret, c2const = 0;
+ cond = (cond == TCG_COND_EQ ? TCG_COND_LEU : TCG_COND_LTU);
+ break;
+
+ case TCG_COND_GTU:
+ case TCG_COND_GEU:
+ if (c2const && c2 != 0) {
+ tcg_out_movi_imm13(s, TCG_REG_I5, c2);
+ c2 = TCG_REG_I5;
+ }
+ t = c1, c1 = c2, c2 = t, c2const = 0;
+ cond = tcg_swap_cond(cond);
+ break;
+
+ case TCG_COND_LTU:
+ case TCG_COND_LEU:
+ break;
+
+ default:
+ tcg_out_cmp(s, c1, c2, c2const);
+#if defined(__sparc_v9__) || defined(__sparc_v8plus__)
+ tcg_out_movi_imm13(s, ret, 0);
+ tcg_out32 (s, ARITH_MOVCC | INSN_RD(ret)
+ | INSN_RS1(tcg_cond_to_bcond[cond])
+ | MOVCC_ICC | INSN_IMM11(1));
+#else
+ t = gen_new_label();
+ tcg_out_branch_i32(s, INSN_COND(tcg_cond_to_bcond[cond], 1), t);
+ tcg_out_movi_imm13(s, ret, 1);
+ tcg_out_movi_imm13(s, ret, 0);
+ tcg_out_label(s, t, (tcg_target_long)s->code_ptr);
+#endif
+ return;
+ }
+
+ tcg_out_cmp(s, c1, c2, c2const);
+ if (cond == TCG_COND_LTU) {
+ tcg_out_arithi(s, ret, TCG_REG_G0, 0, ARITH_ADDX);
+ } else {
+ tcg_out_arithi(s, ret, TCG_REG_G0, -1, ARITH_SUBX);
+ }
+}
+
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_setcond_i64(TCGContext *s, int cond, TCGArg ret,
+ TCGArg c1, TCGArg c2, int c2const)
+{
+ tcg_out_cmp(s, c1, c2, c2const);
+ tcg_out_movi_imm13(s, ret, 0);
+ tcg_out32 (s, ARITH_MOVCC | INSN_RD(ret)
+ | INSN_RS1(tcg_cond_to_bcond[cond])
+ | MOVCC_XCC | INSN_IMM11(1));
+}
+#else
+static void tcg_out_setcond2_i32(TCGContext *s, int cond, TCGArg ret,
+ TCGArg al, TCGArg ah,
+ TCGArg bl, int blconst,
+ TCGArg bh, int bhconst)
+{
+ int lab;
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ tcg_out_setcond_i32(s, TCG_COND_EQ, TCG_REG_I5, al, bl, blconst);
+ tcg_out_setcond_i32(s, TCG_COND_EQ, ret, ah, bh, bhconst);
+ tcg_out_arith(s, ret, ret, TCG_REG_I5, ARITH_AND);
+ break;
+
+ case TCG_COND_NE:
+ tcg_out_setcond_i32(s, TCG_COND_NE, TCG_REG_I5, al, al, blconst);
+ tcg_out_setcond_i32(s, TCG_COND_NE, ret, ah, bh, bhconst);
+ tcg_out_arith(s, ret, ret, TCG_REG_I5, ARITH_OR);
+ break;
+
+ default:
+ lab = gen_new_label();
+
+ tcg_out_cmp(s, ah, bh, bhconst);
+ tcg_out_branch_i32(s, INSN_COND(tcg_cond_to_bcond[cond], 1), lab);
+ tcg_out_movi_imm13(s, ret, 1);
+ tcg_out_branch_i32(s, INSN_COND(COND_NE, 1), lab);
+ tcg_out_movi_imm13(s, ret, 0);
+
+ tcg_out_setcond_i32(s, tcg_unsigned_cond(cond), ret, al, bl, blconst);
+
+ tcg_out_label(s, lab, (tcg_target_long)s->code_ptr);
+ break;
+ }
+}
+#endif
+
/* Generate global QEMU prologue and epilogue code */
void tcg_target_qemu_prologue(TCGContext *s)
{
@@ -1107,9 +1217,15 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
OP_32_64(and):
c = ARITH_AND;
goto gen_arith;
+ OP_32_64(andc):
+ c = ARITH_ANDN;
+ goto gen_arith;
OP_32_64(or):
c = ARITH_OR;
goto gen_arith;
+ OP_32_64(orc):
+ c = ARITH_ORN;
+ goto gen_arith;
OP_32_64(xor):
c = ARITH_XOR;
goto gen_arith;
@@ -1126,6 +1242,13 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
c = ARITH_UMUL;
goto gen_arith;
+ OP_32_64(neg):
+ c = ARITH_SUB;
+ goto gen_arith1;
+ OP_32_64(not):
+ c = ARITH_ORN;
+ goto gen_arith1;
+
case INDEX_op_div_i32:
tcg_out_div32(s, args[0], args[1], args[2], const_args[2], 0);
break;
@@ -1146,12 +1269,22 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
tcg_out_brcond_i32(s, args[2], args[0], args[1], const_args[1],
args[3]);
break;
+ case INDEX_op_setcond_i32:
+ tcg_out_setcond_i32(s, args[3], args[0], args[1],
+ args[2], const_args[2]);
+ break;
+
#if TCG_TARGET_REG_BITS == 32
case INDEX_op_brcond2_i32:
tcg_out_brcond2_i32(s, args[4], args[0], args[1],
args[2], const_args[2],
args[3], const_args[3], args[5]);
break;
+ case INDEX_op_setcond2_i32:
+ tcg_out_setcond2_i32(s, args[5], args[0], args[1], args[2],
+ args[3], const_args[3],
+ args[4], const_args[4]);
+ break;
case INDEX_op_add2_i32:
tcg_out_arithc(s, args[0], args[2], args[4], const_args[4],
ARITH_ADDCC);
@@ -1186,9 +1319,11 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
case INDEX_op_qemu_ld32u:
tcg_out_qemu_ld(s, args, 2);
break;
+#if TCG_TARGET_REG_BITS == 64
case INDEX_op_qemu_ld32s:
tcg_out_qemu_ld(s, args, 2 | 4);
break;
+#endif
case INDEX_op_qemu_st8:
tcg_out_qemu_st(s, args, 0);
break;
@@ -1257,6 +1392,11 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
tcg_out_brcond_i64(s, args[2], args[0], args[1], const_args[1],
args[3]);
break;
+ case INDEX_op_setcond_i64:
+ tcg_out_setcond_i64(s, args[3], args[0], args[1],
+ args[2], const_args[2]);
+ break;
+
case INDEX_op_qemu_ld64:
tcg_out_qemu_ld(s, args, 3);
break;
@@ -1269,6 +1409,10 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
tcg_out_arithc(s, args[0], args[1], args[2], const_args[2], c);
break;
+ gen_arith1:
+ tcg_out_arithc(s, args[0], TCG_REG_G0, args[1], const_args[1], c);
+ break;
+
default:
fprintf(stderr, "unknown opcode 0x%x\n", opc);
tcg_abort();
@@ -1301,16 +1445,24 @@ static const TCGTargetOpDef sparc_op_defs[] = {
{ INDEX_op_remu_i32, { "r", "r", "rJ" } },
{ INDEX_op_sub_i32, { "r", "r", "rJ" } },
{ INDEX_op_and_i32, { "r", "r", "rJ" } },
+ { INDEX_op_andc_i32, { "r", "r", "rJ" } },
{ INDEX_op_or_i32, { "r", "r", "rJ" } },
+ { INDEX_op_orc_i32, { "r", "r", "rJ" } },
{ INDEX_op_xor_i32, { "r", "r", "rJ" } },
{ INDEX_op_shl_i32, { "r", "r", "rJ" } },
{ INDEX_op_shr_i32, { "r", "r", "rJ" } },
{ INDEX_op_sar_i32, { "r", "r", "rJ" } },
+ { INDEX_op_neg_i32, { "r", "rJ" } },
+ { INDEX_op_not_i32, { "r", "rJ" } },
+
{ INDEX_op_brcond_i32, { "r", "rJ" } },
+ { INDEX_op_setcond_i32, { "r", "r", "rJ" } },
+
#if TCG_TARGET_REG_BITS == 32
{ INDEX_op_brcond2_i32, { "r", "r", "rJ", "rJ" } },
+ { INDEX_op_setcond2_i32, { "r", "r", "r", "rJ", "rJ" } },
{ INDEX_op_add2_i32, { "r", "r", "r", "r", "rJ", "rJ" } },
{ INDEX_op_sub2_i32, { "r", "r", "r", "r", "rJ", "rJ" } },
{ INDEX_op_mulu2_i32, { "r", "r", "r", "rJ" } },
@@ -1321,7 +1473,9 @@ static const TCGTargetOpDef sparc_op_defs[] = {
{ INDEX_op_qemu_ld16u, { "r", "L" } },
{ INDEX_op_qemu_ld16s, { "r", "L" } },
{ INDEX_op_qemu_ld32u, { "r", "L" } },
+#if TCG_TARGET_REG_BITS == 64
{ INDEX_op_qemu_ld32s, { "r", "L" } },
+#endif
{ INDEX_op_qemu_st8, { "L", "L" } },
{ INDEX_op_qemu_st16, { "L", "L" } },
@@ -1352,16 +1506,23 @@ static const TCGTargetOpDef sparc_op_defs[] = {
{ INDEX_op_remu_i64, { "r", "r", "rJ" } },
{ INDEX_op_sub_i64, { "r", "r", "rJ" } },
{ INDEX_op_and_i64, { "r", "r", "rJ" } },
+ { INDEX_op_andc_i64, { "r", "r", "rJ" } },
{ INDEX_op_or_i64, { "r", "r", "rJ" } },
+ { INDEX_op_orc_i64, { "r", "r", "rJ" } },
{ INDEX_op_xor_i64, { "r", "r", "rJ" } },
{ INDEX_op_shl_i64, { "r", "r", "rJ" } },
{ INDEX_op_shr_i64, { "r", "r", "rJ" } },
{ INDEX_op_sar_i64, { "r", "r", "rJ" } },
+
+ { INDEX_op_neg_i64, { "r", "rJ" } },
+ { INDEX_op_not_i64, { "r", "rJ" } },
+
{ INDEX_op_ext32s_i64, { "r", "ri" } },
{ INDEX_op_ext32u_i64, { "r", "ri" } },
{ INDEX_op_brcond_i64, { "r", "rJ" } },
+ { INDEX_op_setcond_i64, { "r", "r", "rJ" } },
#endif
{ -1 },
};
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
index d27ed5a12c..dbc574d568 100644
--- a/tcg/sparc/tcg-target.h
+++ b/tcg/sparc/tcg-target.h
@@ -89,19 +89,36 @@ enum {
/* optional instructions */
#define TCG_TARGET_HAS_div_i32
-#define TCG_TARGET_HAS_div_i64
+// #define TCG_TARGET_HAS_rot_i32
+// #define TCG_TARGET_HAS_ext8s_i32
+// #define TCG_TARGET_HAS_ext16s_i32
+// #define TCG_TARGET_HAS_ext8u_i32
+// #define TCG_TARGET_HAS_ext16u_i32
+// #define TCG_TARGET_HAS_bswap16_i32
+// #define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_neg_i32
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_andc_i32
+#define TCG_TARGET_HAS_orc_i32
#if TCG_TARGET_REG_BITS == 64
+#define TCG_TARGET_HAS_div_i64
+// #define TCG_TARGET_HAS_rot_i64
+// #define TCG_TARGET_HAS_ext8s_i64
+// #define TCG_TARGET_HAS_ext16s_i64
#define TCG_TARGET_HAS_ext32s_i64
+// #define TCG_TARGET_HAS_ext8u_i64
+// #define TCG_TARGET_HAS_ext16u_i64
#define TCG_TARGET_HAS_ext32u_i64
+// #define TCG_TARGET_HAS_bswap16_i64
+// #define TCG_TARGET_HAS_bswap32_i64
+// #define TCG_TARGET_HAS_bswap64_i64
+#define TCG_TARGET_HAS_neg_i64
+#define TCG_TARGET_HAS_not_i64
+#define TCG_TARGET_HAS_andc_i64
+#define TCG_TARGET_HAS_orc_i64
#endif
-//#define TCG_TARGET_HAS_bswap32_i32
-//#define TCG_TARGET_HAS_bswap64_i64
-//#define TCG_TARGET_HAS_neg_i32
-//#define TCG_TARGET_HAS_neg_i64
-
-
/* Note: must be synced with dyngen-exec.h and Makefile.target */
#ifdef CONFIG_SOLARIS
#define TCG_AREG0 TCG_REG_G2
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index 13eaa5a9e8..6ae1760298 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -1650,20 +1650,31 @@ static inline void tcg_gen_concat32_i64(TCGv_i64 dest, TCGv_i64 low, TCGv_i64 hi
static inline void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
{
+#ifdef TCG_TARGET_HAS_andc_i32
+ tcg_gen_op3_i32(INDEX_op_andc_i32, ret, arg1, arg2);
+#else
TCGv_i32 t0;
t0 = tcg_temp_new_i32();
tcg_gen_not_i32(t0, arg2);
tcg_gen_and_i32(ret, arg1, t0);
tcg_temp_free_i32(t0);
+#endif
}
static inline void tcg_gen_andc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
{
+#ifdef TCG_TARGET_HAS_andc_i64
+ tcg_gen_op3_i64(INDEX_op_andc_i64, ret, arg1, arg2);
+#elif defined(TCG_TARGET_HAS_andc_i32) && TCG_TARGET_REG_BITS == 32
+ tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+ tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+#else
TCGv_i64 t0;
t0 = tcg_temp_new_i64();
tcg_gen_not_i64(t0, arg2);
tcg_gen_and_i64(ret, arg1, t0);
tcg_temp_free_i64(t0);
+#endif
}
static inline void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
@@ -1704,20 +1715,31 @@ static inline void tcg_gen_nor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
static inline void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
{
+#ifdef TCG_TARGET_HAS_orc_i32
+ tcg_gen_op3_i32(INDEX_op_orc_i32, ret, arg1, arg2);
+#else
TCGv_i32 t0;
t0 = tcg_temp_new_i32();
tcg_gen_not_i32(t0, arg2);
tcg_gen_or_i32(ret, arg1, t0);
tcg_temp_free_i32(t0);
+#endif
}
static inline void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
{
+#ifdef TCG_TARGET_HAS_orc_i64
+ tcg_gen_op3_i64(INDEX_op_orc_i64, ret, arg1, arg2);
+#elif defined(TCG_TARGET_HAS_orc_i32) && TCG_TARGET_REG_BITS == 32
+ tcg_gen_orc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
+ tcg_gen_orc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
+#else
TCGv_i64 t0;
t0 = tcg_temp_new_i64();
tcg_gen_not_i64(t0, arg2);
tcg_gen_or_i64(ret, arg1, t0);
tcg_temp_free_i64(t0);
+#endif
}
static inline void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h
index 89db3b49bf..01fea1e50d 100644
--- a/tcg/tcg-opc.h
+++ b/tcg/tcg-opc.h
@@ -109,6 +109,12 @@ DEF2(not_i32, 1, 1, 0, 0)
#ifdef TCG_TARGET_HAS_neg_i32
DEF2(neg_i32, 1, 1, 0, 0)
#endif
+#ifdef TCG_TARGET_HAS_andc_i32
+DEF2(andc_i32, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_orc_i32
+DEF2(orc_i32, 1, 2, 0, 0)
+#endif
#if TCG_TARGET_REG_BITS == 64
DEF2(mov_i64, 1, 1, 0, 0)
@@ -185,6 +191,12 @@ DEF2(not_i64, 1, 1, 0, 0)
#ifdef TCG_TARGET_HAS_neg_i64
DEF2(neg_i64, 1, 1, 0, 0)
#endif
+#ifdef TCG_TARGET_HAS_andc_i64
+DEF2(andc_i64, 1, 2, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_orc_i64
+DEF2(orc_i64, 1, 2, 0, 0)
+#endif
#endif
/* QEMU specific */
@@ -224,11 +236,6 @@ DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
DEF2(qemu_ld32u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#endif
#if TARGET_LONG_BITS == 32
-DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-#else
-DEF2(qemu_ld32s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-#endif
-#if TARGET_LONG_BITS == 32
DEF2(qemu_ld64, 2, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#else
DEF2(qemu_ld64, 2, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 9949814f25..e6a1caf795 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -981,9 +981,16 @@ void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
op = tdefs->op;
assert(op >= 0 && op < NB_OPS);
def = &tcg_op_defs[op];
+#if defined(CONFIG_DEBUG_TCG)
+ /* Duplicate entry in op definitions? */
+ assert(!def->used);
+ def->used = 1;
+#endif
nb_args = def->nb_iargs + def->nb_oargs;
for(i = 0; i < nb_args; i++) {
ct_str = tdefs->args_ct_str[i];
+ /* Incomplete TCGTargetOpDef entry? */
+ assert(ct_str != NULL);
tcg_regset_clear(def->args_ct[i].u.regs);
def->args_ct[i].ct = 0;
if (ct_str[0] >= '0' && ct_str[0] <= '9') {
@@ -1018,6 +1025,9 @@ void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
}
}
+ /* TCGTargetOpDef entry with too much information? */
+ assert(i == TCG_MAX_OP_ARGS || tdefs->args_ct_str[i] == NULL);
+
/* sort the constraints (XXX: this is just an heuristic) */
sort_constraints(def, 0, def->nb_oargs);
sort_constraints(def, def->nb_oargs, def->nb_iargs);
@@ -1035,6 +1045,17 @@ void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs)
tdefs++;
}
+#if defined(CONFIG_DEBUG_TCG)
+ for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) {
+ if (op < INDEX_op_call || op == INDEX_op_debug_insn_start) {
+ /* Wrong entry in op definitions? */
+ assert(!tcg_op_defs[op].used);
+ } else {
+ /* Missing entry in op definitions? */
+ assert(tcg_op_defs[op].used);
+ }
+ }
+#endif
}
#ifdef USE_LIVENESS_ANALYSIS
diff --git a/tcg/tcg.h b/tcg/tcg.h
index b218abeaf2..cf3a50869f 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -205,11 +205,19 @@ typedef enum {
TCG_COND_GTU,
} TCGCond;
+/* Invert the sense of the comparison. */
static inline TCGCond tcg_invert_cond(TCGCond c)
{
return (TCGCond)(c ^ 1);
}
+/* Swap the operands in a comparison. */
+static inline TCGCond tcg_swap_cond(TCGCond c)
+{
+ int mask = (c < TCG_COND_LT ? 0 : c < TCG_COND_LTU ? 7 : 15);
+ return (TCGCond)(c ^ mask);
+}
+
static inline TCGCond tcg_unsigned_cond(TCGCond c)
{
return (c >= TCG_COND_LT && c <= TCG_COND_GT ? c + 4 : c);
@@ -404,6 +412,9 @@ typedef struct TCGOpDef {
uint16_t copy_size;
TCGArgConstraint *args_ct;
int *sorted_args;
+#if defined(CONFIG_DEBUG_TCG)
+ int used;
+#endif
} TCGOpDef;
typedef struct TCGTargetOpDef {
diff --git a/tcg/x86_64/tcg-target.h b/tcg/x86_64/tcg-target.h
index 3ca392ff21..765f0b4d81 100644
--- a/tcg/x86_64/tcg-target.h
+++ b/tcg/x86_64/tcg-target.h
@@ -75,10 +75,14 @@ enum {
#define TCG_TARGET_HAS_ext8u_i64
#define TCG_TARGET_HAS_ext16u_i64
#define TCG_TARGET_HAS_ext32u_i64
-
#define TCG_TARGET_HAS_rot_i32
#define TCG_TARGET_HAS_rot_i64
+// #define TCG_TARGET_HAS_andc_i32
+// #define TCG_TARGET_HAS_andc_i64
+// #define TCG_TARGET_HAS_orc_i32
+// #define TCG_TARGET_HAS_orc_i64
+
#define TCG_TARGET_HAS_GUEST_BASE
/* Note: must be synced with dyngen-exec.h */
diff --git a/vl.c b/vl.c
index dc05da36ca..db7a178f88 100644
--- a/vl.c
+++ b/vl.c
@@ -182,7 +182,6 @@ const char *bios_name = NULL;
struct drivelist drives = QTAILQ_HEAD_INITIALIZER(drives);
struct driveoptlist driveopts = QTAILQ_HEAD_INITIALIZER(driveopts);
enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
-static DisplayState *display_state;
DisplayType display_type = DT_DEFAULT;
const char* keyboard_layout = NULL;
ram_addr_t ram_size;
@@ -2583,46 +2582,6 @@ void pcmcia_info(Monitor *mon)
}
/***********************************************************/
-/* register display */
-
-struct DisplayAllocator default_allocator = {
- defaultallocator_create_displaysurface,
- defaultallocator_resize_displaysurface,
- defaultallocator_free_displaysurface
-};
-
-void register_displaystate(DisplayState *ds)
-{
- DisplayState **s;
- s = &display_state;
- while (*s != NULL)
- s = &(*s)->next;
- ds->next = NULL;
- *s = ds;
-}
-
-DisplayState *get_displaystate(void)
-{
- return display_state;
-}
-
-DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
-{
- if(ds->allocator == &default_allocator) ds->allocator = da;
- return ds->allocator;
-}
-
-/* dumb display */
-
-static void dumb_display_init(void)
-{
- DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
- ds->allocator = &default_allocator;
- ds->surface = qemu_create_displaysurface(ds, 640, 480);
- register_displaystate(ds);
-}
-
-/***********************************************************/
/* I/O handling */
typedef struct IOHandlerRecord {
@@ -4958,6 +4917,9 @@ int main(int argc, char **argv, char **envp)
fclose(fp);
}
}
+#if defined(cpudef_setup)
+ cpudef_setup(); /* parse cpu definitions in target config file */
+#endif
/* second pass of option parsing */
optind = 1;
@@ -4991,8 +4953,10 @@ int main(int argc, char **argv, char **envp)
/* hw initialization will check this */
if (*optarg == '?') {
/* XXX: implement xxx_cpu_list for targets that still miss it */
-#if defined(cpu_list)
- cpu_list(stdout, &fprintf);
+#if defined(cpu_list_id)
+ cpu_list_id(stdout, &fprintf, optarg);
+#elif defined(cpu_list)
+ cpu_list(stdout, &fprintf); /* deprecated */
#endif
exit(0);
} else {
@@ -5978,10 +5942,10 @@ int main(int argc, char **argv, char **envp)
if (qemu_opts_foreach(&qemu_device_opts, device_init_func, NULL, 1) != 0)
exit(1);
- if (!display_state)
- dumb_display_init();
+ net_check_clients();
+
/* just use the first displaystate for the moment */
- ds = display_state;
+ ds = get_displaystate();
if (display_type == DT_DEFAULT) {
#if defined(CONFIG_SDL) || defined(CONFIG_COCOA)
@@ -6039,7 +6003,7 @@ int main(int argc, char **argv, char **envp)
qemu_mod_timer(nographic_timer, qemu_get_clock(rt_clock));
}
- text_consoles_set_display(display_state);
+ text_consoles_set_display(ds);
if (qemu_opts_foreach(&qemu_mon_opts, mon_init_func, NULL, 1) != 0)
exit(1);