diff options
author | Marcelo Tosatti <mtosatti@redhat.com> | 2010-03-04 16:41:35 -0300 |
---|---|---|
committer | Marcelo Tosatti <mtosatti@redhat.com> | 2010-03-04 16:41:35 -0300 |
commit | e19ec919797ecf047ec805662850311b6a5298ee (patch) | |
tree | e4fb3679ef2fd8f6e85141d60c050e4f960881f0 | |
parent | ca8773d10fa15cd00a754faa7f26091b81587df3 (diff) | |
parent | 6049f4f831c6f409031dfa09282b38d0cbaecad8 (diff) |
Merge commit '6049f4f831c6f409031dfa09282b38d0cbaecad8' into upstream-merge
* commit '6049f4f831c6f409031dfa09282b38d0cbaecad8': (32 commits)
alpha-linux-user: Implement signals.
target-alpha: Implement IEEE FP qualifiers.
target-ppc: don't print invalid opcode messages on the console
Revert "target-ppc: stop translation after a trap instruction"
audio/alsa: Handle SND_PCM_STATE_SETUP in alsa_poll_handler
audio/alsa: Spelling typo (paramters)
target-ppc: stop translation after a trap instruction
qemu-char.c: drop debug printfs from qemu_chr_parse_compat
powerpc/e500: adjust fdt and ramdisk loading addr
powerpc: fix compilation with CONFIG_FDT undefined
powerpc/booke: move fdt loading to rom infrastructure
target-ppc: add synchronize register for booke init
target-sh4: Fix gdb read/write register
target-ppc: fix SPE evsplat* instructions
target-ppc: fix SPE evcmp* instructions
arm host: Fix linker warning (m68k targets)
Fix 'make install' from non-srcdir build
Fix to 'gdb detach' stub
Fix qemu -net user,hostfwd= example
tcg/ppc: Fix right rotation
...
Conflicts:
Makefile.target
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | Makefile.target | 3 | ||||
-rw-r--r-- | arm-dis.c | 8 | ||||
-rw-r--r-- | audio/alsaaudio.c | 6 | ||||
-rw-r--r-- | default-configs/arm-softmmu.mak | 4 | ||||
-rw-r--r-- | fpu/softfloat.h | 1 | ||||
-rw-r--r-- | gdbstub.c | 116 | ||||
-rw-r--r-- | hw/alpha_palcode.c | 81 | ||||
-rw-r--r-- | hw/ppc440_bamboo.c | 19 | ||||
-rw-r--r-- | hw/ppce500_mpc8544ds.c | 33 | ||||
-rw-r--r-- | hw/usb-bus.c | 3 | ||||
-rw-r--r-- | hw/usb-msd.c | 3 | ||||
-rw-r--r-- | hw/usb-net.c | 3 | ||||
-rw-r--r-- | hw/usb-serial.c | 3 | ||||
-rw-r--r-- | kvm.h | 2 | ||||
-rw-r--r-- | linux-user/alpha/target_signal.h | 27 | ||||
-rw-r--r-- | linux-user/main.c | 141 | ||||
-rw-r--r-- | linux-user/signal.c | 267 | ||||
-rw-r--r-- | linux-user/syscall.c | 61 | ||||
-rw-r--r-- | linux-user/syscall_defs.h | 23 | ||||
-rw-r--r-- | qemu-char.c | 3 | ||||
-rw-r--r-- | qemu-malloc.c | 8 | ||||
-rw-r--r-- | qemu-options.hx | 2 | ||||
-rw-r--r-- | target-alpha/cpu.h | 44 | ||||
-rw-r--r-- | target-alpha/helper.c | 161 | ||||
-rw-r--r-- | target-alpha/helper.h | 21 | ||||
-rw-r--r-- | target-alpha/op_helper.c | 275 | ||||
-rw-r--r-- | target-alpha/translate.c | 569 | ||||
-rw-r--r-- | target-i386/helper.c | 11 | ||||
-rw-r--r-- | target-ppc/cpu.h | 8 | ||||
-rw-r--r-- | target-ppc/translate.c | 15 | ||||
-rw-r--r-- | target-sparc/translate.c | 2 | ||||
-rw-r--r-- | tcg/ppc/tcg-target.c | 3 |
33 files changed, 1495 insertions, 433 deletions
@@ -207,7 +207,7 @@ endif install-sysconfig: $(INSTALL_DIR) "$(sysconfdir)/qemu" - $(INSTALL_DATA) sysconfigs/target/target-x86_64.conf "$(sysconfdir)/qemu" + $(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(sysconfdir)/qemu" install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig $(INSTALL_DIR) "$(DESTDIR)$(bindir)" diff --git a/Makefile.target b/Makefile.target index 82caf20b4..89071ec92 100644 --- a/Makefile.target +++ b/Makefile.target @@ -59,7 +59,6 @@ libobj-$(CONFIG_KVM) += kvm-tpr-opt.o libobj-$(CONFIG_KVM) += qemu-kvm-helper.o libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o -libobj-$(TARGET_ALPHA) += alpha_palcode.o # NOTE: the disassembler code is only needed for debugging libobj-y += disas.o @@ -339,6 +338,8 @@ obj-m68k-y += m68k-semi.o dummy_m68k.o obj-s390x-y = s390-virtio-bus.o s390-virtio.o +obj-alpha-y = alpha_palcode.o + ifeq ($(TARGET_ARCH), ia64) firmware.o: firmware.c $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< @@ -60,10 +60,8 @@ #define FPU_VFP_EXT_V3 0 #define FPU_NEON_EXT_V1 0 -int floatformat_ieee_single_little; /* Assume host uses ieee float. */ -static void floatformat_to_double (int *ignored, unsigned char *data, - double *dest) +static void floatformat_to_double (unsigned char *data, double *dest) { union { uint32_t i; @@ -2543,9 +2541,7 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb) valbytes[2] = (value >> 16) & 0xff; valbytes[3] = (value >> 24) & 0xff; - floatformat_to_double - (&floatformat_ieee_single_little, valbytes, - &fvalue); + floatformat_to_double (valbytes, &fvalue); func (stream, "#%.7g\t; 0x%.8lx", fvalue, value); diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 7698d1010..88344ff03 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -213,6 +213,10 @@ static void alsa_poll_handler (void *opaque) state = snd_pcm_state (hlp->handle); switch (state) { + case SND_PCM_STATE_SETUP: + alsa_recover (hlp->handle); + break; + case SND_PCM_STATE_XRUN: alsa_recover (hlp->handle); break; @@ -665,7 +669,7 @@ static int alsa_open (int in, struct alsa_params_req *req, (obt->fmt != req->fmt || obt->nchannels != req->nchannels || obt->freq != req->freq)) { - dolog ("Audio paramters for %s\n", typ); + dolog ("Audio parameters for %s\n", typ); alsa_dump_info (req, obt); } diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index c1b7496c0..4c0fe2261 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -14,8 +14,8 @@ CONFIG_TSC2005=y CONFIG_LM832X=y CONFIG_TMP105=y CONFIG_STELLARIS_INPUT=y -CONFIG_SD0303=y -CONFIG_SD0323=y +CONFIG_SSD0303=y +CONFIG_SSD0323=y CONFIG_ADS7846=y CONFIG_MAX111X=y CONFIG_SSI=y diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 9d8269411..636591b04 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -187,7 +187,6 @@ typedef struct float_status { signed char float_detect_tininess; signed char float_rounding_mode; signed char float_exception_flags; - signed char float_exception_mask; #ifdef FLOATX80 signed char floatx80_rounding_precision; #endif @@ -1149,7 +1149,7 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) GET_REGL(env->gregs[n]); } } else if (n < 16) { - GET_REGL(env->gregs[n - 8]); + GET_REGL(env->gregs[n]); } else if (n >= 25 && n < 41) { GET_REGL(env->fregs[(n - 25) + ((env->fpscr & FPSCR_FR) ? 16 : 0)]); } else if (n >= 43 && n < 51) { @@ -1188,10 +1188,11 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) } return 4; } else if (n < 16) { - env->gregs[n - 8] = tmp; + env->gregs[n] = tmp; return 4; } else if (n >= 25 && n < 41) { env->fregs[(n - 25) + ((env->fpscr & FPSCR_FR) ? 16 : 0)] = tmp; + return 4; } else if (n >= 43 && n < 51) { env->gregs[n - 43] = tmp; return 4; @@ -1200,17 +1201,17 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) return 4; } switch (n) { - case 16: env->pc = tmp; - case 17: env->pr = tmp; - case 18: env->gbr = tmp; - case 19: env->vbr = tmp; - case 20: env->mach = tmp; - case 21: env->macl = tmp; - case 22: env->sr = tmp; - case 23: env->fpul = tmp; - case 24: env->fpscr = tmp; - case 41: env->ssr = tmp; - case 42: env->spc = tmp; + case 16: env->pc = tmp; break; + case 17: env->pr = tmp; break; + case 18: env->gbr = tmp; break; + case 19: env->vbr = tmp; break; + case 20: env->mach = tmp; break; + case 21: env->macl = tmp; break; + case 22: env->sr = tmp; break; + case 23: env->fpul = tmp; break; + case 24: env->fpscr = tmp; break; + case 41: env->ssr = tmp; break; + case 42: env->spc = tmp; break; default: return 0; } @@ -1344,52 +1345,72 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) } #elif defined (TARGET_ALPHA) -#define NUM_CORE_REGS 65 +#define NUM_CORE_REGS 67 static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) { - if (n < 31) { - GET_REGL(env->ir[n]); - } - else if (n == 31) { - GET_REGL(0); - } - else if (n<63) { - uint64_t val; + uint64_t val; + CPU_DoubleU d; - val = *((uint64_t *)&env->fir[n-32]); - GET_REGL(val); - } - else if (n==63) { - GET_REGL(env->fpcr); - } - else if (n==64) { - GET_REGL(env->pc); - } - else { - GET_REGL(0); + switch (n) { + case 0 ... 30: + val = env->ir[n]; + break; + case 32 ... 62: + d.d = env->fir[n - 32]; + val = d.ll; + break; + case 63: + val = cpu_alpha_load_fpcr(env); + break; + case 64: + val = env->pc; + break; + case 66: + val = env->unique; + break; + case 31: + case 65: + /* 31 really is the zero register; 65 is unassigned in the + gdb protocol, but is still required to occupy 8 bytes. */ + val = 0; + break; + default: + return 0; } - - return 0; + GET_REGL(val); } static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) { - target_ulong tmp; - tmp = ldtul_p(mem_buf); + target_ulong tmp = ldtul_p(mem_buf); + CPU_DoubleU d; - if (n < 31) { + switch (n) { + case 0 ... 30: env->ir[n] = tmp; + break; + case 32 ... 62: + d.ll = tmp; + env->fir[n - 32] = d.d; + break; + case 63: + cpu_alpha_store_fpcr(env, tmp); + break; + case 64: + env->pc = tmp; + break; + case 66: + env->unique = tmp; + break; + case 31: + case 65: + /* 31 really is the zero register; 65 is unassigned in the + gdb protocol, but is still required to occupy 8 bytes. */ + break; + default: + return 0; } - - if (n > 31 && n < 63) { - env->fir[n - 32] = ldfl_p(mem_buf); - } - - if (n == 64 ) { - env->pc=tmp; - } - return 8; } #elif defined (TARGET_S390X) @@ -1849,6 +1870,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) case 'D': /* Detach packet */ gdb_breakpoint_remove_all(); + gdb_syscall_mode = GDB_SYS_DISABLED; gdb_continue(s); put_packet(s, "OK"); break; diff --git a/hw/alpha_palcode.c b/hw/alpha_palcode.c index 843bd1491..c1220ad93 100644 --- a/hw/alpha_palcode.c +++ b/hw/alpha_palcode.c @@ -21,11 +21,9 @@ #include <stdlib.h> #include <stdio.h> -#include "qemu.h" #include "cpu.h" #include "exec-all.h" -#if !defined (CONFIG_USER_ONLY) /* Shared handlers */ static void pal_reset (CPUState *env); /* Console handlers */ @@ -997,12 +995,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, uint64_t physical, page_size, end; int prot, zbits, ret; -#if defined(CONFIG_USER_ONLY) - ret = 2; -#else - ret = virtual_to_physical(env, &physical, &zbits, &prot, - address, mmu_idx, rw); -#endif + ret = virtual_to_physical(env, &physical, &zbits, &prot, + address, mmu_idx, rw); + switch (ret) { case 0: /* No fault */ @@ -1050,73 +1045,3 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, return ret; } #endif - -#else /* !defined (CONFIG_USER_ONLY) */ -void pal_init (CPUState *env) -{ -} - -void call_pal (CPUState *env, int palcode) -{ - target_long ret; - - switch (palcode) { - case 0x80: - /* BPT */ - qemu_log("BPT\n"); - /* FIXME: Sends SIGTRAP, si_code=TRAP_BRKPT. */ - exit(1); - case 0x81: - /* BUGCHK */ - qemu_log("BUGCHK\n"); - /* FIXME: Sends SIGTRAP, si_code=SI_FAULT. */ - exit(1); - case 0x83: - /* CALLSYS */ - qemu_log("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]); - ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1], - env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4], - env->ir[IR_A5]); - if (ret >= 0) { - env->ir[IR_A3] = 0; - env->ir[IR_V0] = ret; - } else { - env->ir[IR_A3] = 1; - env->ir[IR_V0] = -ret; - } - break; - case 0x86: - /* IMB */ - qemu_log("IMB\n"); - /* ??? We can probably elide the code using page_unprotect that is - checking for self-modifying code. Instead we could simply call - tb_flush here. Until we work out the changes required to turn - off the extra write protection, this can be a no-op. */ - break; - case 0x9E: - /* RDUNIQUE */ - qemu_log("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique); - /* Handled in the translator for usermode. */ - abort(); - case 0x9F: - /* WRUNIQUE */ - qemu_log("WRUNIQUE: " TARGET_FMT_lx "\n", env->ir[IR_A0]); - /* Handled in the translator for usermode. */ - abort(); - case 0xAA: - /* GENTRAP */ - qemu_log("GENTRAP: " TARGET_FMT_lx "\n", env->ir[IR_A0]); - /* FIXME: This is supposed to send a signal: - SIGFPE: - GEN_INTOVF, GEN_INTDIV, GEN_FLTOVF, GEN_FLTDIV, - GEN_FLTUND, GEN_FLTINV, GEN_FLTINE, GEN_ROPRAND - SIGTRAP: - others - with various settings of si_code. */ - exit(1); - default: - qemu_log("%s: unhandled palcode %02x\n", __func__, palcode); - exit(1); - } -} -#endif diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index c94c961be..04adcf290 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -28,18 +28,18 @@ #define BINARY_DEVICE_TREE_FILE "bamboo.dtb" -static void *bamboo_load_device_tree(target_phys_addr_t addr, +static int bamboo_load_device_tree(target_phys_addr_t addr, uint32_t ramsize, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, const char *kernel_cmdline) { - void *fdt = NULL; + int ret = -1; #ifdef CONFIG_FDT uint32_t mem_reg_property[] = { 0, 0, ramsize }; char *filename; int fdt_size; - int ret; + void *fdt; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); if (!filename) { @@ -76,12 +76,13 @@ static void *bamboo_load_device_tree(target_phys_addr_t addr, if (kvm_enabled()) kvmppc_fdt_update(fdt); - cpu_physical_memory_write (addr, (void *)fdt, fdt_size); + ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); + qemu_free(fdt); out: #endif - return fdt; + return ret; } static void bamboo_init(ram_addr_t ram_size, @@ -102,7 +103,6 @@ static void bamboo_init(ram_addr_t ram_size, target_ulong initrd_base = 0; target_long initrd_size = 0; target_ulong dt_base = 0; - void *fdt; int i; /* Setup CPU. */ @@ -154,13 +154,14 @@ static void bamboo_init(ram_addr_t ram_size, else dt_base = kernel_size + loadaddr; - fdt = bamboo_load_device_tree(dt_base, ram_size, - initrd_base, initrd_size, kernel_cmdline); - if (fdt == NULL) { + if (bamboo_load_device_tree(dt_base, ram_size, + initrd_base, initrd_size, kernel_cmdline) < 0) { fprintf(stderr, "couldn't load device tree\n"); exit(1); } + cpu_synchronize_state(env); + /* Set initial guest state. */ env->gpr[1] = (16<<20) - 8; env->gpr[3] = dt_base; diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 45356ca02..72e663c95 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -35,8 +35,10 @@ #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" #define UIMAGE_LOAD_BASE 0 -#define DTB_LOAD_BASE 0x600000 -#define INITRD_LOAD_BASE 0x2000000 +#define DTC_LOAD_PAD 0x500000 +#define DTC_PAD_MASK 0xFFFFF +#define INITRD_LOAD_PAD 0x2000000 +#define INITRD_PAD_MASK 0xFFFFFF #define RAM_SIZES_ALIGN (64UL << 20) @@ -73,18 +75,18 @@ out: } #endif -static void *mpc8544_load_device_tree(target_phys_addr_t addr, +static int mpc8544_load_device_tree(target_phys_addr_t addr, uint32_t ramsize, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, const char *kernel_cmdline) { - void *fdt = NULL; + int ret = -1; #ifdef CONFIG_FDT uint32_t mem_reg_property[] = {0, ramsize}; char *filename; int fdt_size; - int ret; + void *fdt; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); if (!filename) { @@ -124,6 +126,7 @@ static void *mpc8544_load_device_tree(target_phys_addr_t addr, if ((dp = opendir("/proc/device-tree/cpus/")) == NULL) { printf("Can't open directory /proc/device-tree/cpus/\n"); + ret = -1; goto out; } @@ -137,6 +140,7 @@ static void *mpc8544_load_device_tree(target_phys_addr_t addr, closedir(dp); if (buf[0] == '\0') { printf("Unknow host!\n"); + ret = -1; goto out; } @@ -144,12 +148,13 @@ static void *mpc8544_load_device_tree(target_phys_addr_t addr, mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency"); } - cpu_physical_memory_write (addr, (void *)fdt, fdt_size); + ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); + qemu_free(fdt); out: #endif - return fdt; + return ret; } static void mpc8544ds_init(ram_addr_t ram_size, @@ -166,10 +171,9 @@ static void mpc8544ds_init(ram_addr_t ram_size, target_phys_addr_t entry=0; target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE; target_long kernel_size=0; - target_ulong dt_base=DTB_LOAD_BASE; - target_ulong initrd_base=INITRD_LOAD_BASE; + target_ulong dt_base = 0; + target_ulong initrd_base = 0; target_long initrd_size=0; - void *fdt; int i=0; unsigned int pci_irq_nrs[4] = {1, 2, 3, 4}; qemu_irq *irqs, *mpic, *pci_irqs; @@ -243,6 +247,7 @@ static void mpc8544ds_init(ram_addr_t ram_size, /* Load initrd. */ if (initrd_filename) { + initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; initrd_size = load_image_targphys(initrd_filename, initrd_base, ram_size - initrd_base); @@ -255,13 +260,15 @@ static void mpc8544ds_init(ram_addr_t ram_size, /* If we're loading a kernel directly, we must load the device tree too. */ if (kernel_filename) { - fdt = mpc8544_load_device_tree(dt_base, ram_size, - initrd_base, initrd_size, kernel_cmdline); - if (fdt == NULL) { + dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; + if (mpc8544_load_device_tree(dt_base, ram_size, + initrd_base, initrd_size, kernel_cmdline) < 0) { fprintf(stderr, "couldn't load device tree\n"); exit(1); } + cpu_synchronize_state(env); + /* Set initial guest state. */ env->gpr[1] = (16<<20) - 8; env->gpr[3] = dt_base; diff --git a/hw/usb-bus.c b/hw/usb-bus.c index 54027dfc4..7c823147a 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -102,6 +102,9 @@ USBDevice *usb_create(USBBus *bus, const char *name) USBDevice *usb_create_simple(USBBus *bus, const char *name) { USBDevice *dev = usb_create(bus, name); + if (!dev) { + hw_error("Failed to create USB device '%s'\n", name); + } qdev_init_nofail(&dev->qdev); return dev; } diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 36991f883..1a11bc557 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -592,6 +592,9 @@ static USBDevice *usb_msd_init(const char *filename) /* create guest device */ dev = usb_create(NULL /* FIXME */, "usb-storage"); + if (!dev) { + return NULL; + } qdev_prop_set_drive(&dev->qdev, "drive", dinfo); if (qdev_init(&dev->qdev) < 0) return NULL; diff --git a/hw/usb-net.c b/hw/usb-net.c index cfd2f62e0..6875f112f 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1491,6 +1491,9 @@ static USBDevice *usb_net_init(const char *cmdline) } dev = usb_create(NULL /* FIXME */, "usb-net"); + if (!dev) { + return NULL; + } qdev_set_nic_properties(&dev->qdev, &nd_table[idx]); qdev_init_nofail(&dev->qdev); return dev; diff --git a/hw/usb-serial.c b/hw/usb-serial.c index c3f340137..1410b11b2 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -594,6 +594,9 @@ static USBDevice *usb_serial_init(const char *filename) return NULL; dev = usb_create(NULL /* FIXME */, "usb-serial"); + if (!dev) { + return NULL; + } qdev_prop_set_chr(&dev->qdev, "chardev", cdrv); if (vendorid) qdev_prop_set_uint16(&dev->qdev, "vendorid", vendorid); @@ -59,7 +59,9 @@ int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr, target_ulong len, int type); void kvm_remove_all_breakpoints(CPUState *current_env); int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap); +#ifndef _WIN32 int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset); +#endif int kvm_pit_in_kernel(void); int kvm_irqchip_in_kernel(void); diff --git a/linux-user/alpha/target_signal.h b/linux-user/alpha/target_signal.h index 2382ffdb6..94f15f612 100644 --- a/linux-user/alpha/target_signal.h +++ b/linux-user/alpha/target_signal.h @@ -26,4 +26,31 @@ static inline abi_ulong get_sp_from_cpustate(CPUAlphaState *state) return state->ir[IR_SP]; } +/* From <asm/gentrap.h>. */ +#define TARGET_GEN_INTOVF -1 /* integer overflow */ +#define TARGET_GEN_INTDIV -2 /* integer division by zero */ +#define TARGET_GEN_FLTOVF -3 /* fp overflow */ +#define TARGET_GEN_FLTDIV -4 /* fp division by zero */ +#define TARGET_GEN_FLTUND -5 /* fp underflow */ +#define TARGET_GEN_FLTINV -6 /* invalid fp operand */ +#define TARGET_GEN_FLTINE -7 /* inexact fp operand */ +#define TARGET_GEN_DECOVF -8 /* decimal overflow (for COBOL??) */ +#define TARGET_GEN_DECDIV -9 /* decimal division by zero */ +#define TARGET_GEN_DECINV -10 /* invalid decimal operand */ +#define TARGET_GEN_ROPRAND -11 /* reserved operand */ +#define TARGET_GEN_ASSERTERR -12 /* assertion error */ +#define TARGET_GEN_NULPTRERR -13 /* null pointer error */ +#define TARGET_GEN_STKOVF -14 /* stack overflow */ +#define TARGET_GEN_STRLENERR -15 /* string length error */ +#define TARGET_GEN_SUBSTRERR -16 /* substring error */ +#define TARGET_GEN_RANGERR -17 /* range error */ +#define TARGET_GEN_SUBRNG -18 +#define TARGET_GEN_SUBRNG1 -19 +#define TARGET_GEN_SUBRNG2 -20 +#define TARGET_GEN_SUBRNG3 -21 +#define TARGET_GEN_SUBRNG4 -22 +#define TARGET_GEN_SUBRNG5 -23 +#define TARGET_GEN_SUBRNG6 -24 +#define TARGET_GEN_SUBRNG7 -25 + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/main.c b/linux-user/main.c index 1189dda60..eeae22e2b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2351,6 +2351,7 @@ void cpu_loop (CPUState *env) { int trapnr; target_siginfo_t info; + abi_long sysret; while (1) { trapnr = cpu_alpha_exec (env); @@ -2365,16 +2366,22 @@ void cpu_loop (CPUState *env) exit(1); break; case EXCP_ARITH: - fprintf(stderr, "Arithmetic trap.\n"); - exit(1); + info.si_signo = TARGET_SIGFPE; + info.si_errno = 0; + info.si_code = TARGET_FPE_FLTINV; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, &info); break; case EXCP_HW_INTERRUPT: fprintf(stderr, "External interrupt. Exit\n"); exit(1); break; case EXCP_DFAULT: - fprintf(stderr, "MMU data fault\n"); - exit(1); + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = 0; /* ??? SEGV_MAPERR vs SEGV_ACCERR. */ + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, &info); break; case EXCP_DTB_MISS_PAL: fprintf(stderr, "MMU data TLB miss in PALcode\n"); @@ -2393,36 +2400,116 @@ void cpu_loop (CPUState *env) exit(1); break; case EXCP_UNALIGN: - fprintf(stderr, "Unaligned access\n"); - exit(1); + info.si_signo = TARGET_SIGBUS; + info.si_errno = 0; + info.si_code = TARGET_BUS_ADRALN; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, &info); break; case EXCP_OPCDEC: - fprintf(stderr, "Invalid instruction\n"); - exit(1); + do_sigill: + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPC; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, &info); break; case EXCP_FEN: - fprintf(stderr, "Floating-point not allowed\n"); - exit(1); + /* No-op. Linux simply re-enables the FPU. */ break; case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1): - call_pal(env, (trapnr >> 6) | 0x80); + switch ((trapnr >> 6) | 0x80) { + case 0x80: + /* BPT */ + info.si_signo = TARGET_SIGTRAP; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, &info); + break; + case 0x81: + /* BUGCHK */ + info.si_signo = TARGET_SIGTRAP; + info.si_errno = 0; + info.si_code = 0; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, &info); + break; + case 0x83: + /* CALLSYS */ + trapnr = env->ir[IR_V0]; + sysret = do_syscall(env, trapnr, + env->ir[IR_A0], env->ir[IR_A1], + env->ir[IR_A2], env->ir[IR_A3], + env->ir[IR_A4], env->ir[IR_A5]); + if (trapnr != TARGET_NR_sigreturn + && trapnr != TARGET_NR_rt_sigreturn) { + env->ir[IR_V0] = (sysret < 0 ? -sysret : sysret); + env->ir[IR_A3] = (sysret < 0); + } + break; + case 0x86: + /* IMB */ + /* ??? We can probably elide the code using page_unprotect + that is checking for self-modifying code. Instead we + could simply call tb_flush here. Until we work out the + changes required to turn off the extra write protection, + this can be a no-op. */ + break; + case 0x9E: + /* RDUNIQUE */ + /* Handled in the translator for usermode. */ + abort(); + case 0x9F: + /* WRUNIQUE */ + /* Handled in the translator for usermode. */ + abort(); + case 0xAA: + /* GENTRAP */ + info.si_signo = TARGET_SIGFPE; + switch (env->ir[IR_A0]) { + case TARGET_GEN_INTOVF: + info.si_code = TARGET_FPE_INTOVF; + break; + case TARGET_GEN_INTDIV: + info.si_code = TARGET_FPE_INTDIV; + break; + case TARGET_GEN_FLTOVF: + info.si_code = TARGET_FPE_FLTOVF; + break; + case TARGET_GEN_FLTUND: + info.si_code = TARGET_FPE_FLTUND; + break; + case TARGET_GEN_FLTINV: + info.si_code = TARGET_FPE_FLTINV; + break; + case TARGET_GEN_FLTINE: + info.si_code = TARGET_FPE_FLTRES; + break; + case TARGET_GEN_ROPRAND: + info.si_code = 0; + break; + default: + info.si_signo = TARGET_SIGTRAP; + info.si_code = 0; + break; + } + info.si_errno = 0; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, &info); + break; + default: + goto do_sigill; + } break; case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1): - fprintf(stderr, "Privileged call to PALcode\n"); - exit(1); - break; + goto do_sigill; case EXCP_DEBUG: - { - int sig; - - sig = gdb_handlesig (env, TARGET_SIGTRAP); - if (sig) - { - info.si_signo = sig; - info.si_errno = 0; - info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); - } + info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP); + if (info.si_signo) { + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(env, info.si_signo, &info); } break; default: @@ -3054,10 +3141,8 @@ int main(int argc, char **argv, char **envp) for(i = 0; i < 28; i++) { env->ir[i] = ((abi_ulong *)regs)[i]; } - env->ipr[IPR_USP] = regs->usp; - env->ir[30] = regs->usp; + env->ir[IR_SP] = regs->usp; env->pc = regs->pc; - env->unique = regs->unique; } #elif defined(TARGET_CRIS) { diff --git a/linux-user/signal.c b/linux-user/signal.c index b0faf2eb8..a560a5ce0 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -4410,6 +4410,273 @@ badframe: return 0; } +#elif defined(TARGET_ALPHA) + +struct target_sigcontext { + abi_long sc_onstack; + abi_long sc_mask; + abi_long sc_pc; + abi_long sc_ps; + abi_long sc_regs[32]; + abi_long sc_ownedfp; + abi_long sc_fpregs[32]; + abi_ulong sc_fpcr; + abi_ulong sc_fp_control; + abi_ulong sc_reserved1; + abi_ulong sc_reserved2; + abi_ulong sc_ssize; + abi_ulong sc_sbase; + abi_ulong sc_traparg_a0; + abi_ulong sc_traparg_a1; + abi_ulong sc_traparg_a2; + abi_ulong sc_fp_trap_pc; + abi_ulong sc_fp_trigger_sum; + abi_ulong sc_fp_trigger_inst; +}; + +struct target_ucontext { + abi_ulong uc_flags; + abi_ulong uc_link; + abi_ulong uc_osf_sigmask; + target_stack_t uc_stack; + struct target_sigcontext uc_mcontext; + target_sigset_t uc_sigmask; +}; + +struct target_sigframe { + struct target_sigcontext sc; + unsigned int retcode[3]; +}; + +struct target_rt_sigframe { + target_siginfo_t info; + struct target_ucontext uc; + unsigned int retcode[3]; +}; + +#define INSN_MOV_R30_R16 0x47fe0410 +#define INSN_LDI_R0 0x201f0000 +#define INSN_CALLSYS 0x00000083 + +static int setup_sigcontext(struct target_sigcontext *sc, CPUState *env, + abi_ulong frame_addr, target_sigset_t *set) +{ + int i, err = 0; + + err |= __put_user(on_sig_stack(frame_addr), &sc->sc_onstack); + err |= __put_user(set->sig[0], &sc->sc_mask); + err |= __put_user(env->pc, &sc->sc_pc); + err |= __put_user(8, &sc->sc_ps); + + for (i = 0; i < 31; ++i) { + err |= __put_user(env->ir[i], &sc->sc_regs[i]); + } + err |= __put_user(0, &sc->sc_regs[31]); + + for (i = 0; i < 31; ++i) { + err |= __put_user(env->fir[i], &sc->sc_fpregs[i]); + } + err |= __put_user(0, &sc->sc_fpregs[31]); + err |= __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr); + + err |= __put_user(0, &sc->sc_traparg_a0); /* FIXME */ + err |= __put_user(0, &sc->sc_traparg_a1); /* FIXME */ + err |= __put_user(0, &sc->sc_traparg_a2); /* FIXME */ + + return err; +} + +static int restore_sigcontext(CPUState *env, struct target_sigcontext *sc) +{ + uint64_t fpcr; + int i, err = 0; + + err |= __get_user(env->pc, &sc->sc_pc); + + for (i = 0; i < 31; ++i) { + err |= __get_user(env->ir[i], &sc->sc_regs[i]); + } + for (i = 0; i < 31; ++i) { + err |= __get_user(env->fir[i], &sc->sc_fpregs[i]); + } + + err |= __get_user(fpcr, &sc->sc_fpcr); + cpu_alpha_store_fpcr(env, fpcr); + + return err; +} + +static inline abi_ulong get_sigframe(struct target_sigaction *sa, + CPUState *env, unsigned long framesize) +{ + abi_ulong sp = env->ir[IR_SP]; + + /* This is the X/Open sanctioned signal stack switching. */ + if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) { + sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; + } + return (sp - framesize) & -32; +} + +static void setup_frame(int sig, struct target_sigaction *ka, + target_sigset_t *set, CPUState *env) +{ + abi_ulong frame_addr, r26; + struct target_sigframe *frame; + int err = 0; + + frame_addr = get_sigframe(ka, env, sizeof(*frame)); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto give_sigsegv; + } + + err |= setup_sigcontext(&frame->sc, env, frame_addr, set); + + if (ka->sa_restorer) { + r26 = ka->sa_restorer; + } else { + err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); + err |= __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, + &frame->retcode[1]); + err |= __put_user(INSN_CALLSYS, &frame->retcode[2]); + /* imb() */ + r26 = frame_addr; + } + + unlock_user_struct(frame, frame_addr, 1); + + if (err) { + give_sigsegv: + if (sig == TARGET_SIGSEGV) { + ka->_sa_handler = TARGET_SIG_DFL; + } + force_sig(TARGET_SIGSEGV); + } + + env->ir[IR_RA] = r26; + env->ir[IR_PV] = env->pc = ka->_sa_handler; + env->ir[IR_A0] = sig; + env->ir[IR_A1] = 0; + env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc); + env->ir[IR_SP] = frame_addr; +} + +static void setup_rt_frame(int sig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + abi_ulong frame_addr, r26; + struct target_rt_sigframe *frame; + int i, err = 0; + + frame_addr = get_sigframe(ka, env, sizeof(*frame)); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto give_sigsegv; + } + + err |= copy_siginfo_to_user(&frame->info, info); + + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask); + err |= __put_user(target_sigaltstack_used.ss_sp, + &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(env->ir[IR_SP]), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(target_sigaltstack_used.ss_size, + &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.uc_mcontext, env, frame_addr, set); + for (i = 0; i < TARGET_NSIG_WORDS; ++i) { + err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]); + } + + if (ka->sa_restorer) { + r26 = ka->sa_restorer; + } else { + err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); + err |= __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, + &frame->retcode[1]); + err |= __put_user(INSN_CALLSYS, &frame->retcode[2]); + /* imb(); */ + r26 = frame_addr; + } + + if (err) { + give_sigsegv: + if (sig == TARGET_SIGSEGV) { + ka->_sa_handler = TARGET_SIG_DFL; + } + force_sig(TARGET_SIGSEGV); + } + + env->ir[IR_RA] = r26; + env->ir[IR_PV] = env->pc = ka->_sa_handler; + env->ir[IR_A0] = sig; + env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info); + env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc); + env->ir[IR_SP] = frame_addr; +} + +long do_sigreturn(CPUState *env) +{ + struct target_sigcontext *sc; + abi_ulong sc_addr = env->ir[IR_A0]; + target_sigset_t target_set; + sigset_t set; + + if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) { + goto badframe; + } + + target_sigemptyset(&target_set); + if (__get_user(target_set.sig[0], &sc->sc_mask)) { + goto badframe; + } + + target_to_host_sigset_internal(&set, &target_set); + sigprocmask(SIG_SETMASK, &set, NULL); + + if (restore_sigcontext(env, sc)) { + goto badframe; + } + unlock_user_struct(sc, sc_addr, 0); + return env->ir[IR_V0]; + + badframe: + unlock_user_struct(sc, sc_addr, 0); + force_sig(TARGET_SIGSEGV); +} + +long do_rt_sigreturn(CPUState *env) +{ + abi_ulong frame_addr = env->ir[IR_A0]; + struct target_rt_sigframe *frame; + sigset_t set; + + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { + goto badframe; + } + target_to_host_sigset(&set, &frame->uc.uc_sigmask); + sigprocmask(SIG_SETMASK, &set, NULL); + + if (restore_sigcontext(env, &frame->uc.uc_mcontext)) { + goto badframe; + } + if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, + uc.uc_stack), + 0, env->ir[IR_SP]) == -EFAULT) { + goto badframe; + } + + unlock_user_struct(frame, frame_addr, 0); + return env->ir[IR_V0]; + + + badframe: + unlock_user_struct(frame, frame_addr, 0); + force_sig(TARGET_SIGSEGV); +} + #else static void setup_frame(int sig, struct target_sigaction *ka, diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9fb493fba..38eb35f54 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4775,20 +4775,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_sigaction case TARGET_NR_sigaction: { -#if !defined(TARGET_MIPS) +#if defined(TARGET_ALPHA) + struct target_sigaction act, oact, *pact = 0; struct target_old_sigaction *old_act; - struct target_sigaction act, oact, *pact; if (arg2) { if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) goto efault; act._sa_handler = old_act->_sa_handler; target_siginitset(&act.sa_mask, old_act->sa_mask); act.sa_flags = old_act->sa_flags; - act.sa_restorer = old_act->sa_restorer; + act.sa_restorer = 0; unlock_user_struct(old_act, arg2, 0); pact = &act; - } else { - pact = NULL; } ret = get_errno(do_sigaction(arg1, pact, &oact)); if (!is_error(ret) && arg3) { @@ -4797,10 +4795,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, old_act->_sa_handler = oact._sa_handler; old_act->sa_mask = oact.sa_mask.sig[0]; old_act->sa_flags = oact.sa_flags; - old_act->sa_restorer = oact.sa_restorer; unlock_user_struct(old_act, arg3, 1); } -#else +#elif defined(TARGET_MIPS) struct target_sigaction act, oact, *pact, *old_act; if (arg2) { @@ -4828,12 +4825,61 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, old_act->sa_mask.sig[3] = 0; unlock_user_struct(old_act, arg3, 1); } +#else + struct target_old_sigaction *old_act; + struct target_sigaction act, oact, *pact; + if (arg2) { + if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) + goto efault; + act._sa_handler = old_act->_sa_handler; + target_siginitset(&act.sa_mask, old_act->sa_mask); + act.sa_flags = old_act->sa_flags; + act.sa_restorer = old_act->sa_restorer; + unlock_user_struct(old_act, arg2, 0); + pact = &act; + } else { + pact = NULL; + } + ret = get_errno(do_sigaction(arg1, pact, &oact)); + if (!is_error(ret) && arg3) { + if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) + goto efault; + old_act->_sa_handler = oact._sa_handler; + old_act->sa_mask = oact.sa_mask.sig[0]; + old_act->sa_flags = oact.sa_flags; + old_act->sa_restorer = oact.sa_restorer; + unlock_user_struct(old_act, arg3, 1); + } #endif } break; #endif case TARGET_NR_rt_sigaction: { +#if defined(TARGET_ALPHA) + struct target_sigaction act, oact, *pact = 0; + struct target_rt_sigaction *rt_act; + /* ??? arg4 == sizeof(sigset_t). */ + if (arg2) { + if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1)) + goto efault; + act._sa_handler = rt_act->_sa_handler; + act.sa_mask = rt_act->sa_mask; + act.sa_flags = rt_act->sa_flags; + act.sa_restorer = arg5; + unlock_user_struct(rt_act, arg2, 0); + pact = &act; + } + ret = get_errno(do_sigaction(arg1, pact, &oact)); + if (!is_error(ret) && arg3) { + if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0)) + goto efault; + rt_act->_sa_handler = oact._sa_handler; + rt_act->sa_mask = oact.sa_mask; + rt_act->sa_flags = oact.sa_flags; + unlock_user_struct(rt_act, arg3, 1); + } +#else struct target_sigaction *act; struct target_sigaction *oact; @@ -4855,6 +4901,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user_struct(act, arg2, 0); if (oact) unlock_user_struct(oact, arg3, 1); +#endif } break; #ifdef TARGET_NR_sgetmask /* not on alpha */ diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 2d45753dd..63c2bc3db 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -472,8 +472,28 @@ int do_sigaction(int sig, const struct target_sigaction *act, #endif -#if defined(TARGET_MIPS) +#if defined(TARGET_ALPHA) +struct target_old_sigaction { + abi_ulong _sa_handler; + abi_ulong sa_mask; + abi_ulong sa_flags; +}; + +struct target_rt_sigaction { + abi_ulong _sa_handler; + abi_ulong sa_flags; + target_sigset_t sa_mask; +}; +/* This is the struct used inside the kernel. The ka_restorer + field comes from the 5th argument to sys_rt_sigaction. */ +struct target_sigaction { + abi_ulong _sa_handler; + abi_ulong sa_flags; + target_sigset_t sa_mask; + abi_ulong sa_restorer; +}; +#elif defined(TARGET_MIPS) struct target_sigaction { uint32_t sa_flags; #if defined(TARGET_ABI_MIPSN32) @@ -483,7 +503,6 @@ struct target_sigaction { #endif target_sigset_t sa_mask; }; - #else struct target_old_sigaction { abi_ulong _sa_handler; diff --git a/qemu-char.c b/qemu-char.c index 416949221..86c7c5a3f 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2334,7 +2334,6 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) { host[0] = 0; if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) { - fprintf(stderr, "udp #1\n"); goto fail; } } @@ -2345,7 +2344,6 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) { host[0] = 0; if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) { - fprintf(stderr, "udp #2\n"); goto fail; } } @@ -2373,7 +2371,6 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) } fail: - fprintf(stderr, "%s: fail on \"%s\"\n", __FUNCTION__, filename); qemu_opts_del(opts); return NULL; } diff --git a/qemu-malloc.c b/qemu-malloc.c index 5d9e34d69..6cdc5deb7 100644 --- a/qemu-malloc.c +++ b/qemu-malloc.c @@ -61,12 +61,10 @@ void *qemu_malloc(size_t size) void *qemu_realloc(void *ptr, size_t size) { - if (size) { - return oom_check(realloc(ptr, size)); - } else if (allow_zero_malloc()) { - return oom_check(realloc(ptr, size ? size : 1)); + if (!size && !allow_zero_malloc()) { + abort(); } - abort(); + return oom_check(realloc(ptr, size ? size : 1)); } void *qemu_mallocz(size_t size) diff --git a/qemu-options.hx b/qemu-options.hx index 9683d09bd..42e8b4be0 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1030,7 +1030,7 @@ the guest, use the following: @example # on the host -qemu -net user,hostfwd=tcp:5555::23 [...] +qemu -net user,hostfwd=tcp::5555-:23 [...] telnet localhost 5555 @end example diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index c0dff4bb8..617f55c20 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -145,6 +145,10 @@ enum { #define FPCR_UNFD (1ULL << 61) #define FPCR_UNDZ (1ULL << 60) #define FPCR_DYN_SHIFT 58 +#define FPCR_DYN_CHOPPED (0ULL << FPCR_DYN_SHIFT) +#define FPCR_DYN_MINUS (1ULL << FPCR_DYN_SHIFT) +#define FPCR_DYN_NORMAL (2ULL << FPCR_DYN_SHIFT) +#define FPCR_DYN_PLUS (3ULL << FPCR_DYN_SHIFT) #define FPCR_DYN_MASK (3ULL << FPCR_DYN_SHIFT) #define FPCR_IOV (1ULL << 57) #define FPCR_INE (1ULL << 56) @@ -189,6 +193,11 @@ enum { /* Internal processor registers */ /* XXX: TOFIX: most of those registers are implementation dependant */ enum { +#if defined(CONFIG_USER_ONLY) + IPR_EXC_ADDR, + IPR_EXC_SUM, + IPR_EXC_MASK, +#else /* Ebox IPRs */ IPR_CC = 0xC0, /* 21264 */ IPR_CC_CTL = 0xC1, /* 21264 */ @@ -302,6 +311,7 @@ enum { IPR_VPTB, IPR_WHAMI, IPR_ALT_MODE, +#endif IPR_LAST, }; @@ -341,17 +351,27 @@ struct pal_handler_t { struct CPUAlphaState { uint64_t ir[31]; - float64 fir[31]; - float_status fp_status; - uint64_t fpcr; + float64 fir[31]; uint64_t pc; uint64_t lock; uint32_t pcc[2]; uint64_t ipr[IPR_LAST]; uint64_t ps; uint64_t unique; - int saved_mode; /* Used for HW_LD / HW_ST */ - int intr_flag; /* For RC and RS */ + float_status fp_status; + /* The following fields make up the FPCR, but in FP_STATUS format. */ + uint8_t fpcr_exc_status; + uint8_t fpcr_exc_mask; + uint8_t fpcr_dyn_round; + uint8_t fpcr_flush_to_zero; + uint8_t fpcr_dnz; + uint8_t fpcr_dnod; + uint8_t fpcr_undz; + + /* Used for HW_LD / HW_ST */ + uint8_t saved_mode; + /* For RC and RS */ + uint8_t intr_flag; #if TARGET_LONG_BITS > HOST_LONG_BITS /* temporary fixed-point registers @@ -430,9 +450,13 @@ enum { }; /* Arithmetic exception */ -enum { - EXCP_ARITH_OVERFLOW, -}; +#define EXC_M_IOV (1<<16) /* Integer Overflow */ +#define EXC_M_INE (1<<15) /* Inexact result */ +#define EXC_M_UNF (1<<14) /* Underflow */ +#define EXC_M_FOV (1<<13) /* Overflow */ +#define EXC_M_DZE (1<<12) /* Division by zero */ +#define EXC_M_INV (1<<11) /* Invalid operation */ +#define EXC_M_SWC (1<<10) /* Software completion */ enum { IR_V0 = 0, @@ -487,11 +511,9 @@ uint64_t cpu_alpha_load_fpcr (CPUState *env); void cpu_alpha_store_fpcr (CPUState *env, uint64_t val); int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp); int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); -void pal_init (CPUState *env); #if !defined (CONFIG_USER_ONLY) +void pal_init (CPUState *env); void call_pal (CPUState *env); -#else -void call_pal (CPUState *env, int palcode); #endif static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) diff --git a/target-alpha/helper.c b/target-alpha/helper.c index 1e0bc4a15..f35ca9ac5 100644 --- a/target-alpha/helper.c +++ b/target-alpha/helper.c @@ -27,79 +27,136 @@ uint64_t cpu_alpha_load_fpcr (CPUState *env) { - uint64_t ret = 0; - int flags, mask; - - flags = env->fp_status.float_exception_flags; - ret |= (uint64_t) flags << 52; - if (flags) - ret |= FPCR_SUM; - env->ipr[IPR_EXC_SUM] &= ~0x3E; - env->ipr[IPR_EXC_SUM] |= flags << 1; - - mask = env->fp_status.float_exception_mask; - if (mask & float_flag_invalid) - ret |= FPCR_INVD; - if (mask & float_flag_divbyzero) - ret |= FPCR_DZED; - if (mask & float_flag_overflow) - ret |= FPCR_OVFD; - if (mask & float_flag_underflow) - ret |= FPCR_UNFD; - if (mask & float_flag_inexact) - ret |= FPCR_INED; - - switch (env->fp_status.float_rounding_mode) { + uint64_t r = 0; + uint8_t t; + + t = env->fpcr_exc_status; + if (t) { + r = FPCR_SUM; + if (t & float_flag_invalid) { + r |= FPCR_INV; + } + if (t & float_flag_divbyzero) { + r |= FPCR_DZE; + } + if (t & float_flag_overflow) { + r |= FPCR_OVF; + } + if (t & float_flag_underflow) { + r |= FPCR_UNF; + } + if (t & float_flag_inexact) { + r |= FPCR_INE; + } + } + + t = env->fpcr_exc_mask; + if (t & float_flag_invalid) { + r |= FPCR_INVD; + } + if (t & float_flag_divbyzero) { + r |= FPCR_DZED; + } + if (t & float_flag_overflow) { + r |= FPCR_OVFD; + } + if (t & float_flag_underflow) { + r |= FPCR_UNFD; + } + if (t & float_flag_inexact) { + r |= FPCR_INED; + } + + switch (env->fpcr_dyn_round) { case float_round_nearest_even: - ret |= 2ULL << FPCR_DYN_SHIFT; + r |= FPCR_DYN_NORMAL; break; case float_round_down: - ret |= 1ULL << FPCR_DYN_SHIFT; + r |= FPCR_DYN_MINUS; break; case float_round_up: - ret |= 3ULL << FPCR_DYN_SHIFT; + r |= FPCR_DYN_PLUS; break; case float_round_to_zero: + r |= FPCR_DYN_CHOPPED; break; } - return ret; + + if (env->fpcr_dnz) { + r |= FPCR_DNZ; + } + if (env->fpcr_dnod) { + r |= FPCR_DNOD; + } + if (env->fpcr_undz) { + r |= FPCR_UNDZ; + } + + return r; } void cpu_alpha_store_fpcr (CPUState *env, uint64_t val) { - int round_mode, mask; + uint8_t t; - set_float_exception_flags((val >> 52) & 0x3F, &env->fp_status); + t = 0; + if (val & FPCR_INV) { + t |= float_flag_invalid; + } + if (val & FPCR_DZE) { + t |= float_flag_divbyzero; + } + if (val & FPCR_OVF) { + t |= float_flag_overflow; + } + if (val & FPCR_UNF) { + t |= float_flag_underflow; + } + if (val & FPCR_INE) { + t |= float_flag_inexact; + } + env->fpcr_exc_status = t; - mask = 0; - if (val & FPCR_INVD) - mask |= float_flag_invalid; - if (val & FPCR_DZED) - mask |= float_flag_divbyzero; - if (val & FPCR_OVFD) - mask |= float_flag_overflow; - if (val & FPCR_UNFD) - mask |= float_flag_underflow; - if (val & FPCR_INED) - mask |= float_flag_inexact; - env->fp_status.float_exception_mask = mask; + t = 0; + if (val & FPCR_INVD) { + t |= float_flag_invalid; + } + if (val & FPCR_DZED) { + t |= float_flag_divbyzero; + } + if (val & FPCR_OVFD) { + t |= float_flag_overflow; + } + if (val & FPCR_UNFD) { + t |= float_flag_underflow; + } + if (val & FPCR_INED) { + t |= float_flag_inexact; + } + env->fpcr_exc_mask = t; - switch ((val >> FPCR_DYN_SHIFT) & 3) { - case 0: - round_mode = float_round_to_zero; + switch (val & FPCR_DYN_MASK) { + case FPCR_DYN_CHOPPED: + t = float_round_to_zero; break; - case 1: - round_mode = float_round_down; + case FPCR_DYN_MINUS: + t = float_round_down; break; - case 2: - round_mode = float_round_nearest_even; + case FPCR_DYN_NORMAL: + t = float_round_nearest_even; break; - case 3: - default: /* this avoids a gcc (< 4.4) warning */ - round_mode = float_round_up; + case FPCR_DYN_PLUS: + t = float_round_up; break; } - set_float_rounding_mode(round_mode, &env->fp_status); + env->fpcr_dyn_round = t; + + env->fpcr_flush_to_zero + = (val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD); + + env->fpcr_dnz = (val & FPCR_DNZ) != 0; + env->fpcr_dnod = (val & FPCR_DNOD) != 0; + env->fpcr_undz = (val & FPCR_UNDZ) != 0; } #if defined(CONFIG_USER_ONLY) diff --git a/target-alpha/helper.h b/target-alpha/helper.h index bedd3c0da..79cf375a6 100644 --- a/target-alpha/helper.h +++ b/target-alpha/helper.h @@ -83,7 +83,6 @@ DEF_HELPER_2(cpyse, i64, i64, i64) DEF_HELPER_1(cvtts, i64, i64) DEF_HELPER_1(cvtst, i64, i64) -DEF_HELPER_1(cvttq, i64, i64) DEF_HELPER_1(cvtqs, i64, i64) DEF_HELPER_1(cvtqt, i64, i64) DEF_HELPER_1(cvtqf, i64, i64) @@ -91,9 +90,25 @@ DEF_HELPER_1(cvtgf, i64, i64) DEF_HELPER_1(cvtgq, i64, i64) DEF_HELPER_1(cvtqg, i64, i64) DEF_HELPER_1(cvtlq, i64, i64) + +DEF_HELPER_1(cvttq, i64, i64) +DEF_HELPER_1(cvttq_c, i64, i64) +DEF_HELPER_1(cvttq_svic, i64, i64) + DEF_HELPER_1(cvtql, i64, i64) -DEF_HELPER_1(cvtqlv, i64, i64) -DEF_HELPER_1(cvtqlsv, i64, i64) +DEF_HELPER_1(cvtql_v, i64, i64) +DEF_HELPER_1(cvtql_sv, i64, i64) + +DEF_HELPER_1(setroundmode, void, i32) +DEF_HELPER_1(setflushzero, void, i32) +DEF_HELPER_0(fp_exc_clear, void) +DEF_HELPER_0(fp_exc_get, i32) +DEF_HELPER_2(fp_exc_raise, void, i32, i32) +DEF_HELPER_2(fp_exc_raise_s, void, i32, i32) + +DEF_HELPER_1(ieee_input, i64, i64) +DEF_HELPER_1(ieee_input_cmp, i64, i64) +DEF_HELPER_1(ieee_input_s, i64, i64) #if !defined (CONFIG_USER_ONLY) DEF_HELPER_0(hw_rei, void) diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index b2abf6c78..4d2c2ee58 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -24,7 +24,7 @@ /*****************************************************************************/ /* Exceptions processing helpers */ -void helper_excp (int excp, int error) +void QEMU_NORETURN helper_excp (int excp, int error) { env->exception_index = excp; env->error_code = error; @@ -78,7 +78,7 @@ uint64_t helper_addqv (uint64_t op1, uint64_t op2) uint64_t tmp = op1; op1 += op2; if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) { - helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); + helper_excp(EXCP_ARITH, EXC_M_IOV); } return op1; } @@ -88,7 +88,7 @@ uint64_t helper_addlv (uint64_t op1, uint64_t op2) uint64_t tmp = op1; op1 = (uint32_t)(op1 + op2); if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) { - helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); + helper_excp(EXCP_ARITH, EXC_M_IOV); } return op1; } @@ -98,7 +98,7 @@ uint64_t helper_subqv (uint64_t op1, uint64_t op2) uint64_t res; res = op1 - op2; if (unlikely((op1 ^ op2) & (res ^ op1) & (1ULL << 63))) { - helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); + helper_excp(EXCP_ARITH, EXC_M_IOV); } return res; } @@ -108,7 +108,7 @@ uint64_t helper_sublv (uint64_t op1, uint64_t op2) uint32_t res; res = op1 - op2; if (unlikely((op1 ^ op2) & (res ^ op1) & (1UL << 31))) { - helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); + helper_excp(EXCP_ARITH, EXC_M_IOV); } return res; } @@ -118,7 +118,7 @@ uint64_t helper_mullv (uint64_t op1, uint64_t op2) int64_t res = (int64_t)op1 * (int64_t)op2; if (unlikely((int32_t)res != res)) { - helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); + helper_excp(EXCP_ARITH, EXC_M_IOV); } return (int64_t)((int32_t)res); } @@ -130,7 +130,7 @@ uint64_t helper_mulqv (uint64_t op1, uint64_t op2) muls64(&tl, &th, op1, op2); /* If th != 0 && th != -1, then we had an overflow */ if (unlikely((th + 1) > 1)) { - helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); + helper_excp(EXCP_ARITH, EXC_M_IOV); } return tl; } @@ -370,6 +370,130 @@ uint64_t helper_unpkbw (uint64_t op1) /* Floating point helpers */ +void helper_setroundmode (uint32_t val) +{ + set_float_rounding_mode(val, &FP_STATUS); +} + +void helper_setflushzero (uint32_t val) +{ + set_flush_to_zero(val, &FP_STATUS); +} + +void helper_fp_exc_clear (void) +{ + set_float_exception_flags(0, &FP_STATUS); +} + +uint32_t helper_fp_exc_get (void) +{ + return get_float_exception_flags(&FP_STATUS); +} + +/* Raise exceptions for ieee fp insns without software completion. + In that case there are no exceptions that don't trap; the mask + doesn't apply. */ +void helper_fp_exc_raise(uint32_t exc, uint32_t regno) +{ + if (exc) { + uint32_t hw_exc = 0; + + env->ipr[IPR_EXC_MASK] |= 1ull << regno; + + if (exc & float_flag_invalid) { + hw_exc |= EXC_M_INV; + } + if (exc & float_flag_divbyzero) { + hw_exc |= EXC_M_DZE; + } + if (exc & float_flag_overflow) { + hw_exc |= EXC_M_FOV; + } + if (exc & float_flag_underflow) { + hw_exc |= EXC_M_UNF; + } + if (exc & float_flag_inexact) { + hw_exc |= EXC_M_INE; + } + helper_excp(EXCP_ARITH, hw_exc); + } +} + +/* Raise exceptions for ieee fp insns with software completion. */ +void helper_fp_exc_raise_s(uint32_t exc, uint32_t regno) +{ + if (exc) { + env->fpcr_exc_status |= exc; + + exc &= ~env->fpcr_exc_mask; + if (exc) { + helper_fp_exc_raise(exc, regno); + } + } +} + +/* Input remapping without software completion. Handle denormal-map-to-zero + and trap for all other non-finite numbers. */ +uint64_t helper_ieee_input(uint64_t val) +{ + uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; + uint64_t frac = val & 0xfffffffffffffull; + + if (exp == 0) { + if (frac != 0) { + /* If DNZ is set flush denormals to zero on input. */ + if (env->fpcr_dnz) { + val &= 1ull << 63; + } else { + helper_excp(EXCP_ARITH, EXC_M_UNF); + } + } + } else if (exp == 0x7ff) { + /* Infinity or NaN. */ + /* ??? I'm not sure these exception bit flags are correct. I do + know that the Linux kernel, at least, doesn't rely on them and + just emulates the insn to figure out what exception to use. */ + helper_excp(EXCP_ARITH, frac ? EXC_M_INV : EXC_M_FOV); + } + return val; +} + +/* Similar, but does not trap for infinities. Used for comparisons. */ +uint64_t helper_ieee_input_cmp(uint64_t val) +{ + uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; + uint64_t frac = val & 0xfffffffffffffull; + + if (exp == 0) { + if (frac != 0) { + /* If DNZ is set flush denormals to zero on input. */ + if (env->fpcr_dnz) { + val &= 1ull << 63; + } else { + helper_excp(EXCP_ARITH, EXC_M_UNF); + } + } + } else if (exp == 0x7ff && frac) { + /* NaN. */ + helper_excp(EXCP_ARITH, EXC_M_INV); + } + return val; +} + +/* Input remapping with software completion enabled. All we have to do + is handle denormal-map-to-zero; all other inputs get exceptions as + needed from the actual operation. */ +uint64_t helper_ieee_input_s(uint64_t val) +{ + if (env->fpcr_dnz) { + uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; + if (exp == 0) { + val &= 1ull << 63; + } + } + return val; +} + /* F floating (VAX) */ static inline uint64_t float32_to_f(float32 fa) { @@ -447,6 +571,9 @@ uint64_t helper_memory_to_f (uint32_t a) return r; } +/* ??? Emulating VAX arithmetic with IEEE arithmetic is wrong. We should + either implement VAX arithmetic properly or just signal invalid opcode. */ + uint64_t helper_addf (uint64_t a, uint64_t b) { float32 fa, fb, fr; @@ -931,10 +1058,107 @@ uint64_t helper_cvtqs (uint64_t a) return float32_to_s(fr); } -uint64_t helper_cvttq (uint64_t a) +/* Implement float64 to uint64 conversion without saturation -- we must + supply the truncated result. This behaviour is used by the compiler + to get unsigned conversion for free with the same instruction. + + The VI flag is set when overflow or inexact exceptions should be raised. */ + +static inline uint64_t helper_cvttq_internal(uint64_t a, int roundmode, int VI) { - float64 fa = t_to_float64(a); - return float64_to_int64_round_to_zero(fa, &FP_STATUS); + uint64_t frac, ret = 0; + uint32_t exp, sign, exc = 0; + int shift; + + sign = (a >> 63); + exp = (uint32_t)(a >> 52) & 0x7ff; + frac = a & 0xfffffffffffffull; + + if (exp == 0) { + if (unlikely(frac != 0)) { + goto do_underflow; + } + } else if (exp == 0x7ff) { + exc = (frac ? float_flag_invalid : VI ? float_flag_overflow : 0); + } else { + /* Restore implicit bit. */ + frac |= 0x10000000000000ull; + + shift = exp - 1023 - 52; + if (shift >= 0) { + /* In this case the number is so large that we must shift + the fraction left. There is no rounding to do. */ + if (shift < 63) { + ret = frac << shift; + if (VI && (ret >> shift) != frac) { + exc = float_flag_overflow; + } + } + } else { + uint64_t round; + + /* In this case the number is smaller than the fraction as + represented by the 52 bit number. Here we must think + about rounding the result. Handle this by shifting the + fractional part of the number into the high bits of ROUND. + This will let us efficiently handle round-to-nearest. */ + shift = -shift; + if (shift < 63) { + ret = frac >> shift; + round = frac << (64 - shift); + } else { + /* The exponent is so small we shift out everything. + Leave a sticky bit for proper rounding below. */ + do_underflow: + round = 1; + } + + if (round) { + exc = (VI ? float_flag_inexact : 0); + switch (roundmode) { + case float_round_nearest_even: + if (round == (1ull << 63)) { + /* Fraction is exactly 0.5; round to even. */ + ret += (ret & 1); + } else if (round > (1ull << 63)) { + ret += 1; + } + break; + case float_round_to_zero: + break; + case float_round_up: + ret += 1 - sign; + break; + case float_round_down: + ret += sign; + break; + } + } + } + if (sign) { + ret = -ret; + } + } + if (unlikely(exc)) { + float_raise(exc, &FP_STATUS); + } + + return ret; +} + +uint64_t helper_cvttq(uint64_t a) +{ + return helper_cvttq_internal(a, FP_STATUS.float_rounding_mode, 1); +} + +uint64_t helper_cvttq_c(uint64_t a) +{ + return helper_cvttq_internal(a, float_round_to_zero, 0); +} + +uint64_t helper_cvttq_svic(uint64_t a) +{ + return helper_cvttq_internal(a, float_round_to_zero, 1); } uint64_t helper_cvtqt (uint64_t a) @@ -979,35 +1203,24 @@ uint64_t helper_cvtlq (uint64_t a) return (lo & 0x3FFFFFFF) | (hi & 0xc0000000); } -static inline uint64_t __helper_cvtql(uint64_t a, int s, int v) -{ - uint64_t r; - - r = ((uint64_t)(a & 0xC0000000)) << 32; - r |= ((uint64_t)(a & 0x7FFFFFFF)) << 29; - - if (v && (int64_t)((int32_t)r) != (int64_t)r) { - helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW); - } - if (s) { - /* TODO */ - } - return r; -} - uint64_t helper_cvtql (uint64_t a) { - return __helper_cvtql(a, 0, 0); + return ((a & 0xC0000000) << 32) | ((a & 0x7FFFFFFF) << 29); } -uint64_t helper_cvtqlv (uint64_t a) +uint64_t helper_cvtql_v (uint64_t a) { - return __helper_cvtql(a, 0, 1); + if ((int32_t)a != (int64_t)a) + helper_excp(EXCP_ARITH, EXC_M_IOV); + return helper_cvtql(a); } -uint64_t helper_cvtqlsv (uint64_t a) +uint64_t helper_cvtql_sv (uint64_t a) { - return __helper_cvtql(a, 1, 1); + /* ??? I'm pretty sure there's nothing that /sv needs to do that /v + doesn't do. The only thing I can think is that /sv is a valid + instruction merely for completeness in the ISA. */ + return helper_cvtql_v(a); } /* PALcode support special instructions */ diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 87813e7dd..719b42319 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -33,6 +33,7 @@ #include "helper.h" #undef ALPHA_DEBUG_DISAS +#define CONFIG_SOFTFLOAT_INLINE #ifdef ALPHA_DEBUG_DISAS # define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) @@ -49,6 +50,11 @@ struct DisasContext { #endif CPUAlphaState *env; uint32_t amask; + + /* Current rounding mode for this TB. */ + int tb_rm; + /* Current flush-to-zero setting for this TB. */ + int tb_ftz; }; /* global register indexes */ @@ -442,62 +448,333 @@ static void gen_fcmov(TCGCond inv_cond, int ra, int rb, int rc) gen_set_label(l1); } -#define FARITH2(name) \ -static inline void glue(gen_f, name)(int rb, int rc) \ -{ \ - if (unlikely(rc == 31)) \ - return; \ - \ - if (rb != 31) \ - gen_helper_ ## name (cpu_fir[rc], cpu_fir[rb]); \ - else { \ - TCGv tmp = tcg_const_i64(0); \ - gen_helper_ ## name (cpu_fir[rc], tmp); \ - tcg_temp_free(tmp); \ - } \ +#define QUAL_RM_N 0x080 /* Round mode nearest even */ +#define QUAL_RM_C 0x000 /* Round mode chopped */ +#define QUAL_RM_M 0x040 /* Round mode minus infinity */ +#define QUAL_RM_D 0x0c0 /* Round mode dynamic */ +#define QUAL_RM_MASK 0x0c0 + +#define QUAL_U 0x100 /* Underflow enable (fp output) */ +#define QUAL_V 0x100 /* Overflow enable (int output) */ +#define QUAL_S 0x400 /* Software completion enable */ +#define QUAL_I 0x200 /* Inexact detection enable */ + +static void gen_qual_roundmode(DisasContext *ctx, int fn11) +{ + TCGv_i32 tmp; + + fn11 &= QUAL_RM_MASK; + if (fn11 == ctx->tb_rm) { + return; + } + ctx->tb_rm = fn11; + + tmp = tcg_temp_new_i32(); + switch (fn11) { + case QUAL_RM_N: + tcg_gen_movi_i32(tmp, float_round_nearest_even); + break; + case QUAL_RM_C: + tcg_gen_movi_i32(tmp, float_round_to_zero); + break; + case QUAL_RM_M: + tcg_gen_movi_i32(tmp, float_round_down); + break; + case QUAL_RM_D: + tcg_gen_ld8u_i32(tmp, cpu_env, offsetof(CPUState, fpcr_dyn_round)); + break; + } + +#if defined(CONFIG_SOFTFLOAT_INLINE) + /* ??? The "softfloat.h" interface is to call set_float_rounding_mode. + With CONFIG_SOFTFLOAT that expands to an out-of-line call that just + sets the one field. */ + tcg_gen_st8_i32(tmp, cpu_env, + offsetof(CPUState, fp_status.float_rounding_mode)); +#else + gen_helper_setroundmode(tmp); +#endif + + tcg_temp_free_i32(tmp); +} + +static void gen_qual_flushzero(DisasContext *ctx, int fn11) +{ + TCGv_i32 tmp; + + fn11 &= QUAL_U; + if (fn11 == ctx->tb_ftz) { + return; + } + ctx->tb_ftz = fn11; + + tmp = tcg_temp_new_i32(); + if (fn11) { + /* Underflow is enabled, use the FPCR setting. */ + tcg_gen_ld8u_i32(tmp, cpu_env, offsetof(CPUState, fpcr_flush_to_zero)); + } else { + /* Underflow is disabled, force flush-to-zero. */ + tcg_gen_movi_i32(tmp, 1); + } + +#if defined(CONFIG_SOFTFLOAT_INLINE) + tcg_gen_st8_i32(tmp, cpu_env, + offsetof(CPUState, fp_status.flush_to_zero)); +#else + gen_helper_setflushzero(tmp); +#endif + + tcg_temp_free_i32(tmp); +} + +static TCGv gen_ieee_input(int reg, int fn11, int is_cmp) +{ + TCGv val = tcg_temp_new(); + if (reg == 31) { + tcg_gen_movi_i64(val, 0); + } else if (fn11 & QUAL_S) { + gen_helper_ieee_input_s(val, cpu_fir[reg]); + } else if (is_cmp) { + gen_helper_ieee_input_cmp(val, cpu_fir[reg]); + } else { + gen_helper_ieee_input(val, cpu_fir[reg]); + } + return val; +} + +static void gen_fp_exc_clear(void) +{ +#if defined(CONFIG_SOFTFLOAT_INLINE) + TCGv_i32 zero = tcg_const_i32(0); + tcg_gen_st8_i32(zero, cpu_env, + offsetof(CPUState, fp_status.float_exception_flags)); + tcg_temp_free_i32(zero); +#else + gen_helper_fp_exc_clear(); +#endif +} + +static void gen_fp_exc_raise_ignore(int rc, int fn11, int ignore) +{ + /* ??? We ought to be able to do something with imprecise exceptions. + E.g. notice we're still in the trap shadow of something within the + TB and do not generate the code to signal the exception; end the TB + when an exception is forced to arrive, either by consumption of a + register value or TRAPB or EXCB. */ + TCGv_i32 exc = tcg_temp_new_i32(); + TCGv_i32 reg; + +#if defined(CONFIG_SOFTFLOAT_INLINE) + tcg_gen_ld8u_i32(exc, cpu_env, + offsetof(CPUState, fp_status.float_exception_flags)); +#else + gen_helper_fp_exc_get(exc); +#endif + + if (ignore) { + tcg_gen_andi_i32(exc, exc, ~ignore); + } + + /* ??? Pass in the regno of the destination so that the helper can + set EXC_MASK, which contains a bitmask of destination registers + that have caused arithmetic traps. A simple userspace emulation + does not require this. We do need it for a guest kernel's entArith, + or if we were to do something clever with imprecise exceptions. */ + reg = tcg_const_i32(rc + 32); + + if (fn11 & QUAL_S) { + gen_helper_fp_exc_raise_s(exc, reg); + } else { + gen_helper_fp_exc_raise(exc, reg); + } + + tcg_temp_free_i32(reg); + tcg_temp_free_i32(exc); +} + +static inline void gen_fp_exc_raise(int rc, int fn11) +{ + gen_fp_exc_raise_ignore(rc, fn11, fn11 & QUAL_I ? 0 : float_flag_inexact); +} + +#define FARITH2(name) \ +static inline void glue(gen_f, name)(int rb, int rc) \ +{ \ + if (unlikely(rc == 31)) { \ + return; \ + } \ + if (rb != 31) { \ + gen_helper_ ## name (cpu_fir[rc], cpu_fir[rb]); \ + } else { \ + TCGv tmp = tcg_const_i64(0); \ + gen_helper_ ## name (cpu_fir[rc], tmp); \ + tcg_temp_free(tmp); \ + } \ } -FARITH2(sqrts) +FARITH2(cvtlq) +FARITH2(cvtql) +FARITH2(cvtql_v) +FARITH2(cvtql_sv) + +/* ??? VAX instruction qualifiers ignored. */ FARITH2(sqrtf) FARITH2(sqrtg) -FARITH2(sqrtt) FARITH2(cvtgf) FARITH2(cvtgq) FARITH2(cvtqf) FARITH2(cvtqg) -FARITH2(cvtst) -FARITH2(cvtts) -FARITH2(cvttq) -FARITH2(cvtqs) -FARITH2(cvtqt) -FARITH2(cvtlq) -FARITH2(cvtql) -FARITH2(cvtqlv) -FARITH2(cvtqlsv) - -#define FARITH3(name) \ -static inline void glue(gen_f, name)(int ra, int rb, int rc) \ -{ \ - if (unlikely(rc == 31)) \ - return; \ - \ - if (ra != 31) { \ - if (rb != 31) \ - gen_helper_ ## name (cpu_fir[rc], cpu_fir[ra], cpu_fir[rb]); \ - else { \ - TCGv tmp = tcg_const_i64(0); \ - gen_helper_ ## name (cpu_fir[rc], cpu_fir[ra], tmp); \ - tcg_temp_free(tmp); \ - } \ - } else { \ - TCGv tmp = tcg_const_i64(0); \ - if (rb != 31) \ - gen_helper_ ## name (cpu_fir[rc], tmp, cpu_fir[rb]); \ - else \ - gen_helper_ ## name (cpu_fir[rc], tmp, tmp); \ - tcg_temp_free(tmp); \ - } \ + +static void gen_ieee_arith2(DisasContext *ctx, void (*helper)(TCGv, TCGv), + int rb, int rc, int fn11) +{ + TCGv vb; + + /* ??? This is wrong: the instruction is not a nop, it still may + raise exceptions. */ + if (unlikely(rc == 31)) { + return; + } + + gen_qual_roundmode(ctx, fn11); + gen_qual_flushzero(ctx, fn11); + gen_fp_exc_clear(); + + vb = gen_ieee_input(rb, fn11, 0); + helper(cpu_fir[rc], vb); + tcg_temp_free(vb); + + gen_fp_exc_raise(rc, fn11); } +#define IEEE_ARITH2(name) \ +static inline void glue(gen_f, name)(DisasContext *ctx, \ + int rb, int rc, int fn11) \ +{ \ + gen_ieee_arith2(ctx, gen_helper_##name, rb, rc, fn11); \ +} +IEEE_ARITH2(sqrts) +IEEE_ARITH2(sqrtt) +IEEE_ARITH2(cvtst) +IEEE_ARITH2(cvtts) + +static void gen_fcvttq(DisasContext *ctx, int rb, int rc, int fn11) +{ + TCGv vb; + int ignore = 0; + + /* ??? This is wrong: the instruction is not a nop, it still may + raise exceptions. */ + if (unlikely(rc == 31)) { + return; + } + + /* No need to set flushzero, since we have an integer output. */ + gen_fp_exc_clear(); + vb = gen_ieee_input(rb, fn11, 0); + + /* Almost all integer conversions use cropped rounding, and most + also do not have integer overflow enabled. Special case that. */ + switch (fn11) { + case QUAL_RM_C: + gen_helper_cvttq_c(cpu_fir[rc], vb); + break; + case QUAL_V | QUAL_RM_C: + case QUAL_S | QUAL_V | QUAL_RM_C: + ignore = float_flag_inexact; + /* FALLTHRU */ + case QUAL_S | QUAL_V | QUAL_I | QUAL_RM_C: + gen_helper_cvttq_svic(cpu_fir[rc], vb); + break; + default: + gen_qual_roundmode(ctx, fn11); + gen_helper_cvttq(cpu_fir[rc], vb); + ignore |= (fn11 & QUAL_V ? 0 : float_flag_overflow); + ignore |= (fn11 & QUAL_I ? 0 : float_flag_inexact); + break; + } + tcg_temp_free(vb); + + gen_fp_exc_raise_ignore(rc, fn11, ignore); +} + +static void gen_ieee_intcvt(DisasContext *ctx, void (*helper)(TCGv, TCGv), + int rb, int rc, int fn11) +{ + TCGv vb; + + /* ??? This is wrong: the instruction is not a nop, it still may + raise exceptions. */ + if (unlikely(rc == 31)) { + return; + } + + gen_qual_roundmode(ctx, fn11); + + if (rb == 31) { + vb = tcg_const_i64(0); + } else { + vb = cpu_fir[rb]; + } + + /* The only exception that can be raised by integer conversion + is inexact. Thus we only need to worry about exceptions when + inexact handling is requested. */ + if (fn11 & QUAL_I) { + gen_fp_exc_clear(); + helper(cpu_fir[rc], vb); + gen_fp_exc_raise(rc, fn11); + } else { + helper(cpu_fir[rc], vb); + } + + if (rb == 31) { + tcg_temp_free(vb); + } +} + +#define IEEE_INTCVT(name) \ +static inline void glue(gen_f, name)(DisasContext *ctx, \ + int rb, int rc, int fn11) \ +{ \ + gen_ieee_intcvt(ctx, gen_helper_##name, rb, rc, fn11); \ +} +IEEE_INTCVT(cvtqs) +IEEE_INTCVT(cvtqt) + +#define FARITH3(name) \ +static inline void glue(gen_f, name)(int ra, int rb, int rc) \ +{ \ + TCGv va, vb; \ + \ + if (unlikely(rc == 31)) { \ + return; \ + } \ + if (ra == 31) { \ + va = tcg_const_i64(0); \ + } else { \ + va = cpu_fir[ra]; \ + } \ + if (rb == 31) { \ + vb = tcg_const_i64(0); \ + } else { \ + vb = cpu_fir[rb]; \ + } \ + \ + gen_helper_ ## name (cpu_fir[rc], va, vb); \ + \ + if (ra == 31) { \ + tcg_temp_free(va); \ + } \ + if (rb == 31) { \ + tcg_temp_free(vb); \ + } \ +} +/* ??? Ought to expand these inline; simple masking operations. */ +FARITH3(cpys) +FARITH3(cpysn) +FARITH3(cpyse) + +/* ??? VAX instruction qualifiers ignored. */ FARITH3(addf) FARITH3(subf) FARITH3(mulf) @@ -509,21 +786,80 @@ FARITH3(divg) FARITH3(cmpgeq) FARITH3(cmpglt) FARITH3(cmpgle) -FARITH3(adds) -FARITH3(subs) -FARITH3(muls) -FARITH3(divs) -FARITH3(addt) -FARITH3(subt) -FARITH3(mult) -FARITH3(divt) -FARITH3(cmptun) -FARITH3(cmpteq) -FARITH3(cmptlt) -FARITH3(cmptle) -FARITH3(cpys) -FARITH3(cpysn) -FARITH3(cpyse) + +static void gen_ieee_arith3(DisasContext *ctx, + void (*helper)(TCGv, TCGv, TCGv), + int ra, int rb, int rc, int fn11) +{ + TCGv va, vb; + + /* ??? This is wrong: the instruction is not a nop, it still may + raise exceptions. */ + if (unlikely(rc == 31)) { + return; + } + + gen_qual_roundmode(ctx, fn11); + gen_qual_flushzero(ctx, fn11); + gen_fp_exc_clear(); + + va = gen_ieee_input(ra, fn11, 0); + vb = gen_ieee_input(rb, fn11, 0); + helper(cpu_fir[rc], va, vb); + tcg_temp_free(va); + tcg_temp_free(vb); + + gen_fp_exc_raise(rc, fn11); +} + +#define IEEE_ARITH3(name) \ +static inline void glue(gen_f, name)(DisasContext *ctx, \ + int ra, int rb, int rc, int fn11) \ +{ \ + gen_ieee_arith3(ctx, gen_helper_##name, ra, rb, rc, fn11); \ +} +IEEE_ARITH3(adds) +IEEE_ARITH3(subs) +IEEE_ARITH3(muls) +IEEE_ARITH3(divs) +IEEE_ARITH3(addt) +IEEE_ARITH3(subt) +IEEE_ARITH3(mult) +IEEE_ARITH3(divt) + +static void gen_ieee_compare(DisasContext *ctx, + void (*helper)(TCGv, TCGv, TCGv), + int ra, int rb, int rc, int fn11) +{ + TCGv va, vb; + + /* ??? This is wrong: the instruction is not a nop, it still may + raise exceptions. */ + if (unlikely(rc == 31)) { + return; + } + + gen_fp_exc_clear(); + + va = gen_ieee_input(ra, fn11, 1); + vb = gen_ieee_input(rb, fn11, 1); + helper(cpu_fir[rc], va, vb); + tcg_temp_free(va); + tcg_temp_free(vb); + + gen_fp_exc_raise(rc, fn11); +} + +#define IEEE_CMP3(name) \ +static inline void glue(gen_f, name)(DisasContext *ctx, \ + int ra, int rb, int rc, int fn11) \ +{ \ + gen_ieee_compare(ctx, gen_helper_##name, ra, rb, rc, fn11); \ +} +IEEE_CMP3(cmptun) +IEEE_CMP3(cmpteq) +IEEE_CMP3(cmptlt) +IEEE_CMP3(cmptle) static inline uint64_t zapnot_mask(uint8_t lit) { @@ -1607,7 +1943,7 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn) } break; case 0x14: - switch (fpfn) { /* f11 & 0x3F */ + switch (fpfn) { /* fn11 & 0x3F */ case 0x04: /* ITOFS */ if (!(ctx->amask & AMASK_FIX)) @@ -1632,7 +1968,7 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn) /* SQRTS */ if (!(ctx->amask & AMASK_FIX)) goto invalid_opc; - gen_fsqrts(rb, rc); + gen_fsqrts(ctx, rb, rc, fn11); break; case 0x14: /* ITOFF */ @@ -1669,7 +2005,7 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn) /* SQRTT */ if (!(ctx->amask & AMASK_FIX)) goto invalid_opc; - gen_fsqrtt(rb, rc); + gen_fsqrtt(ctx, rb, rc, fn11); break; default: goto invalid_opc; @@ -1678,7 +2014,7 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn) case 0x15: /* VAX floating point */ /* XXX: rounding mode and trap are ignored (!) */ - switch (fpfn) { /* f11 & 0x3F */ + switch (fpfn) { /* fn11 & 0x3F */ case 0x00: /* ADDF */ gen_faddf(ra, rb, rc); @@ -1761,77 +2097,75 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn) break; case 0x16: /* IEEE floating-point */ - /* XXX: rounding mode and traps are ignored (!) */ - switch (fpfn) { /* f11 & 0x3F */ + switch (fpfn) { /* fn11 & 0x3F */ case 0x00: /* ADDS */ - gen_fadds(ra, rb, rc); + gen_fadds(ctx, ra, rb, rc, fn11); break; case 0x01: /* SUBS */ - gen_fsubs(ra, rb, rc); + gen_fsubs(ctx, ra, rb, rc, fn11); break; case 0x02: /* MULS */ - gen_fmuls(ra, rb, rc); + gen_fmuls(ctx, ra, rb, rc, fn11); break; case 0x03: /* DIVS */ - gen_fdivs(ra, rb, rc); + gen_fdivs(ctx, ra, rb, rc, fn11); break; case 0x20: /* ADDT */ - gen_faddt(ra, rb, rc); + gen_faddt(ctx, ra, rb, rc, fn11); break; case 0x21: /* SUBT */ - gen_fsubt(ra, rb, rc); + gen_fsubt(ctx, ra, rb, rc, fn11); break; case 0x22: /* MULT */ - gen_fmult(ra, rb, rc); + gen_fmult(ctx, ra, rb, rc, fn11); break; case 0x23: /* DIVT */ - gen_fdivt(ra, rb, rc); + gen_fdivt(ctx, ra, rb, rc, fn11); break; case 0x24: /* CMPTUN */ - gen_fcmptun(ra, rb, rc); + gen_fcmptun(ctx, ra, rb, rc, fn11); break; case 0x25: /* CMPTEQ */ - gen_fcmpteq(ra, rb, rc); + gen_fcmpteq(ctx, ra, rb, rc, fn11); break; case 0x26: /* CMPTLT */ - gen_fcmptlt(ra, rb, rc); + gen_fcmptlt(ctx, ra, rb, rc, fn11); break; case 0x27: /* CMPTLE */ - gen_fcmptle(ra, rb, rc); + gen_fcmptle(ctx, ra, rb, rc, fn11); break; case 0x2C: - /* XXX: incorrect */ if (fn11 == 0x2AC || fn11 == 0x6AC) { /* CVTST */ - gen_fcvtst(rb, rc); + gen_fcvtst(ctx, rb, rc, fn11); } else { /* CVTTS */ - gen_fcvtts(rb, rc); + gen_fcvtts(ctx, rb, rc, fn11); } break; case 0x2F: /* CVTTQ */ - gen_fcvttq(rb, rc); + gen_fcvttq(ctx, rb, rc, fn11); break; case 0x3C: /* CVTQS */ - gen_fcvtqs(rb, rc); + gen_fcvtqs(ctx, rb, rc, fn11); break; case 0x3E: /* CVTQT */ - gen_fcvtqt(rb, rc); + gen_fcvtqt(ctx, rb, rc, fn11); break; default: goto invalid_opc; @@ -1910,11 +2244,11 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn) break; case 0x130: /* CVTQL/V */ - gen_fcvtqlv(rb, rc); + gen_fcvtql_v(rb, rc); break; case 0x530: /* CVTQL/SV */ - gen_fcvtqlsv(rb, rc); + gen_fcvtql_sv(rb, rc); break; default: goto invalid_opc; @@ -2597,6 +2931,17 @@ static inline void gen_intermediate_code_internal(CPUState *env, ctx.mem_idx = ((env->ps >> 3) & 3); ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1; #endif + + /* ??? Every TB begins with unset rounding mode, to be initialized on + the first fp insn of the TB. Alternately we could define a proper + default for every TB (e.g. QUAL_RM_N or QUAL_RM_D) and make sure + to reset the FP_STATUS to that default at the end of any TB that + changes the default. We could even (gasp) dynamiclly figure out + what default would be most efficient given the running program. */ + ctx.tb_rm = -1; + /* Similarly for flush-to-zero. */ + ctx.tb_ftz = -1; + num_insns = 0; max_insns = tb->cflags & CF_COUNT_MASK; if (max_insns == 0) @@ -2721,7 +3066,6 @@ static const struct cpu_def_t cpu_defs[] = { CPUAlphaState * cpu_alpha_init (const char *cpu_model) { CPUAlphaState *env; - uint64_t hwpcb; int implver, amask, i, max; env = qemu_mallocz(sizeof(CPUAlphaState)); @@ -2750,26 +3094,37 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model) env->ps |= 1 << 3; cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD | FPCR_UNFD | FPCR_INED | FPCR_DNOD)); -#endif +#else pal_init(env); +#endif + /* Initialize IPR */ - hwpcb = env->ipr[IPR_PCBB]; - env->ipr[IPR_ASN] = 0; - env->ipr[IPR_ASTEN] = 0; - env->ipr[IPR_ASTSR] = 0; - env->ipr[IPR_DATFX] = 0; - /* XXX: fix this */ - // env->ipr[IPR_ESP] = ldq_raw(hwpcb + 8); - // env->ipr[IPR_KSP] = ldq_raw(hwpcb + 0); - // env->ipr[IPR_SSP] = ldq_raw(hwpcb + 16); - // env->ipr[IPR_USP] = ldq_raw(hwpcb + 24); - env->ipr[IPR_FEN] = 0; - env->ipr[IPR_IPL] = 31; - env->ipr[IPR_MCES] = 0; - env->ipr[IPR_PERFMON] = 0; /* Implementation specific */ - // env->ipr[IPR_PTBR] = ldq_raw(hwpcb + 32); - env->ipr[IPR_SISR] = 0; - env->ipr[IPR_VIRBND] = -1ULL; +#if defined (CONFIG_USER_ONLY) + env->ipr[IPR_EXC_ADDR] = 0; + env->ipr[IPR_EXC_SUM] = 0; + env->ipr[IPR_EXC_MASK] = 0; +#else + { + uint64_t hwpcb; + hwpcb = env->ipr[IPR_PCBB]; + env->ipr[IPR_ASN] = 0; + env->ipr[IPR_ASTEN] = 0; + env->ipr[IPR_ASTSR] = 0; + env->ipr[IPR_DATFX] = 0; + /* XXX: fix this */ + // env->ipr[IPR_ESP] = ldq_raw(hwpcb + 8); + // env->ipr[IPR_KSP] = ldq_raw(hwpcb + 0); + // env->ipr[IPR_SSP] = ldq_raw(hwpcb + 16); + // env->ipr[IPR_USP] = ldq_raw(hwpcb + 24); + env->ipr[IPR_FEN] = 0; + env->ipr[IPR_IPL] = 31; + env->ipr[IPR_MCES] = 0; + env->ipr[IPR_PERFMON] = 0; /* Implementation specific */ + // env->ipr[IPR_PTBR] = ldq_raw(hwpcb + 32); + env->ipr[IPR_SISR] = 0; + env->ipr[IPR_VIRBND] = -1ULL; + } +#endif qemu_init_vcpu(env); return env; diff --git a/target-i386/helper.c b/target-i386/helper.c index e595a3e2f..6d7390cfa 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -659,8 +659,9 @@ static void listflags(char *buf, int bufsize, uint32_t fbits, else nc = snprintf(q, bufsize, "%s[%d]", q == buf ? "" : " ", bit); if (bufsize <= nc) { - if (b) - sprintf(b, "..."); + if (b) { + memcpy(b, "...", sizeof("...")); + } return; } q += nc; @@ -778,7 +779,7 @@ static int cpu_x86_register (CPUX86State *env, const char *cpu_model) return 0; } -#if !defined(CONFIG_LINUX_USER) +#if !defined(CONFIG_USER_ONLY) /* copy vendor id string to 32 bit register, nul pad as needed */ static void cpyid(const char *s, uint32_t *id) @@ -881,7 +882,7 @@ static int cpudef_register(QemuOpts *opts, void *opaque) x86_defs = def; return (0); } -#endif /* !CONFIG_LINUX_USER */ +#endif /* !CONFIG_USER_ONLY */ /* register "cpudef" models defined in configuration file. Here we first * preload any built-in definitions @@ -895,7 +896,7 @@ void x86_cpudef_setup(void) builtin_x86_defs[i].flags = 1; x86_defs = &builtin_x86_defs[i]; } -#if !defined(CONFIG_LINUX_USER) +#if !defined(CONFIG_USER_ONLY) qemu_opts_foreach(&qemu_cpudef_opts, cpudef_register, NULL, 0); #endif } diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index fc735f4e9..6aba61c98 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -835,10 +835,10 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) #define CRF_GT 2 #define CRF_EQ 1 #define CRF_SO 0 -#define CRF_CH (1 << 4) -#define CRF_CL (1 << 3) -#define CRF_CH_OR_CL (1 << 2) -#define CRF_CH_AND_CL (1 << 1) +#define CRF_CH (1 << CRF_LT) +#define CRF_CL (1 << CRF_GT) +#define CRF_CH_OR_CL (1 << CRF_EQ) +#define CRF_CH_AND_CL (1 << CRF_SO) /* XER definitions */ #define XER_SO 31 diff --git a/target-ppc/translate.c b/target-ppc/translate.c index d4e81ce89..7c79665d0 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -7001,7 +7001,7 @@ static inline void gen_evmergelohi(DisasContext *ctx) } static inline void gen_evsplati(DisasContext *ctx) { - uint64_t imm = ((int32_t)(rA(ctx->opcode) << 11)) >> 27; + uint64_t imm = ((int32_t)(rA(ctx->opcode) << 27)) >> 27; #if defined(TARGET_PPC64) tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm); @@ -7012,7 +7012,7 @@ static inline void gen_evsplati(DisasContext *ctx) } static inline void gen_evsplatfi(DisasContext *ctx) { - uint64_t imm = rA(ctx->opcode) << 11; + uint64_t imm = rA(ctx->opcode) << 27; #if defined(TARGET_PPC64) tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm); @@ -9053,11 +9053,6 @@ static inline void gen_intermediate_code_internal(CPUState *env, "%02x - %02x - %02x (%08x) " TARGET_FMT_lx " %d\n", opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir); - } else { - printf("invalid/unsupported opcode: " - "%02x - %02x - %02x (%08x) " TARGET_FMT_lx " %d\n", - opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir); } } else { if (unlikely((ctx.opcode & handler->inval) != 0)) { @@ -9067,12 +9062,6 @@ static inline void gen_intermediate_code_internal(CPUState *env, ctx.opcode & handler->inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); - } else { - printf("invalid bits: %08x for opcode: " - "%02x - %02x - %02x (%08x) " TARGET_FMT_lx "\n", - ctx.opcode & handler->inval, opc1(ctx.opcode), - opc2(ctx.opcode), opc3(ctx.opcode), - ctx.opcode, ctx.nip - 4); } gen_inval_exception(ctxp, POWERPC_EXCP_INVAL_INVAL); break; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index b7d2a324c..1164feb88 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1680,7 +1680,7 @@ static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_ptr cpu_env) 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_ptr(r_tl_tmp); } tcg_temp_free_i32(r_tl); diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c index 96cc46190..b40246d41 100644 --- a/tcg/ppc/tcg-target.c +++ b/tcg/ppc/tcg-target.c @@ -328,6 +328,7 @@ static int tcg_target_const_match(tcg_target_long val, #define MULLI OPCD( 7) #define CMPLI OPCD(10) #define CMPI OPCD(11) +#define SUBFIC OPCD( 8) #define LWZU OPCD(33) #define STWU OPCD(37) @@ -1588,7 +1589,7 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, } } else { - tcg_out32 (s, ADDI | RT (0) | RA (args[2]) | 0xffe0); + tcg_out32 (s, SUBFIC | RT (0) | RA (args[2]) | 32); tcg_out32 (s, RLWNM | RA (args[0]) | RS (args[1]) |