summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2010-03-04 16:41:35 -0300
committerMarcelo Tosatti <mtosatti@redhat.com>2010-03-04 16:41:35 -0300
commite19ec919797ecf047ec805662850311b6a5298ee (patch)
treee4fb3679ef2fd8f6e85141d60c050e4f960881f0
parentca8773d10fa15cd00a754faa7f26091b81587df3 (diff)
parent6049f4f831c6f409031dfa09282b38d0cbaecad8 (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--Makefile2
-rw-r--r--Makefile.target3
-rw-r--r--arm-dis.c8
-rw-r--r--audio/alsaaudio.c6
-rw-r--r--default-configs/arm-softmmu.mak4
-rw-r--r--fpu/softfloat.h1
-rw-r--r--gdbstub.c116
-rw-r--r--hw/alpha_palcode.c81
-rw-r--r--hw/ppc440_bamboo.c19
-rw-r--r--hw/ppce500_mpc8544ds.c33
-rw-r--r--hw/usb-bus.c3
-rw-r--r--hw/usb-msd.c3
-rw-r--r--hw/usb-net.c3
-rw-r--r--hw/usb-serial.c3
-rw-r--r--kvm.h2
-rw-r--r--linux-user/alpha/target_signal.h27
-rw-r--r--linux-user/main.c141
-rw-r--r--linux-user/signal.c267
-rw-r--r--linux-user/syscall.c61
-rw-r--r--linux-user/syscall_defs.h23
-rw-r--r--qemu-char.c3
-rw-r--r--qemu-malloc.c8
-rw-r--r--qemu-options.hx2
-rw-r--r--target-alpha/cpu.h44
-rw-r--r--target-alpha/helper.c161
-rw-r--r--target-alpha/helper.h21
-rw-r--r--target-alpha/op_helper.c275
-rw-r--r--target-alpha/translate.c569
-rw-r--r--target-i386/helper.c11
-rw-r--r--target-ppc/cpu.h8
-rw-r--r--target-ppc/translate.c15
-rw-r--r--target-sparc/translate.c2
-rw-r--r--tcg/ppc/tcg-target.c3
33 files changed, 1495 insertions, 433 deletions
diff --git a/Makefile b/Makefile
index 296f50009..14c1930b7 100644
--- a/Makefile
+++ b/Makefile
@@ -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 $@ $<
diff --git a/arm-dis.c b/arm-dis.c
index 2c67d8fca..4fb899e38 100644
--- a/arm-dis.c
+++ b/arm-dis.c
@@ -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
diff --git a/gdbstub.c b/gdbstub.c
index 6e61eddaf..9fd80b115 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -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);
diff --git a/kvm.h b/kvm.h
index c1c1ae80e..b0d07c890 100644
--- a/kvm.h
+++ b/kvm.h
@@ -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])