diff options
95 files changed, 2382 insertions, 839 deletions
@@ -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 @@ -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 */ @@ -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) { @@ -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 @@ -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); -} @@ -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; @@ -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); } @@ -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); @@ -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")); } @@ -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); @@ -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); } @@ -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); @@ -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; @@ -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); @@ -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; } @@ -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; } @@ -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; } @@ -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 Binary files differindex 1bcfed3022..b82ce2c371 100644 --- a/pc-bios/openbios-ppc +++ b/pc-bios/openbios-ppc diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 Binary files differindex aafb04146a..4f2f45f2c4 100644 --- a/pc-bios/openbios-sparc32 +++ b/pc-bios/openbios-sparc32 diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 Binary files differindex 437d246351..632f9380da 100644 --- a/pc-bios/openbios-sparc64 +++ b/pc-bios/openbios-sparc64 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 @@ -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)" + @@ -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) @@ -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 @@ -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 */ @@ -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); |