diff options
45 files changed, 837 insertions, 574 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 780f480725..93ad19d90e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -781,6 +781,7 @@ Tiny Code Generator (TCG) ------------------------- Common code M: qemu-devel@nongnu.org +M: Richard Henderson <rth@twiddle.net> S: Maintained F: tcg/ @@ -3445,6 +3445,36 @@ if test "$cpu" = "s390x" ; then roms="$roms s390-ccw" fi +# Probe for the need for relocating the user-only binary. +if test "$pie" = "no" ; then + textseg_addr= + case "$cpu" in + arm | hppa | i386 | m68k | ppc | ppc64 | s390* | sparc | sparc64 | x86_64) + textseg_addr=0x60000000 + ;; + mips) + textseg_addr=0x400000 + ;; + esac + if [ -n "$textseg_addr" ]; then + cat > $TMPC <<EOF + int main(void) { return 0; } +EOF + textseg_ldflags="-Wl,-Ttext-segment=$textseg_addr" + if ! compile_prog "" "$textseg_ldflags"; then + # In case ld does not support -Ttext-segment, edit the default linker + # script via sed to set the .text start addr. This is needed on FreeBSD + # at least. + $ld --verbose | sed \ + -e '1,/==================================================/d' \ + -e '/==================================================/,$d' \ + -e "s/[.] = [0-9a-fx]* [+] SIZEOF_HEADERS/. = $textseg_addr + SIZEOF_HEADERS/" \ + -e "s/__executable_start = [0-9a-fx]*/__executable_start = $textseg_addr/" > config-host.ld + textseg_ldflags="-Wl,-T../config-host.ld" + fi + fi +fi + # add pixman flags after all config tests are done QEMU_CFLAGS="$QEMU_CFLAGS $pixman_cflags $fdt_cflags" libs_softmmu="$libs_softmmu $pixman_libs" @@ -4073,9 +4103,6 @@ if test "$gcov" = "yes" ; then echo "GCOV=$gcov_tool" >> $config_host_mak fi -# generate list of library paths for linker script -$ld --verbose -v 2> /dev/null | grep SEARCH_DIR > config-host.ld - # use included Linux headers if test "$linux" = "yes" ; then mkdir -p linux-headers @@ -4438,21 +4465,8 @@ if test "$gprof" = "yes" ; then fi fi -if test "$ARCH" = "tci"; then - linker_script="" -else - linker_script="-Wl,-T../config-host.ld -Wl,-T,\$(SRC_PATH)/ldscripts/\$(ARCH).ld" -fi - if test "$target_linux_user" = "yes" -o "$target_bsd_user" = "yes" ; then - case "$ARCH" in - alpha | s390x | aarch64) - # The default placement of the application is fine. - ;; - *) - ldflags="$linker_script $ldflags" - ;; - esac + ldflags="$ldflags $textseg_ldflags" fi echo "LDFLAGS+=$ldflags" >> $config_target_mak diff --git a/device_tree.c b/device_tree.c index 69be9da8e4..10cf3d0b60 100644 --- a/device_tree.c +++ b/device_tree.c @@ -21,6 +21,7 @@ #include "config.h" #include "qemu-common.h" #include "sysemu/device_tree.h" +#include "sysemu/sysemu.h" #include "hw/loader.h" #include "qemu/option.h" #include "qemu/config-file.h" @@ -239,15 +240,8 @@ uint32_t qemu_devtree_alloc_phandle(void *fdt) * which phandle id to start allocting phandles. */ if (!phandle) { - QemuOpts *machine_opts; - machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); - if (machine_opts) { - const char *phandle_start; - phandle_start = qemu_opt_get(machine_opts, "phandle_start"); - if (phandle_start) { - phandle = strtoul(phandle_start, NULL, 0); - } - } + phandle = qemu_opt_get_number(qemu_get_machine_opts(), + "phandle_start", 0); } if (!phandle) { @@ -307,15 +301,10 @@ int qemu_devtree_add_subnode(void *fdt, const char *name) void qemu_devtree_dumpdtb(void *fdt, int size) { - QemuOpts *machine_opts; - - machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); - if (machine_opts) { - const char *dumpdtb = qemu_opt_get(machine_opts, "dumpdtb"); - if (dumpdtb) { - /* Dump the dtb to a file and quit */ - exit(g_file_set_contents(dumpdtb, fdt, size, NULL) ? 0 : 1); - } - } + const char *dumpdtb = qemu_opt_get(qemu_get_machine_opts(), "dumpdtb"); + if (dumpdtb) { + /* Dump the dtb to a file and quit */ + exit(g_file_set_contents(dumpdtb, fdt, size, NULL) ? 0 : 1); + } } @@ -31,6 +31,7 @@ #include "hw/qdev.h" #include "qemu/osdep.h" #include "sysemu/kvm.h" +#include "sysemu/sysemu.h" #include "hw/xen/xen.h" #include "qemu/timer.h" #include "qemu/config-file.h" @@ -53,7 +54,6 @@ //#define DEBUG_SUBPAGE #if !defined(CONFIG_USER_ONLY) -int phys_ram_fd; static int in_migration; RAMList ram_list = { .blocks = QTAILQ_HEAD_INITIALIZER(ram_list.blocks) }; @@ -1039,12 +1039,10 @@ ram_addr_t last_ram_offset(void) static void qemu_ram_setup_dump(void *addr, ram_addr_t size) { int ret; - QemuOpts *machine_opts; /* Use MADV_DONTDUMP, if user doesn't want the guest memory in the core */ - machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); - if (machine_opts && - !qemu_opt_get_bool(machine_opts, "dump-guest-core", true)) { + if (!qemu_opt_get_bool(qemu_get_machine_opts(), + "dump-guest-core", true)) { ret = qemu_madvise(addr, size, QEMU_MADV_DONTDUMP); if (ret) { perror("qemu_madvise"); @@ -1091,10 +1089,7 @@ void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev) static int memory_try_enable_merging(void *addr, size_t len) { - QemuOpts *opts; - - opts = qemu_opts_find(qemu_find_opts("machine"), 0); - if (opts && !qemu_opt_get_bool(opts, "mem-merge", true)) { + if (!qemu_opt_get_bool(qemu_get_machine_opts(), "mem-merge", true)) { /* disabled by the user */ return 0; } diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c index 6eaf36dbfa..ccfec139ab 100644 --- a/fsdev/qemu-fsdev.c +++ b/fsdev/qemu-fsdev.c @@ -76,6 +76,8 @@ int qemu_fsdev_add(QemuOpts *opts) if (fsle->fse.ops->parse_opts) { if (fsle->fse.ops->parse_opts(opts, &fsle->fse)) { + g_free(fsle->fse.fsdev_id); + g_free(fsle); return -1; } } diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index dc6f4e404f..35e2af47b2 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -68,14 +68,14 @@ static int virtio_9p_device_init(VirtIODevice *vdev) fprintf(stderr, "Virtio-9p device couldn't find fsdev with the " "id = %s\n", s->fsconf.fsdev_id ? s->fsconf.fsdev_id : "NULL"); - return -1; + goto out; } if (!s->fsconf.tag) { /* we haven't specified a mount_tag */ fprintf(stderr, "fsdev with id %s needs mount_tag arguments\n", s->fsconf.fsdev_id); - return -1; + goto out; } s->ctx.export_flags = fse->export_flags; @@ -85,10 +85,10 @@ static int virtio_9p_device_init(VirtIODevice *vdev) if (len > MAX_TAG_LEN - 1) { fprintf(stderr, "mount tag '%s' (%d bytes) is longer than " "maximum (%d bytes)", s->fsconf.tag, len, MAX_TAG_LEN - 1); - return -1; + goto out; } - s->tag = strdup(s->fsconf.tag); + s->tag = g_strdup(s->fsconf.tag); s->ctx.uid = -1; s->ops = fse->ops; @@ -99,11 +99,11 @@ static int virtio_9p_device_init(VirtIODevice *vdev) if (s->ops->init(&s->ctx) < 0) { fprintf(stderr, "Virtio-9p Failed to initialize fs-driver with id:%s" " and export path:%s\n", s->fsconf.fsdev_id, s->ctx.fs_root); - return -1; + goto out; } if (v9fs_init_worker_threads() < 0) { fprintf(stderr, "worker thread initialization failed\n"); - return -1; + goto out; } /* @@ -115,18 +115,26 @@ static int virtio_9p_device_init(VirtIODevice *vdev) if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) { fprintf(stderr, "error in converting name to path %s", strerror(errno)); - return -1; + goto out; } if (s->ops->lstat(&s->ctx, &path, &stat)) { fprintf(stderr, "share path %s does not exist\n", fse->path); - return -1; + goto out; } else if (!S_ISDIR(stat.st_mode)) { fprintf(stderr, "share path %s is not a directory\n", fse->path); - return -1; + goto out; } v9fs_path_free(&path); return 0; +out: + g_free(s->ctx.fs_root); + g_free(s->tag); + virtio_cleanup(vdev); + v9fs_path_free(&path); + + return -1; + } /* virtio-9p device */ diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 2b33444cf1..a2e4032f42 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -359,7 +359,6 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) uint64_t elf_entry; hwaddr entry; int big_endian; - QemuOpts *machine_opts; /* Load the kernel. */ if (!info->kernel_filename) { @@ -367,12 +366,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) exit(1); } - machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); - if (machine_opts) { - info->dtb_filename = qemu_opt_get(machine_opts, "dtb"); - } else { - info->dtb_filename = NULL; - } + info->dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb"); if (!info->secondary_cpu_reset_hook) { info->secondary_cpu_reset_hook = default_reset_secondary; diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c index 6df0fa916d..c98e447533 100644 --- a/hw/i2c/pm_smbus.c +++ b/hw/i2c/pm_smbus.c @@ -32,6 +32,18 @@ #define SMBHSTDAT1 0x06 #define SMBBLKDAT 0x07 +#define STS_HOST_BUSY (1) +#define STS_INTR (1<<1) +#define STS_DEV_ERR (1<<2) +#define STS_BUS_ERR (1<<3) +#define STS_FAILED (1<<4) +#define STS_SMBALERT (1<<5) +#define STS_INUSE_STS (1<<6) +#define STS_BYTE_DONE (1<<7) +/* Signs of successfully transaction end : +* ByteDoneStatus = 1 (STS_BYTE_DONE) and INTR = 1 (STS_INTR ) +*/ + //#define DEBUG #ifdef DEBUG @@ -50,9 +62,14 @@ static void smb_transaction(PMSMBus *s) i2c_bus *bus = s->smbus; SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot); + /* Transaction isn't exec if STS_DEV_ERR bit set */ + if ((s->smb_stat & STS_DEV_ERR) != 0) { + goto error; + } switch(prot) { case 0x0: smbus_quick_command(bus, addr, read); + s->smb_stat |= STS_BYTE_DONE | STS_INTR; break; case 0x1: if (read) { @@ -60,6 +77,7 @@ static void smb_transaction(PMSMBus *s) } else { smbus_send_byte(bus, addr, cmd); } + s->smb_stat |= STS_BYTE_DONE | STS_INTR; break; case 0x2: if (read) { @@ -67,6 +85,7 @@ static void smb_transaction(PMSMBus *s) } else { smbus_write_byte(bus, addr, cmd, s->smb_data0); } + s->smb_stat |= STS_BYTE_DONE | STS_INTR; break; case 0x3: if (read) { @@ -77,6 +96,7 @@ static void smb_transaction(PMSMBus *s) } else { smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0); } + s->smb_stat |= STS_BYTE_DONE | STS_INTR; break; case 0x5: if (read) { @@ -84,6 +104,7 @@ static void smb_transaction(PMSMBus *s) } else { smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0); } + s->smb_stat |= STS_BYTE_DONE | STS_INTR; break; default: goto error; @@ -91,7 +112,7 @@ static void smb_transaction(PMSMBus *s) return; error: - s->smb_stat |= 0x04; + s->smb_stat |= STS_DEV_ERR; } static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, @@ -102,7 +123,7 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, SMBUS_DPRINTF("SMB writeb port=0x%04x val=0x%02x\n", addr, val); switch(addr) { case SMBHSTSTS: - s->smb_stat = 0; + s->smb_stat = (~(val & 0xff)) & s->smb_stat; s->smb_index = 0; break; case SMBHSTCNT: diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c index 3f1d70ef9b..5b057f7880 100644 --- a/hw/microblaze/boot.c +++ b/hw/microblaze/boot.c @@ -28,6 +28,7 @@ #include "qemu/config-file.h" #include "qemu-common.h" #include "sysemu/device_tree.h" +#include "sysemu/sysemu.h" #include "hw/loader.h" #include "elf.h" @@ -93,20 +94,18 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, void (*machine_cpu_reset)(MicroBlazeCPU *)) { QemuOpts *machine_opts; - const char *kernel_filename = NULL; - const char *kernel_cmdline = NULL; - - machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); - if (machine_opts) { - const char *dtb_arg; - kernel_filename = qemu_opt_get(machine_opts, "kernel"); - kernel_cmdline = qemu_opt_get(machine_opts, "append"); - dtb_arg = qemu_opt_get(machine_opts, "dtb"); - if (dtb_arg) { /* Preference a -dtb argument */ - dtb_filename = dtb_arg; - } else { /* default to pcbios dtb as passed by machine_init */ - dtb_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename); - } + const char *kernel_filename; + const char *kernel_cmdline; + const char *dtb_arg; + + machine_opts = qemu_get_machine_opts(); + kernel_filename = qemu_opt_get(machine_opts, "kernel"); + kernel_cmdline = qemu_opt_get(machine_opts, "append"); + dtb_arg = qemu_opt_get(machine_opts, "dtb"); + if (dtb_arg) { /* Preference a -dtb argument */ + dtb_filename = dtb_arg; + } else { /* default to pcbios dtb as passed by machine_init */ + dtb_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename); } boot_info.machine_cpu_reset = machine_cpu_reset; diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 960059930f..f00a62a1ca 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -137,7 +137,6 @@ static int ppce500_load_device_tree(CPUPPCState *env, uint32_t clock_freq = 400000000; uint32_t tb_freq = 400000000; int i; - const char *toplevel_compat = NULL; /* user override */ char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus"; char soc[128]; char mpic[128]; @@ -158,14 +157,9 @@ static int ppce500_load_device_tree(CPUPPCState *env, 0x0, 0xe1000000, 0x0, 0x10000, }; - QemuOpts *machine_opts; - const char *dtb_file = NULL; - - machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); - if (machine_opts) { - dtb_file = qemu_opt_get(machine_opts, "dtb"); - toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible"); - } + QemuOpts *machine_opts = qemu_get_machine_opts(); + const char *dtb_file = qemu_opt_get(machine_opts, "dtb"); + const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible"); if (dtb_file) { char *filename; @@ -525,7 +519,6 @@ static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params, static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr, qemu_irq **irqs) { - QemuOptsList *list; qemu_irq *mpic; DeviceState *dev = NULL; SysBusDevice *s; @@ -534,15 +527,11 @@ static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr, mpic = g_new(qemu_irq, 256); if (kvm_enabled()) { - bool irqchip_allowed = true, irqchip_required = false; - - list = qemu_find_opts("machine"); - if (!QTAILQ_EMPTY(&list->head)) { - irqchip_allowed = qemu_opt_get_bool(QTAILQ_FIRST(&list->head), + QemuOpts *machine_opts = qemu_get_machine_opts(); + bool irqchip_allowed = qemu_opt_get_bool(machine_opts, "kernel_irqchip", true); - irqchip_required = qemu_opt_get_bool(QTAILQ_FIRST(&list->head), - "kernel_irqchip", false); - } + bool irqchip_required = qemu_opt_get_bool(machine_opts, + "kernel_irqchip", false); if (irqchip_allowed) { dev = ppce500_init_mpic_kvm(params, irqs); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index e46aad30d9..5c31ad36bd 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -675,27 +675,19 @@ static void spapr_cpu_reset(void *opaque) static void spapr_create_nvram(sPAPREnvironment *spapr) { - QemuOpts *machine_opts; - DeviceState *dev; + DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram"); + const char *drivename = qemu_opt_get(qemu_get_machine_opts(), "nvram"); - dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram"); + if (drivename) { + BlockDriverState *bs; - machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); - if (machine_opts) { - const char *drivename; - - drivename = qemu_opt_get(machine_opts, "nvram"); - if (drivename) { - BlockDriverState *bs; - - bs = bdrv_find(drivename); - if (!bs) { - fprintf(stderr, "No such block device \"%s\" for nvram\n", - drivename); - exit(1); - } - qdev_prop_set_drive_nofail(dev, "drive", bs); + bs = bdrv_find(drivename); + if (!bs) { + fprintf(stderr, "No such block device \"%s\" for nvram\n", + drivename); + exit(1); } + qdev_prop_set_drive_nofail(dev, "drive", bs); } qdev_init_nofail(dev); diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 6499cd0f2e..5084202217 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -443,7 +443,6 @@ hwaddr cpu_get_phys_page_debug(CPUArchState *env, target_ulong addr); /* memory API */ -extern int phys_ram_fd; extern ram_addr_t ram_size; /* RAM is pre-allocated and passed into qemu_ram_alloc_from_ptr */ diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 2fb71afa25..d85bdc0cac 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -185,6 +185,8 @@ char *get_boot_devices_list(size_t *size); DeviceState *get_boot_device(uint32_t position); +QemuOpts *qemu_get_machine_opts(void); + bool usb_enabled(bool default_usb); extern QemuOptsList qemu_drive_opts; @@ -1288,12 +1288,9 @@ int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq) static int kvm_irqchip_create(KVMState *s) { - QemuOptsList *list = qemu_find_opts("machine"); int ret; - if (QTAILQ_EMPTY(&list->head) || - !qemu_opt_get_bool(QTAILQ_FIRST(&list->head), - "kernel_irqchip", true) || + if (!qemu_opt_get_bool(qemu_get_machine_opts(), "kernel_irqchip", true) || !kvm_check_extension(s, KVM_CAP_IRQCHIP)) { return 0; } diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 8a4776756a..439c2a9e32 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -88,8 +88,6 @@ #endif IOCTL(SIOCATMARK, 0, TYPE_NULL) - IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry))) - IOCTL(SIOCDELRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry))) IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(SIOCGIFFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) IOCTL(SIOCSIFFLAGS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) @@ -379,3 +377,7 @@ MK_PTR(MK_STRUCT(STRUCT_dm_ioctl))) IOCTL_SPECIAL(DM_DEV_SET_GEOMETRY, IOC_RW, do_ioctl_dm, MK_PTR(MK_STRUCT(STRUCT_dm_ioctl))) + IOCTL_SPECIAL(SIOCADDRT, IOC_W, do_ioctl_rt, + MK_PTR(MK_STRUCT(STRUCT_rtentry))) + IOCTL_SPECIAL(SIOCDELRT, IOC_W, do_ioctl_rt, + MK_PTR(MK_STRUCT(STRUCT_rtentry))) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index b412e3fe0a..de2219768d 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -483,6 +483,10 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, if (!(flags & MAP_ANONYMOUS)) { p = mmap(g2h(start), len, prot, flags | MAP_FIXED, fd, host_offset); + if (p == MAP_FAILED) { + munmap(g2h(start), host_len); + goto fail; + } host_start += offset - host_offset; } start = h2g(host_start); diff --git a/linux-user/signal.c b/linux-user/signal.c index 42d8911070..d0727becc2 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -102,14 +102,14 @@ static inline int sas_ss_flags(unsigned long sp) int host_to_target_signal(int sig) { - if (sig >= _NSIG) + if (sig < 0 || sig >= _NSIG) return sig; return host_to_target_signal_table[sig]; } int target_to_host_signal(int sig) { - if (sig >= _NSIG) + if (sig < 0 || sig >= _NSIG) return sig; return target_to_host_signal_table[sig]; } diff --git a/linux-user/socket.h b/linux-user/socket.h index 339cae5a16..ae17959902 100644 --- a/linux-user/socket.h +++ b/linux-user/socket.h @@ -1,91 +1,104 @@ #if defined(TARGET_MIPS) - // MIPS special values for constants - - /* - * For setsockopt(2) - * - * This defines are ABI conformant as far as Linux supports these ... - */ - #define TARGET_SOL_SOCKET 0xffff - - #define TARGET_SO_DEBUG 0x0001 /* Record debugging information. */ - #define TARGET_SO_REUSEADDR 0x0004 /* Allow reuse of local addresses. */ - #define TARGET_SO_KEEPALIVE 0x0008 /* Keep connections alive and send - SIGPIPE when they die. */ - #define TARGET_SO_DONTROUTE 0x0010 /* Don't do local routing. */ - #define TARGET_SO_BROADCAST 0x0020 /* Allow transmission of - broadcast messages. */ - #define TARGET_SO_LINGER 0x0080 /* Block on close of a reliable - socket to transmit pending data. */ - #define TARGET_SO_OOBINLINE 0x0100 /* Receive out-of-band data in-band. */ - #if 0 - To add: #define TARGET_SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ - #endif - - #define TARGET_SO_TYPE 0x1008 /* Compatible name for SO_STYLE. */ - #define TARGET_SO_STYLE SO_TYPE /* Synonym */ - #define TARGET_SO_ERROR 0x1007 /* get error status and clear */ - #define TARGET_SO_SNDBUF 0x1001 /* Send buffer size. */ - #define TARGET_SO_RCVBUF 0x1002 /* Receive buffer. */ - #define TARGET_SO_SNDLOWAT 0x1003 /* send low-water mark */ - #define TARGET_SO_RCVLOWAT 0x1004 /* receive low-water mark */ - #define TARGET_SO_SNDTIMEO 0x1005 /* send timeout */ - #define TARGET_SO_RCVTIMEO 0x1006 /* receive timeout */ - #define TARGET_SO_ACCEPTCONN 0x1009 - - /* linux-specific, might as well be the same as on i386 */ - #define TARGET_SO_NO_CHECK 11 - #define TARGET_SO_PRIORITY 12 - #define TARGET_SO_BSDCOMPAT 14 - - #define TARGET_SO_PASSCRED 17 - #define TARGET_SO_PEERCRED 18 - - /* Security levels - as per NRL IPv6 - don't actually do anything */ - #define TARGET_SO_SECURITY_AUTHENTICATION 22 - #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23 - #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24 - - #define TARGET_SO_BINDTODEVICE 25 - - /* Socket filtering */ - #define TARGET_SO_ATTACH_FILTER 26 - #define TARGET_SO_DETACH_FILTER 27 - - #define TARGET_SO_PEERNAME 28 - #define TARGET_SO_TIMESTAMP 29 - #define SCM_TIMESTAMP SO_TIMESTAMP - - #define TARGET_SO_PEERSEC 30 - #define TARGET_SO_SNDBUFFORCE 31 - #define TARGET_SO_RCVBUFFORCE 33 - - /** sock_type - Socket types - * - * Please notice that for binary compat reasons MIPS has to - * override the enum sock_type in include/linux/net.h, so - * we define ARCH_HAS_SOCKET_TYPES here. - * - * @SOCK_DGRAM - datagram (conn.less) socket - * @SOCK_STREAM - stream (connection) socket - * @SOCK_RAW - raw socket - * @SOCK_RDM - reliably-delivered message - * @SOCK_SEQPACKET - sequential packet socket - * @SOCK_PACKET - linux specific way of getting packets at the dev level. - * For writing rarp and other similar things on the user level. - */ - enum sock_type { - TARGET_SOCK_DGRAM = 1, - TARGET_SOCK_STREAM = 2, - TARGET_SOCK_RAW = 3, - TARGET_SOCK_RDM = 4, - TARGET_SOCK_SEQPACKET = 5, - TARGET_SOCK_DCCP = 6, - TARGET_SOCK_PACKET = 10, - }; - - #define TARGET_SOCK_MAX (SOCK_PACKET + 1) + /* MIPS special values for constants */ + + /* + * For setsockopt(2) + * + * This defines are ABI conformant as far as Linux supports these ... + */ + #define TARGET_SOL_SOCKET 0xffff + + #define TARGET_SO_DEBUG 0x0001 /* Record debugging information. */ + #define TARGET_SO_REUSEADDR 0x0004 /* Allow reuse of local addresses. */ + #define TARGET_SO_KEEPALIVE 0x0008 /* Keep connections alive and send + SIGPIPE when they die. */ + #define TARGET_SO_DONTROUTE 0x0010 /* Don't do local routing. */ + #define TARGET_SO_BROADCAST 0x0020 /* Allow transmission of + broadcast messages. */ + #define TARGET_SO_LINGER 0x0080 /* Block on close of a reliable + * socket to transmit pending data. + */ + #define TARGET_SO_OOBINLINE 0x0100 /* Receive out-of-band data in-band. + */ + #if 0 + /* To add: Allow local address and port reuse. */ + #define TARGET_SO_REUSEPORT 0x0200 + #endif + + #define TARGET_SO_TYPE 0x1008 /* Compatible name for SO_STYLE. */ + #define TARGET_SO_STYLE SO_TYPE /* Synonym */ + #define TARGET_SO_ERROR 0x1007 /* get error status and clear */ + #define TARGET_SO_SNDBUF 0x1001 /* Send buffer size. */ + #define TARGET_SO_RCVBUF 0x1002 /* Receive buffer. */ + #define TARGET_SO_SNDLOWAT 0x1003 /* send low-water mark */ + #define TARGET_SO_RCVLOWAT 0x1004 /* receive low-water mark */ + #define TARGET_SO_SNDTIMEO 0x1005 /* send timeout */ + #define TARGET_SO_RCVTIMEO 0x1006 /* receive timeout */ + #define TARGET_SO_ACCEPTCONN 0x1009 + + /* linux-specific, might as well be the same as on i386 */ + #define TARGET_SO_NO_CHECK 11 + #define TARGET_SO_PRIORITY 12 + #define TARGET_SO_BSDCOMPAT 14 + + #define TARGET_SO_PASSCRED 17 + #define TARGET_SO_PEERCRED 18 + + /* Security levels - as per NRL IPv6 - don't actually do anything */ + #define TARGET_SO_SECURITY_AUTHENTICATION 22 + #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23 + #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24 + + #define TARGET_SO_BINDTODEVICE 25 + + /* Socket filtering */ + #define TARGET_SO_ATTACH_FILTER 26 + #define TARGET_SO_DETACH_FILTER 27 + + #define TARGET_SO_PEERNAME 28 + #define TARGET_SO_TIMESTAMP 29 + #define SCM_TIMESTAMP SO_TIMESTAMP + + #define TARGET_SO_PEERSEC 30 + #define TARGET_SO_SNDBUFFORCE 31 + #define TARGET_SO_RCVBUFFORCE 33 + + /** sock_type - Socket types + * + * Please notice that for binary compat reasons MIPS has to + * override the enum sock_type in include/linux/net.h, so + * we define ARCH_HAS_SOCKET_TYPES here. + * + * @SOCK_DGRAM - datagram (conn.less) socket + * @SOCK_STREAM - stream (connection) socket + * @SOCK_RAW - raw socket + * @SOCK_RDM - reliably-delivered message + * @SOCK_SEQPACKET - sequential packet socket + * @SOCK_DCCP - Datagram Congestion Control Protocol socket + * @SOCK_PACKET - linux specific way of getting packets at the dev level. + * For writing rarp and other similar things on the user + * level. + * @SOCK_CLOEXEC - sets the close-on-exec (FD_CLOEXEC) flag. + * @SOCK_NONBLOCK - sets the O_NONBLOCK file status flag. + */ + + #define ARCH_HAS_SOCKET_TYPES 1 + + enum sock_type { + TARGET_SOCK_DGRAM = 1, + TARGET_SOCK_STREAM = 2, + TARGET_SOCK_RAW = 3, + TARGET_SOCK_RDM = 4, + TARGET_SOCK_SEQPACKET = 5, + TARGET_SOCK_DCCP = 6, + TARGET_SOCK_PACKET = 10, + TARGET_SOCK_CLOEXEC = 02000000, + TARGET_SOCK_NONBLOCK = 0200, + }; + + #define TARGET_SOCK_MAX (TARGET_SOCK_PACKET + 1) + #define TARGET_SOCK_TYPE_MASK 0xf /* Covers up to TARGET_SOCK_MAX-1. */ #elif defined(TARGET_ALPHA) @@ -156,61 +169,167 @@ /* Instruct lower device to use last 4-bytes of skb data as FCS */ #define TARGET_SO_NOFCS 43 + /** sock_type - Socket types + * + * Please notice that for binary compat reasons ALPHA has to + * override the enum sock_type in include/linux/net.h, so + * we define ARCH_HAS_SOCKET_TYPES here. + * + * @SOCK_DGRAM - datagram (conn.less) socket + * @SOCK_STREAM - stream (connection) socket + * @SOCK_RAW - raw socket + * @SOCK_RDM - reliably-delivered message + * @SOCK_SEQPACKET - sequential packet socket + * @SOCK_DCCP - Datagram Congestion Control Protocol socket + * @SOCK_PACKET - linux specific way of getting packets at the dev level. + * For writing rarp and other similar things on the user + * level. + * @SOCK_CLOEXEC - sets the close-on-exec (FD_CLOEXEC) flag. + * @SOCK_NONBLOCK - sets the O_NONBLOCK file status flag. + */ + + #define ARCH_HAS_SOCKET_TYPES 1 + + enum sock_type { + TARGET_SOCK_STREAM = 1, + TARGET_SOCK_DGRAM = 2, + TARGET_SOCK_RAW = 3, + TARGET_SOCK_RDM = 4, + TARGET_SOCK_SEQPACKET = 5, + TARGET_SOCK_DCCP = 6, + TARGET_SOCK_PACKET = 10, + TARGET_SOCK_CLOEXEC = 010000000, + TARGET_SOCK_NONBLOCK = 010000000000, + }; + + #define TARGET_SOCK_MAX (TARGET_SOCK_PACKET + 1) + #define TARGET_SOCK_TYPE_MASK 0xf /* Covers up to TARGET_SOCK_MAX-1. */ #else - /* For setsockopt(2) */ - #define TARGET_SOL_SOCKET 1 - - #define TARGET_SO_DEBUG 1 - #define TARGET_SO_REUSEADDR 2 - #define TARGET_SO_TYPE 3 - #define TARGET_SO_ERROR 4 - #define TARGET_SO_DONTROUTE 5 - #define TARGET_SO_BROADCAST 6 - #define TARGET_SO_SNDBUF 7 - #define TARGET_SO_RCVBUF 8 - #define TARGET_SO_SNDBUFFORCE 32 - #define TARGET_SO_RCVBUFFORCE 33 - #define TARGET_SO_KEEPALIVE 9 - #define TARGET_SO_OOBINLINE 10 - #define TARGET_SO_NO_CHECK 11 - #define TARGET_SO_PRIORITY 12 - #define TARGET_SO_LINGER 13 - #define TARGET_SO_BSDCOMPAT 14 - /* To add :#define TARGET_SO_REUSEPORT 15 */ +#if defined(TARGET_SPARC) + /** sock_type - Socket types + * + * Please notice that for binary compat reasons SPARC has to + * override the enum sock_type in include/linux/net.h, so + * we define ARCH_HAS_SOCKET_TYPES here. + * + * @SOCK_DGRAM - datagram (conn.less) socket + * @SOCK_STREAM - stream (connection) socket + * @SOCK_RAW - raw socket + * @SOCK_RDM - reliably-delivered message + * @SOCK_SEQPACKET - sequential packet socket + * @SOCK_DCCP - Datagram Congestion Control Protocol socket + * @SOCK_PACKET - linux specific way of getting packets at the dev level. + * For writing rarp and other similar things on the user + * level. + * @SOCK_CLOEXEC - sets the close-on-exec (FD_CLOEXEC) flag. + * @SOCK_NONBLOCK - sets the O_NONBLOCK file status flag. + */ + + #define ARCH_HAS_SOCKET_TYPES 1 + + enum sock_type { + TARGET_SOCK_STREAM = 1, + TARGET_SOCK_DGRAM = 2, + TARGET_SOCK_RAW = 3, + TARGET_SOCK_RDM = 4, + TARGET_SOCK_SEQPACKET = 5, + TARGET_SOCK_DCCP = 6, + TARGET_SOCK_PACKET = 10, + TARGET_SOCK_CLOEXEC = 020000000, + TARGET_SOCK_NONBLOCK = 040000, + }; + + #define TARGET_SOCK_MAX (TARGET_SOCK_PACKET + 1) + #define TARGET_SOCK_TYPE_MASK 0xf /* Covers up to TARGET_SOCK_MAX-1. */ +#endif + + /* For setsockopt(2) */ + #define TARGET_SOL_SOCKET 1 + + #define TARGET_SO_DEBUG 1 + #define TARGET_SO_REUSEADDR 2 + #define TARGET_SO_TYPE 3 + #define TARGET_SO_ERROR 4 + #define TARGET_SO_DONTROUTE 5 + #define TARGET_SO_BROADCAST 6 + #define TARGET_SO_SNDBUF 7 + #define TARGET_SO_RCVBUF 8 + #define TARGET_SO_SNDBUFFORCE 32 + #define TARGET_SO_RCVBUFFORCE 33 + #define TARGET_SO_KEEPALIVE 9 + #define TARGET_SO_OOBINLINE 10 + #define TARGET_SO_NO_CHECK 11 + #define TARGET_SO_PRIORITY 12 + #define TARGET_SO_LINGER 13 + #define TARGET_SO_BSDCOMPAT 14 + /* To add :#define TARGET_SO_REUSEPORT 15 */ #if defined(TARGET_PPC) - #define TARGET_SO_RCVLOWAT 16 - #define TARGET_SO_SNDLOWAT 17 - #define TARGET_SO_RCVTIMEO 18 - #define TARGET_SO_SNDTIMEO 19 - #define TARGET_SO_PASSCRED 20 - #define TARGET_SO_PEERCRED 21 + #define TARGET_SO_RCVLOWAT 16 + #define TARGET_SO_SNDLOWAT 17 + #define TARGET_SO_RCVTIMEO 18 + #define TARGET_SO_SNDTIMEO 19 + #define TARGET_SO_PASSCRED 20 + #define TARGET_SO_PEERCRED 21 #else - #define TARGET_SO_PASSCRED 16 - #define TARGET_SO_PEERCRED 17 - #define TARGET_SO_RCVLOWAT 18 - #define TARGET_SO_SNDLOWAT 19 - #define TARGET_SO_RCVTIMEO 20 - #define TARGET_SO_SNDTIMEO 21 + #define TARGET_SO_PASSCRED 16 + #define TARGET_SO_PEERCRED 17 + #define TARGET_SO_RCVLOWAT 18 + #define TARGET_SO_SNDLOWAT 19 + #define TARGET_SO_RCVTIMEO 20 + #define TARGET_SO_SNDTIMEO 21 #endif - /* Security levels - as per NRL IPv6 - don't actually do anything */ - #define TARGET_SO_SECURITY_AUTHENTICATION 22 - #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23 - #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24 + /* Security levels - as per NRL IPv6 - don't actually do anything */ + #define TARGET_SO_SECURITY_AUTHENTICATION 22 + #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23 + #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24 - #define TARGET_SO_BINDTODEVICE 25 + #define TARGET_SO_BINDTODEVICE 25 - /* Socket filtering */ - #define TARGET_SO_ATTACH_FILTER 26 - #define TARGET_SO_DETACH_FILTER 27 + /* Socket filtering */ + #define TARGET_SO_ATTACH_FILTER 26 + #define TARGET_SO_DETACH_FILTER 27 + + #define TARGET_SO_PEERNAME 28 + #define TARGET_SO_TIMESTAMP 29 + #define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP - #define TARGET_SO_PEERNAME 28 - #define TARGET_SO_TIMESTAMP 29 - #define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP + #define TARGET_SO_ACCEPTCONN 30 - #define TARGET_SO_ACCEPTCONN 30 + #define TARGET_SO_PEERSEC 31 + +#endif - #define TARGET_SO_PEERSEC 31 +#ifndef ARCH_HAS_SOCKET_TYPES + /** sock_type - Socket types - default values + * + * + * @SOCK_STREAM - stream (connection) socket + * @SOCK_DGRAM - datagram (conn.less) socket + * @SOCK_RAW - raw socket + * @SOCK_RDM - reliably-delivered message + * @SOCK_SEQPACKET - sequential packet socket + * @SOCK_DCCP - Datagram Congestion Control Protocol socket + * @SOCK_PACKET - linux specific way of getting packets at the dev level. + * For writing rarp and other similar things on the user + * level. + * @SOCK_CLOEXEC - sets the close-on-exec (FD_CLOEXEC) flag. + * @SOCK_NONBLOCK - sets the O_NONBLOCK file status flag. + */ + enum sock_type { + TARGET_SOCK_STREAM = 1, + TARGET_SOCK_DGRAM = 2, + TARGET_SOCK_RAW = 3, + TARGET_SOCK_RDM = 4, + TARGET_SOCK_SEQPACKET = 5, + TARGET_SOCK_DCCP = 6, + TARGET_SOCK_PACKET = 10, + TARGET_SOCK_CLOEXEC = 02000000, + TARGET_SOCK_NONBLOCK = 04000, + }; + + #define TARGET_SOCK_MAX (TARGET_SOCK_PACKET + 1) + #define TARGET_SOCK_TYPE_MASK 0xf /* Covers up to TARGET_SOCK_MAX-1. */ #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 433d3ba990..00a0390ea9 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -105,6 +105,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include <linux/vt.h> #include <linux/dm-ioctl.h> #include <linux/reboot.h> +#include <linux/route.h> #include "linux_loop.h" #include "cpu-uname.h" @@ -338,6 +339,7 @@ static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode) } #endif +#ifdef TARGET_NR_utimensat #ifdef CONFIG_UTIMENSAT static int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) @@ -347,12 +349,19 @@ static int sys_utimensat(int dirfd, const char *pathname, else return utimensat(dirfd, pathname, times, flags); } -#else -#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat) +#elif defined(__NR_utimensat) +#define __NR_sys_utimensat __NR_utimensat _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname, const struct timespec *,tsp,int,flags) +#else +static int sys_utimensat(int dirfd, const char *pathname, + const struct timespec times[2], int flags) +{ + errno = ENOSYS; + return -1; +} #endif -#endif /* CONFIG_UTIMENSAT */ +#endif /* TARGET_NR_utimensat */ #ifdef CONFIG_INOTIFY #include <sys/inotify.h> @@ -1696,31 +1705,36 @@ static void unlock_iovec(struct iovec *vec, abi_ulong target_addr, free(vec); } -/* do_socket() Must return target values and target errnos. */ -static abi_long do_socket(int domain, int type, int protocol) +static inline void target_to_host_sock_type(int *type) { -#if defined(TARGET_MIPS) - switch(type) { + int host_type = 0; + int target_type = *type; + + switch (target_type & TARGET_SOCK_TYPE_MASK) { case TARGET_SOCK_DGRAM: - type = SOCK_DGRAM; + host_type = SOCK_DGRAM; break; case TARGET_SOCK_STREAM: - type = SOCK_STREAM; - break; - case TARGET_SOCK_RAW: - type = SOCK_RAW; + host_type = SOCK_STREAM; break; - case TARGET_SOCK_RDM: - type = SOCK_RDM; - break; - case TARGET_SOCK_SEQPACKET: - type = SOCK_SEQPACKET; - break; - case TARGET_SOCK_PACKET: - type = SOCK_PACKET; + default: + host_type = target_type & TARGET_SOCK_TYPE_MASK; break; } -#endif + if (target_type & TARGET_SOCK_CLOEXEC) { + host_type |= SOCK_CLOEXEC; + } + if (target_type & TARGET_SOCK_NONBLOCK) { + host_type |= SOCK_NONBLOCK; + } + *type = host_type; +} + +/* do_socket() Must return target values and target errnos. */ +static abi_long do_socket(int domain, int type, int protocol) +{ + target_to_host_sock_type(&type); + if (domain == PF_NETLINK) return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */ return get_errno(socket(domain, type, protocol)); @@ -1953,6 +1967,8 @@ static abi_long do_socketpair(int domain, int type, int protocol, int tab[2]; abi_long ret; + target_to_host_sock_type(&type); + ret = get_errno(socketpair(domain, type, protocol, tab)); if (!is_error(ret)) { if (put_user_s32(tab[0], target_tab_addr) @@ -3551,6 +3567,69 @@ out: return ret; } +static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp, + int fd, abi_long cmd, abi_long arg) +{ + const argtype *arg_type = ie->arg_type; + const StructEntry *se; + const argtype *field_types; + const int *dst_offsets, *src_offsets; + int target_size; + void *argptr; + abi_ulong *target_rt_dev_ptr; + unsigned long *host_rt_dev_ptr; + abi_long ret; + int i; + + assert(ie->access == IOC_W); + assert(*arg_type == TYPE_PTR); + arg_type++; + assert(*arg_type == TYPE_STRUCT); + target_size = thunk_type_size(arg_type, 0); + argptr = lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) { + return -TARGET_EFAULT; + } + arg_type++; + assert(*arg_type == (int)STRUCT_rtentry); + se = struct_entries + *arg_type++; + assert(se->convert[0] == NULL); + /* convert struct here to be able to catch rt_dev string */ + field_types = se->field_types; + dst_offsets = se->field_offsets[THUNK_HOST]; + src_offsets = se->field_offsets[THUNK_TARGET]; + for (i = 0; i < se->nb_fields; i++) { + if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) { + assert(*field_types == TYPE_PTRVOID); + target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]); + host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]); + if (*target_rt_dev_ptr != 0) { + *host_rt_dev_ptr = (unsigned long)lock_user_string( + tswapal(*target_rt_dev_ptr)); + if (!*host_rt_dev_ptr) { + unlock_user(argptr, arg, 0); + return -TARGET_EFAULT; + } + } else { + *host_rt_dev_ptr = 0; + } + field_types++; + continue; + } + field_types = thunk_convert(buf_temp + dst_offsets[i], + argptr + src_offsets[i], + field_types, THUNK_HOST); + } + unlock_user(argptr, arg, 0); + + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + if (*host_rt_dev_ptr != 0) { + unlock_user((void *)*host_rt_dev_ptr, + *target_rt_dev_ptr, 0); + } + return ret; +} + static IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, ...) \ { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } }, @@ -4973,6 +5052,30 @@ static int open_self_auxv(void *cpu_env, int fd) return 0; } +static int is_proc_myself(const char *filename, const char *entry) +{ + if (!strncmp(filename, "/proc/", strlen("/proc/"))) { + filename += strlen("/proc/"); + if (!strncmp(filename, "self/", strlen("self/"))) { + filename += strlen("self/"); + } else if (*filename >= '1' && *filename <= '9') { + char myself[80]; + snprintf(myself, sizeof(myself), "%d/", getpid()); + if (!strncmp(filename, myself, strlen(myself))) { + filename += strlen(myself); + } else { + return 0; + } + } else { + return 0; + } + if (!strcmp(filename, entry)) { + return 1; + } + } + return 0; +} + static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) { struct fake_open { @@ -4981,15 +5084,14 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) }; const struct fake_open *fake_open; static const struct fake_open fakes[] = { - { "/proc/self/maps", open_self_maps }, - { "/proc/self/stat", open_self_stat }, - { "/proc/self/auxv", open_self_auxv }, + { "maps", open_self_maps }, + { "stat", open_self_stat }, + { "auxv", open_self_auxv }, { NULL, NULL } }; for (fake_open = fakes; fake_open->filename; fake_open++) { - if (!strncmp(pathname, fake_open->filename, - strlen(fake_open->filename))) { + if (is_proc_myself(pathname, fake_open->filename)) { break; } } @@ -6266,20 +6368,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif case TARGET_NR_readlink: { - void *p2, *temp; + void *p2; p = lock_user_string(arg1); p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0); - if (!p || !p2) + if (!p || !p2) { ret = -TARGET_EFAULT; - else { - if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) { - char real[PATH_MAX]; - temp = realpath(exec_path,real); - ret = (temp==NULL) ? get_errno(-1) : strlen(real) ; - snprintf((char *)p2, arg3, "%s", real); - } - else - ret = get_errno(readlink(path(p), p2, arg3)); + } else if (is_proc_myself((const char *)p, "exe")) { + char real[PATH_MAX], *temp; + temp = realpath(exec_path, real); + ret = temp == NULL ? get_errno(-1) : strlen(real) ; + snprintf((char *)p2, arg3, "%s", real); + } else { + ret = get_errno(readlink(path(p), p2, arg3)); } unlock_user(p2, arg2, ret); unlock_user(p, arg1, 0); @@ -6291,10 +6391,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, void *p2; p = lock_user_string(arg2); p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0); - if (!p || !p2) - ret = -TARGET_EFAULT; - else + if (!p || !p2) { + ret = -TARGET_EFAULT; + } else if (is_proc_myself((const char *)p, "exe")) { + char real[PATH_MAX], *temp; + temp = realpath(exec_path, real); + ret = temp == NULL ? get_errno(-1) : strlen(real) ; + snprintf((char *)p2, arg4, "%s", real); + } else { ret = get_errno(readlinkat(arg1, path(p), p2, arg4)); + } unlock_user(p2, arg3, ret); unlock_user(p, arg2, 0); } @@ -8540,7 +8646,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto unimplemented_nowarn; #endif -#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat) +#if defined(TARGET_NR_utimensat) case TARGET_NR_utimensat: { struct timespec *tsp, ts[2]; diff --git a/qemu-char.c b/qemu-char.c index 6cec5d7114..18c42a39da 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -926,7 +926,6 @@ static void qemu_chr_set_echo_stdio(CharDriverState *chr, bool echo) tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 0; } - /* if graphical mode, we allow Ctrl-C handling */ if (!stdio_allow_signal) tty.c_lflag &= ~ISIG; @@ -955,7 +954,6 @@ static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) chr = qemu_chr_open_fd(0, 1); chr->chr_close = qemu_chr_close_stdio; chr->chr_set_echo = qemu_chr_set_echo_stdio; - stdio_allow_signal = display_type != DT_NOGRAPHIC; if (opts->has_signal) { stdio_allow_signal = opts->signal; } @@ -2932,6 +2930,14 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) if (strstart(filename, "mon:", &p)) { filename = p; qemu_opt_set(opts, "mux", "on"); + if (strcmp(filename, "stdio") == 0) { + /* Monitor is muxed to stdio: do not exit on Ctrl+C by default + * but pass it to the guest. Handle this only for compat syntax, + * for -chardev syntax we have special option for this. + * This is what -nographic did, redirecting+muxing serial+monitor + * to stdio causing Ctrl+C to be passed to guest. */ + qemu_opt_set(opts, "signal", "off"); + } } if (strcmp(filename, "null") == 0 || @@ -3060,8 +3066,7 @@ static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend, { backend->stdio = g_new0(ChardevStdio, 1); backend->stdio->has_signal = true; - backend->stdio->signal = - qemu_opt_get_bool(opts, "signal", display_type != DT_NOGRAPHIC); + backend->stdio->signal = qemu_opt_get_bool(opts, "signal", true); } static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend, diff --git a/qemu-options.hx b/qemu-options.hx index 137a39b7ad..7cc4d8ef25 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -842,7 +842,8 @@ STEXI Normally, QEMU uses SDL to display the VGA output. With this option, you can totally disable graphical output so that QEMU is a simple command line application. The emulated serial port is redirected on -the console. Therefore, you can still use QEMU to debug a Linux kernel +the console and muxed with the monitor (unless redirected elsewhere +explicitly). Therefore, you can still use QEMU to debug a Linux kernel with a serial console. ETEXI @@ -2485,14 +2486,15 @@ same as if you had specified @code{-serial tcp} except the unix domain socket @item mon:@var{dev_string} This is a special option to allow the monitor to be multiplexed onto another serial port. The monitor is accessed with key sequence of -@key{Control-a} and then pressing @key{c}. See monitor access -@ref{pcsys_keys} in the -nographic section for more keys. +@key{Control-a} and then pressing @key{c}. @var{dev_string} should be any one of the serial devices specified above. An example to multiplex the monitor onto a telnet server listening on port 4444 would be: @table @code @item -serial mon:telnet::4444,server,nowait @end table +When monitor is multiplexed to stdio this way, Ctrl+C will not terminate +QEMU anymore but will be passed to the guest instead. @item braille Braille device. This will use BrlAPI to display the braille output on a real diff --git a/qom/object.c b/qom/object.c index cbd7e86033..b2479d1c06 100644 --- a/qom/object.c +++ b/qom/object.c @@ -531,14 +531,14 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, #ifdef CONFIG_QOM_CAST_DEBUG int i; - for (i = 0; i < OBJECT_CLASS_CAST_CACHE; i++) { + for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) { if (class->cast_cache[i] == typename) { ret = class; goto out; } } #else - if (!class->interfaces) { + if (!class || !class->interfaces) { return class; } #endif @@ -551,7 +551,7 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, } #ifdef CONFIG_QOM_CAST_DEBUG - if (ret == class) { + if (class && ret == class) { for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { class->cast_cache[i - 1] = class->cast_cache[i]; } diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 935ef6393d..8315489989 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -743,7 +743,6 @@ static int kvm_get_supported_msrs(KVMState *s) int kvm_arch_init(KVMState *s) { - QemuOptsList *list = qemu_find_opts("machine"); uint64_t identity_base = 0xfffbc000; uint64_t shadow_mem; int ret; @@ -792,15 +791,13 @@ int kvm_arch_init(KVMState *s) } qemu_register_reset(kvm_unpoison_all, NULL); - if (!QTAILQ_EMPTY(&list->head)) { - shadow_mem = qemu_opt_get_size(QTAILQ_FIRST(&list->head), - "kvm_shadow_mem", -1); - if (shadow_mem != -1) { - shadow_mem /= 4096; - ret = kvm_vm_ioctl(s, KVM_SET_NR_MMU_PAGES, shadow_mem); - if (ret < 0) { - return ret; - } + shadow_mem = qemu_opt_get_size(qemu_get_machine_opts(), + "kvm_shadow_mem", -1); + if (shadow_mem != -1) { + shadow_mem /= 4096; + ret = kvm_vm_ioctl(s, KVM_SET_NR_MMU_PAGES, shadow_mem); + if (ret < 0) { + return ret; } } return 0; diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index 97e4a5baa7..51e50920b2 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -40,6 +40,7 @@ typedef enum { /* optional instructions */ #define TCG_TARGET_HAS_div_i32 0 +#define TCG_TARGET_HAS_rem_i32 0 #define TCG_TARGET_HAS_ext8s_i32 1 #define TCG_TARGET_HAS_ext16s_i32 1 #define TCG_TARGET_HAS_ext8u_i32 1 @@ -62,6 +63,7 @@ typedef enum { #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_div_i64 0 +#define TCG_TARGET_HAS_rem_i64 0 #define TCG_TARGET_HAS_ext8s_i64 1 #define TCG_TARGET_HAS_ext16s_i64 1 #define TCG_TARGET_HAS_ext32s_i64 1 diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 6be736b75e..6c4854dbb0 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -22,50 +22,43 @@ * THE SOFTWARE. */ -#if defined(__ARM_ARCH_7__) || \ - defined(__ARM_ARCH_7A__) || \ - defined(__ARM_ARCH_7EM__) || \ - defined(__ARM_ARCH_7M__) || \ - defined(__ARM_ARCH_7R__) -#define USE_ARMV7_INSTRUCTIONS +/* The __ARM_ARCH define is provided by gcc 4.8. Construct it otherwise. */ +#ifndef __ARM_ARCH +# if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \ + || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \ + || defined(__ARM_ARCH_7EM__) +# define __ARM_ARCH 7 +# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) \ + || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) +# define __ARM_ARCH 6 +# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5E__) \ + || defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) +# define __ARM_ARCH 5 +# else +# define __ARM_ARCH 4 +# endif #endif -#if defined(USE_ARMV7_INSTRUCTIONS) || \ - defined(__ARM_ARCH_6J__) || \ - defined(__ARM_ARCH_6K__) || \ - defined(__ARM_ARCH_6T2__) || \ - defined(__ARM_ARCH_6Z__) || \ - defined(__ARM_ARCH_6ZK__) -#define USE_ARMV6_INSTRUCTIONS -#endif - -#if defined(USE_ARMV6_INSTRUCTIONS) || \ - defined(__ARM_ARCH_5T__) || \ - defined(__ARM_ARCH_5TE__) || \ - defined(__ARM_ARCH_5TEJ__) -#define USE_ARMV5_INSTRUCTIONS -#endif +static int arm_arch = __ARM_ARCH; -#ifdef USE_ARMV5_INSTRUCTIONS -static const int use_armv5_instructions = 1; +#if defined(__ARM_ARCH_5T__) \ + || defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__) +# define use_armv5t_instructions 1 #else -static const int use_armv5_instructions = 0; +# define use_armv5t_instructions use_armv6_instructions #endif -#undef USE_ARMV5_INSTRUCTIONS -#ifdef USE_ARMV6_INSTRUCTIONS -static const int use_armv6_instructions = 1; -#else -static const int use_armv6_instructions = 0; -#endif -#undef USE_ARMV6_INSTRUCTIONS +#define use_armv6_instructions (__ARM_ARCH >= 6 || arm_arch >= 6) +#define use_armv7_instructions (__ARM_ARCH >= 7 || arm_arch >= 7) -#ifdef USE_ARMV7_INSTRUCTIONS -static const int use_armv7_instructions = 1; -#else -static const int use_armv7_instructions = 0; +#ifndef use_idiv_instructions +bool use_idiv_instructions; +#endif +#ifdef CONFIG_GETAUXVAL +# include <sys/auxv.h> #endif -#undef USE_ARMV7_INSTRUCTIONS #ifndef NDEBUG static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { @@ -1023,7 +1016,7 @@ static inline void tcg_out_call(TCGContext *s, uint32_t addr) if (val - 8 < 0x02000000 && val - 8 >= -0x02000000) { if (addr & 1) { /* Use BLX if the target is in Thumb mode */ - if (!use_armv5_instructions) { + if (!use_armv5t_instructions) { tcg_abort(); } tcg_out_blx_imm(s, val); @@ -1042,7 +1035,7 @@ static inline void tcg_out_call(TCGContext *s, uint32_t addr) static inline void tcg_out_callr(TCGContext *s, int cond, int arg) { - if (use_armv5_instructions) { + if (use_armv5t_instructions) { tcg_out_blx(s, cond, arg); } else { tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R14, 0, @@ -1926,18 +1919,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_divu_i32: tcg_out_udiv(s, COND_AL, args[0], args[1], args[2]); break; - case INDEX_op_rem_i32: - tcg_out_sdiv(s, COND_AL, TCG_REG_TMP, args[1], args[2]); - tcg_out_mul32(s, COND_AL, TCG_REG_TMP, TCG_REG_TMP, args[2]); - tcg_out_dat_reg(s, COND_AL, ARITH_SUB, args[0], args[1], TCG_REG_TMP, - SHIFT_IMM_LSL(0)); - break; - case INDEX_op_remu_i32: - tcg_out_udiv(s, COND_AL, TCG_REG_TMP, args[1], args[2]); - tcg_out_mul32(s, COND_AL, TCG_REG_TMP, TCG_REG_TMP, args[2]); - tcg_out_dat_reg(s, COND_AL, ARITH_SUB, args[0], args[1], TCG_REG_TMP, - SHIFT_IMM_LSL(0)); - break; default: tcg_abort(); @@ -2041,18 +2022,31 @@ static const TCGTargetOpDef arm_op_defs[] = { { INDEX_op_deposit_i32, { "r", "0", "rZ" } }, -#if TCG_TARGET_HAS_div_i32 { INDEX_op_div_i32, { "r", "r", "r" } }, - { INDEX_op_rem_i32, { "r", "r", "r" } }, { INDEX_op_divu_i32, { "r", "r", "r" } }, - { INDEX_op_remu_i32, { "r", "r", "r" } }, -#endif { -1 }, }; static void tcg_target_init(TCGContext *s) { +#if defined(CONFIG_GETAUXVAL) + /* Only probe for the platform and capabilities if we havn't already + determined maximum values at compile time. */ +# if !defined(use_idiv_instructions) + { + unsigned long hwcap = getauxval(AT_HWCAP); + use_idiv_instructions = (hwcap & HWCAP_ARM_IDIVA) != 0; + } +# endif + if (__ARM_ARCH < 7) { + const char *pl = (const char *)getauxval(AT_PLATFORM); + if (pl != NULL && pl[0] == 'v' && pl[1] >= '4' && pl[1] <= '9') { + arm_arch = pl[1] - '0'; + } + } +#endif /* GETAUXVAL */ + tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff); tcg_regset_set32(tcg_target_call_clobber_regs, 0, (1 << TCG_REG_R0) | @@ -2094,23 +2088,31 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type, tcg_out_movi32(s, COND_AL, ret, arg); } +/* Compute frame size via macros, to share between tcg_target_qemu_prologue + and tcg_register_jit. */ + +#define PUSH_SIZE ((11 - 4 + 1 + 1) * sizeof(tcg_target_long)) + +#define FRAME_SIZE \ + ((PUSH_SIZE \ + + TCG_STATIC_CALL_ARGS_SIZE \ + + CPU_TEMP_BUF_NLONGS * sizeof(long) \ + + TCG_TARGET_STACK_ALIGN - 1) \ + & -TCG_TARGET_STACK_ALIGN) + static void tcg_target_qemu_prologue(TCGContext *s) { - int frame_size; + int stack_addend; /* Calling convention requires us to save r4-r11 and lr. */ /* stmdb sp!, { r4 - r11, lr } */ tcg_out32(s, (COND_AL << 28) | 0x092d4ff0); - /* Allocate the local stack frame. */ - frame_size = TCG_STATIC_CALL_ARGS_SIZE; - frame_size += CPU_TEMP_BUF_NLONGS * sizeof(long); - /* We saved an odd number of registers above; keep an 8 aligned stack. */ - frame_size = ((frame_size + TCG_TARGET_STACK_ALIGN - 1) - & -TCG_TARGET_STACK_ALIGN) + 4; + /* Reserve callee argument and tcg temp space. */ + stack_addend = FRAME_SIZE - PUSH_SIZE; tcg_out_dat_rI(s, COND_AL, ARITH_SUB, TCG_REG_CALL_STACK, - TCG_REG_CALL_STACK, frame_size, 1); + TCG_REG_CALL_STACK, stack_addend, 1); tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE, CPU_TEMP_BUF_NLONGS * sizeof(long)); @@ -2121,8 +2123,58 @@ static void tcg_target_qemu_prologue(TCGContext *s) /* Epilogue. We branch here via tb_ret_addr. */ tcg_out_dat_rI(s, COND_AL, ARITH_ADD, TCG_REG_CALL_STACK, - TCG_REG_CALL_STACK, frame_size, 1); + TCG_REG_CALL_STACK, stack_addend, 1); /* ldmia sp!, { r4 - r11, pc } */ tcg_out32(s, (COND_AL << 28) | 0x08bd8ff0); } + +typedef struct { + DebugFrameCIE cie; + DebugFrameFDEHeader fde; + uint8_t fde_def_cfa[4]; + uint8_t fde_reg_ofs[18]; +} DebugFrame; + +#define ELF_HOST_MACHINE EM_ARM + +/* We're expecting a 2 byte uleb128 encoded value. */ +QEMU_BUILD_BUG_ON(FRAME_SIZE >= (1 << 14)); + +static DebugFrame debug_frame = { + .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */ + .cie.id = -1, + .cie.version = 1, + .cie.code_align = 1, + .cie.data_align = 0x7c, /* sleb128 -4 */ + .cie.return_column = 14, + + /* Total FDE size does not include the "len" member. */ + .fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset), + + .fde_def_cfa = { + 12, 13, /* DW_CFA_def_cfa sp, ... */ + (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */ + (FRAME_SIZE >> 7) + }, + .fde_reg_ofs = { + /* The following must match the stmdb in the prologue. */ + 0x8e, 1, /* DW_CFA_offset, lr, -4 */ + 0x8b, 2, /* DW_CFA_offset, r11, -8 */ + 0x8a, 3, /* DW_CFA_offset, r10, -12 */ + 0x89, 4, /* DW_CFA_offset, r9, -16 */ + 0x88, 5, /* DW_CFA_offset, r8, -20 */ + 0x87, 6, /* DW_CFA_offset, r7, -24 */ + 0x86, 7, /* DW_CFA_offset, r6, -28 */ + 0x85, 8, /* DW_CFA_offset, r5, -32 */ + 0x84, 9, /* DW_CFA_offset, r4, -36 */ + } +}; + +void tcg_register_jit(void *buf, size_t buf_size) +{ + debug_frame.fde.func_start = (tcg_target_long) buf; + debug_frame.fde.func_len = buf_size; + + tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame)); +} diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index 3be41cce3c..5cd9d6a679 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -49,6 +49,13 @@ typedef enum { #define TCG_TARGET_NB_REGS 16 +#ifdef __ARM_ARCH_EXT_IDIV__ +#define use_idiv_instructions 1 +#else +extern bool use_idiv_instructions; +#endif + + /* used for function call generation */ #define TCG_REG_CALL_STACK TCG_REG_R13 #define TCG_TARGET_STACK_ALIGN 8 @@ -73,12 +80,8 @@ typedef enum { #define TCG_TARGET_HAS_deposit_i32 1 #define TCG_TARGET_HAS_movcond_i32 1 #define TCG_TARGET_HAS_muls2_i32 1 - -#ifdef __ARM_ARCH_EXT_IDIV__ -#define TCG_TARGET_HAS_div_i32 1 -#else -#define TCG_TARGET_HAS_div_i32 0 -#endif +#define TCG_TARGET_HAS_div_i32 use_idiv_instructions +#define TCG_TARGET_HAS_rem_i32 0 extern bool tcg_target_deposit_valid(int ofs, int len); #define TCG_TARGET_deposit_i32_valid tcg_target_deposit_valid diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c index 656e73621a..68f77ba4dd 100644 --- a/tcg/hppa/tcg-target.c +++ b/tcg/hppa/tcg-target.c @@ -1766,28 +1766,11 @@ static void tcg_target_init(TCGContext *s) } typedef struct { - uint32_t len __attribute__((aligned((sizeof(void *))))); - uint32_t id; - uint8_t version; - char augmentation[1]; - uint8_t code_align; - uint8_t data_align; - uint8_t return_column; -} DebugFrameCIE; - -typedef struct { - uint32_t len __attribute__((aligned((sizeof(void *))))); - uint32_t cie_offset; - tcg_target_long func_start __attribute__((packed)); - tcg_target_long func_len __attribute__((packed)); - uint8_t def_cfa[4]; - uint8_t ret_ofs[3]; - uint8_t reg_ofs[ARRAY_SIZE(tcg_target_callee_save_regs) * 2]; -} DebugFrameFDE; - -typedef struct { DebugFrameCIE cie; - DebugFrameFDE fde; + DebugFrameFDEHeader fde; + uint8_t fde_def_cfa[4]; + uint8_t fde_ret_ofs[3]; + uint8_t fde_reg_ofs[ARRAY_SIZE(tcg_target_callee_save_regs) * 2]; } DebugFrame; #define ELF_HOST_MACHINE EM_PARISC @@ -1806,16 +1789,18 @@ static DebugFrame debug_frame = { .cie.data_align = 1, .cie.return_column = 2, - .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */ - .fde.def_cfa = { + /* Total FDE size does not include the "len" member. */ + .fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset), + + .fde_def_cfa = { 0x12, 30, /* DW_CFA_def_cfa_sf sp, ... */ (-FRAME_SIZE & 0x7f) | 0x80, /* ... sleb128 -FRAME_SIZE */ (-FRAME_SIZE >> 7) & 0x7f }, - .fde.ret_ofs = { + .fde_ret_ofs = { 0x11, 2, (-20 / 4) & 0x7f /* DW_CFA_offset_extended_sf r2, 20 */ }, - .fde.reg_ofs = { + .fde_reg_ofs = { /* This must match the ordering in tcg_target_callee_save_regs. */ 0x80 + 4, 0, /* DW_CFA_offset r4, 0 */ 0x80 + 5, 4, /* DW_CFA_offset r5, 4 */ diff --git a/tcg/hppa/tcg-target.h b/tcg/hppa/tcg-target.h index ebd53d9e36..25467bdd43 100644 --- a/tcg/hppa/tcg-target.h +++ b/tcg/hppa/tcg-target.h @@ -85,6 +85,7 @@ typedef enum { /* optional instructions */ #define TCG_TARGET_HAS_div_i32 0 +#define TCG_TARGET_HAS_rem_i32 0 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_ext8s_i32 1 #define TCG_TARGET_HAS_ext16s_i32 1 diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index 9e95477ef4..87eeab3d30 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -2312,29 +2312,15 @@ static void tcg_target_init(TCGContext *s) } typedef struct { - uint32_t len __attribute__((aligned((sizeof(void *))))); - uint32_t id; - uint8_t version; - char augmentation[1]; - uint8_t code_align; - uint8_t data_align; - uint8_t return_column; -} DebugFrameCIE; - -typedef struct { - uint32_t len __attribute__((aligned((sizeof(void *))))); - uint32_t cie_offset; - tcg_target_long func_start __attribute__((packed)); - tcg_target_long func_len __attribute__((packed)); - uint8_t def_cfa[4]; - uint8_t reg_ofs[14]; -} DebugFrameFDE; - -typedef struct { DebugFrameCIE cie; - DebugFrameFDE fde; + DebugFrameFDEHeader fde; + uint8_t fde_def_cfa[4]; + uint8_t fde_reg_ofs[14]; } DebugFrame; +/* We're expecting a 2 byte uleb128 encoded value. */ +QEMU_BUILD_BUG_ON(FRAME_SIZE >= (1 << 14)); + #if !defined(__ELF__) /* Host machine without ELF. */ #elif TCG_TARGET_REG_BITS == 64 @@ -2347,13 +2333,15 @@ static DebugFrame debug_frame = { .cie.data_align = 0x78, /* sleb128 -8 */ .cie.return_column = 16, - .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */ - .fde.def_cfa = { + /* Total FDE size does not include the "len" member. */ + .fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset), + + .fde_def_cfa = { 12, 7, /* DW_CFA_def_cfa %rsp, ... */ (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */ (FRAME_SIZE >> 7) }, - .fde.reg_ofs = { + .fde_reg_ofs = { 0x90, 1, /* DW_CFA_offset, %rip, -8 */ /* The following ordering must match tcg_target_callee_save_regs. */ 0x86, 2, /* DW_CFA_offset, %rbp, -16 */ @@ -2374,13 +2362,15 @@ static DebugFrame debug_frame = { .cie.data_align = 0x7c, /* sleb128 -4 */ .cie.return_column = 8, - .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */ - .fde.def_cfa = { + /* Total FDE size does not include the "len" member. */ + .fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset), + + .fde_def_cfa = { 12, 4, /* DW_CFA_def_cfa %esp, ... */ (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */ (FRAME_SIZE >> 7) }, - .fde.reg_ofs = { + .fde_reg_ofs = { 0x88, 1, /* DW_CFA_offset, %eip, -4 */ /* The following ordering must match tcg_target_callee_save_regs. */ 0x85, 2, /* DW_CFA_offset, %ebp, -8 */ @@ -2394,9 +2384,6 @@ static DebugFrame debug_frame = { #if defined(ELF_HOST_MACHINE) void tcg_register_jit(void *buf, size_t buf_size) { - /* We're expecting a 2 byte uleb128 encoded value. */ - assert(FRAME_SIZE >> 14 == 0); - debug_frame.fde.func_start = (tcg_target_long) buf; debug_frame.fde.func_len = buf_size; diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h index e3d72ea52f..f32d5199cb 100644 --- a/tcg/ia64/tcg-target.h +++ b/tcg/ia64/tcg-target.h @@ -104,7 +104,9 @@ typedef enum { /* optional instructions */ #define TCG_TARGET_HAS_div_i32 0 +#define TCG_TARGET_HAS_rem_i32 0 #define TCG_TARGET_HAS_div_i64 0 +#define TCG_TARGET_HAS_rem_i64 0 #define TCG_TARGET_HAS_andc_i32 1 #define TCG_TARGET_HAS_andc_i64 1 #define TCG_TARGET_HAS_bswap16_i32 1 diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index 6155327a9a..a438950bc1 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -79,6 +79,7 @@ typedef enum { /* optional instructions */ #define TCG_TARGET_HAS_div_i32 1 +#define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_nor_i32 1 #define TCG_TARGET_HAS_ext8s_i32 1 diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c index 29ca934e66..453ab6b580 100644 --- a/tcg/ppc/tcg-target.c +++ b/tcg/ppc/tcg-target.c @@ -1671,18 +1671,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, tcg_out32 (s, DIVWU | TAB (args[0], args[1], args[2])); break; - case INDEX_op_rem_i32: - tcg_out32 (s, DIVW | TAB (0, args[1], args[2])); - tcg_out32 (s, MULLW | TAB (0, 0, args[2])); - tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); - break; - - case INDEX_op_remu_i32: - tcg_out32 (s, DIVWU | TAB (0, args[1], args[2])); - tcg_out32 (s, MULLW | TAB (0, 0, args[2])); - tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); - break; - case INDEX_op_mulu2_i32: if (args[0] == args[2] || args[0] == args[3]) { tcg_out32 (s, MULLW | TAB (0, args[2], args[3])); @@ -1992,8 +1980,6 @@ static const TCGTargetOpDef ppc_op_defs[] = { { INDEX_op_mul_i32, { "r", "r", "ri" } }, { INDEX_op_div_i32, { "r", "r", "r" } }, { INDEX_op_divu_i32, { "r", "r", "r" } }, - { INDEX_op_rem_i32, { "r", "r", "r" } }, - { INDEX_op_remu_i32, { "r", "r", "r" } }, { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } }, { INDEX_op_sub_i32, { "r", "r", "ri" } }, { INDEX_op_and_i32, { "r", "r", "ri" } }, diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index 17a6bb367a..b42d97cc24 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -78,6 +78,7 @@ typedef enum { /* optional instructions */ #define TCG_TARGET_HAS_div_i32 1 +#define TCG_TARGET_HAS_rem_i32 0 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_ext8s_i32 1 #define TCG_TARGET_HAS_ext16s_i32 1 diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c index 606b73defc..0678de2045 100644 --- a/tcg/ppc64/tcg-target.c +++ b/tcg/ppc64/tcg-target.c @@ -1617,18 +1617,6 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args, tcg_out32 (s, DIVWU | TAB (args[0], args[1], args[2])); break; - case INDEX_op_rem_i32: - tcg_out32 (s, DIVW | TAB (0, args[1], args[2])); - tcg_out32 (s, MULLW | TAB (0, 0, args[2])); - tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); - break; - - case INDEX_op_remu_i32: - tcg_out32 (s, DIVWU | TAB (0, args[1], args[2])); - tcg_out32 (s, MULLW | TAB (0, 0, args[2])); - tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); - break; - case INDEX_op_shl_i32: if (const_args[2]) { tcg_out_rlw(s, RLWINM, args[0], args[1], args[2], 0, 31 - args[2]); @@ -1786,16 +1774,6 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args, case INDEX_op_divu_i64: tcg_out32 (s, DIVDU | TAB (args[0], args[1], args[2])); break; - case INDEX_op_rem_i64: - tcg_out32 (s, DIVD | TAB (0, args[1], args[2])); - tcg_out32 (s, MULLD | TAB (0, 0, args[2])); - tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); - break; - case INDEX_op_remu_i64: - tcg_out32 (s, DIVDU | TAB (0, args[1], args[2])); - tcg_out32 (s, MULLD | TAB (0, 0, args[2])); - tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); - break; case INDEX_op_qemu_ld8u: tcg_out_qemu_ld (s, args, 0); @@ -2064,8 +2042,6 @@ static const TCGTargetOpDef ppc_op_defs[] = { { INDEX_op_mul_i32, { "r", "r", "rI" } }, { INDEX_op_div_i32, { "r", "r", "r" } }, { INDEX_op_divu_i32, { "r", "r", "r" } }, - { INDEX_op_rem_i32, { "r", "r", "r" } }, - { INDEX_op_remu_i32, { "r", "r", "r" } }, { INDEX_op_sub_i32, { "r", "rI", "ri" } }, { INDEX_op_and_i32, { "r", "r", "ri" } }, { INDEX_op_or_i32, { "r", "r", "ri" } }, @@ -2108,8 +2084,6 @@ static const TCGTargetOpDef ppc_op_defs[] = { { INDEX_op_mul_i64, { "r", "r", "rI" } }, { INDEX_op_div_i64, { "r", "r", "r" } }, { INDEX_op_divu_i64, { "r", "r", "r" } }, - { INDEX_op_rem_i64, { "r", "r", "r" } }, - { INDEX_op_remu_i64, { "r", "r", "r" } }, { INDEX_op_neg_i64, { "r", "r" } }, { INDEX_op_not_i64, { "r", "r" } }, diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h index cb77634714..48fc6e2e54 100644 --- a/tcg/ppc64/tcg-target.h +++ b/tcg/ppc64/tcg-target.h @@ -76,6 +76,7 @@ typedef enum { /* optional instructions */ #define TCG_TARGET_HAS_div_i32 1 +#define TCG_TARGET_HAS_rem_i32 0 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_ext8s_i32 1 #define TCG_TARGET_HAS_ext16s_i32 1 @@ -96,6 +97,7 @@ typedef enum { #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_div_i64 1 +#define TCG_TARGET_HAS_rem_i64 0 #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_ext8s_i64 1 #define TCG_TARGET_HAS_ext16s_i64 1 diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index 025af9b379..5bfd29c3b4 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -1647,28 +1647,11 @@ static void tcg_target_init(TCGContext *s) #endif typedef struct { - uint32_t len __attribute__((aligned((sizeof(void *))))); - uint32_t id; - uint8_t version; - char augmentation[1]; - uint8_t code_align; - uint8_t data_align; - uint8_t return_column; -} DebugFrameCIE; - -typedef struct { - uint32_t len __attribute__((aligned((sizeof(void *))))); - uint32_t cie_offset; - tcg_target_long func_start __attribute__((packed)); - tcg_target_long func_len __attribute__((packed)); - uint8_t def_cfa[TCG_TARGET_REG_BITS == 64 ? 4 : 2]; - uint8_t win_save; - uint8_t ret_save[3]; -} DebugFrameFDE; - -typedef struct { DebugFrameCIE cie; - DebugFrameFDE fde; + DebugFrameFDEHeader fde; + uint8_t fde_def_cfa[TCG_TARGET_REG_BITS == 64 ? 4 : 2]; + uint8_t fde_win_save; + uint8_t fde_ret_save[3]; } DebugFrame; static DebugFrame debug_frame = { @@ -1679,8 +1662,10 @@ static DebugFrame debug_frame = { .cie.data_align = -sizeof(void *) & 0x7f, .cie.return_column = 15, /* o7 */ - .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */ - .fde.def_cfa = { + /* Total FDE size does not include the "len" member. */ + .fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset), + + .fde_def_cfa = { #if TCG_TARGET_REG_BITS == 64 12, 30, /* DW_CFA_def_cfa i6, 2047 */ (2047 & 0x7f) | 0x80, (2047 >> 7) @@ -1688,8 +1673,8 @@ static DebugFrame debug_frame = { 13, 30 /* DW_CFA_def_cfa_register i6 */ #endif }, - .fde.win_save = 0x2d, /* DW_CFA_GNU_window_save */ - .fde.ret_save = { 9, 15, 31 }, /* DW_CFA_register o7, i7 */ + .fde_win_save = 0x2d, /* DW_CFA_GNU_window_save */ + .fde_ret_save = { 9, 15, 31 }, /* DW_CFA_register o7, i7 */ }; void tcg_register_jit(void *buf, size_t buf_size) diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h index b5217bef25..dab52d7176 100644 --- a/tcg/sparc/tcg-target.h +++ b/tcg/sparc/tcg-target.h @@ -86,6 +86,7 @@ typedef enum { /* optional instructions */ #define TCG_TARGET_HAS_div_i32 1 +#define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_rot_i32 0 #define TCG_TARGET_HAS_ext8s_i32 0 #define TCG_TARGET_HAS_ext16s_i32 0 @@ -109,6 +110,7 @@ typedef enum { #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_div_i64 1 +#define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_rot_i64 0 #define TCG_TARGET_HAS_ext8s_i64 0 #define TCG_TARGET_HAS_ext16s_i64 0 diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 94f6043786..364964d8d4 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -731,8 +731,14 @@ static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_div_i32) { + if (TCG_TARGET_HAS_rem_i32) { tcg_gen_op3_i32(INDEX_op_rem_i32, ret, arg1, arg2); + } else if (TCG_TARGET_HAS_div_i32) { + TCGv_i32 t0 = tcg_temp_new_i32(); + tcg_gen_op3_i32(INDEX_op_div_i32, t0, arg1, arg2); + tcg_gen_mul_i32(t0, t0, arg2); + tcg_gen_sub_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); } else if (TCG_TARGET_HAS_div2_i32) { TCGv_i32 t0 = tcg_temp_new_i32(); tcg_gen_sari_i32(t0, arg1, 31); @@ -769,8 +775,14 @@ static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_div_i32) { + if (TCG_TARGET_HAS_rem_i32) { tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2); + } else if (TCG_TARGET_HAS_div_i32) { + TCGv_i32 t0 = tcg_temp_new_i32(); + tcg_gen_op3_i32(INDEX_op_divu_i32, t0, arg1, arg2); + tcg_gen_mul_i32(t0, t0, arg2); + tcg_gen_sub_i32(ret, arg1, t0); + tcg_temp_free_i32(t0); } else if (TCG_TARGET_HAS_div2_i32) { TCGv_i32 t0 = tcg_temp_new_i32(); tcg_gen_movi_i32(t0, 0); @@ -1361,8 +1373,14 @@ static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - if (TCG_TARGET_HAS_div_i64) { + if (TCG_TARGET_HAS_rem_i64) { tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2); + } else if (TCG_TARGET_HAS_div_i64) { + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_op3_i64(INDEX_op_div_i64, t0, arg1, arg2); + tcg_gen_mul_i64(t0, t0, arg2); + tcg_gen_sub_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); } else if (TCG_TARGET_HAS_div2_i64) { TCGv_i64 t0 = tcg_temp_new_i64(); tcg_gen_sari_i64(t0, arg1, 63); @@ -1399,8 +1417,14 @@ static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - if (TCG_TARGET_HAS_div_i64) { + if (TCG_TARGET_HAS_rem_i64) { tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2); + } else if (TCG_TARGET_HAS_div_i64) { + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_op3_i64(INDEX_op_divu_i64, t0, arg1, arg2); + tcg_gen_mul_i64(t0, t0, arg2); + tcg_gen_sub_i64(ret, arg1, t0); + tcg_temp_free_i64(t0); } else if (TCG_TARGET_HAS_div2_i64) { TCGv_i64 t0 = tcg_temp_new_i64(); tcg_gen_movi_i64(t0, 0); diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h index 4246e9c1fa..a8af5b96a4 100644 --- a/tcg/tcg-opc.h +++ b/tcg/tcg-opc.h @@ -27,20 +27,24 @@ */ /* predefined ops */ -DEF(end, 0, 0, 0, 0) /* must be kept first */ -DEF(nop, 0, 0, 0, 0) -DEF(nop1, 0, 0, 1, 0) -DEF(nop2, 0, 0, 2, 0) -DEF(nop3, 0, 0, 3, 0) -DEF(nopn, 0, 0, 1, 0) /* variable number of parameters */ +DEF(end, 0, 0, 0, TCG_OPF_NOT_PRESENT) /* must be kept first */ +DEF(nop, 0, 0, 0, TCG_OPF_NOT_PRESENT) +DEF(nop1, 0, 0, 1, TCG_OPF_NOT_PRESENT) +DEF(nop2, 0, 0, 2, TCG_OPF_NOT_PRESENT) +DEF(nop3, 0, 0, 3, TCG_OPF_NOT_PRESENT) -DEF(discard, 1, 0, 0, 0) +/* variable number of parameters */ +DEF(nopn, 0, 0, 1, TCG_OPF_NOT_PRESENT) + +DEF(discard, 1, 0, 0, TCG_OPF_NOT_PRESENT) +DEF(set_label, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_NOT_PRESENT) + +/* variable number of parameters */ +DEF(call, 0, 1, 2, TCG_OPF_CALL_CLOBBER) -DEF(set_label, 0, 0, 1, TCG_OPF_BB_END) -DEF(call, 0, 1, 2, TCG_OPF_CALL_CLOBBER) /* variable number of parameters */ DEF(br, 0, 0, 1, TCG_OPF_BB_END) -#define IMPL(X) (X ? 0 : TCG_OPF_NOT_PRESENT) +#define IMPL(X) (__builtin_constant_p(X) && !(X) ? TCG_OPF_NOT_PRESENT : 0) #if TCG_TARGET_REG_BITS == 32 # define IMPL64 TCG_OPF_64BIT | TCG_OPF_NOT_PRESENT #else @@ -66,8 +70,8 @@ DEF(sub_i32, 1, 2, 0, 0) DEF(mul_i32, 1, 2, 0, 0) DEF(div_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_div_i32)) DEF(divu_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_div_i32)) -DEF(rem_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_div_i32)) -DEF(remu_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_div_i32)) +DEF(rem_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_rem_i32)) +DEF(remu_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_rem_i32)) DEF(div2_i32, 2, 3, 0, IMPL(TCG_TARGET_HAS_div2_i32)) DEF(divu2_i32, 2, 3, 0, IMPL(TCG_TARGET_HAS_div2_i32)) DEF(and_i32, 1, 2, 0, 0) @@ -126,8 +130,8 @@ DEF(sub_i64, 1, 2, 0, IMPL64) DEF(mul_i64, 1, 2, 0, IMPL64) DEF(div_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_div_i64)) DEF(divu_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_div_i64)) -DEF(rem_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_div_i64)) -DEF(remu_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_div_i64)) +DEF(rem_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_rem_i64)) +DEF(remu_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_rem_i64)) DEF(div2_i64, 2, 3, 0, IMPL64 | IMPL(TCG_TARGET_HAS_div2_i64)) DEF(divu2_i64, 2, 3, 0, IMPL64 | IMPL(TCG_TARGET_HAS_div2_i64)) DEF(and_i64, 1, 2, 0, IMPL64) @@ -166,9 +170,9 @@ DEF(muls2_i64, 2, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_muls2_i64)) /* QEMU specific */ #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS -DEF(debug_insn_start, 0, 0, 2, 0) +DEF(debug_insn_start, 0, 0, 2, TCG_OPF_NOT_PRESENT) #else -DEF(debug_insn_start, 0, 0, 1, 0) +DEF(debug_insn_start, 0, 0, 1, TCG_OPF_NOT_PRESENT) #endif DEF(exit_tb, 0, 0, 1, TCG_OPF_BB_END) DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_END) @@ -68,6 +68,24 @@ static void tcg_target_qemu_prologue(TCGContext *s); static void patch_reloc(uint8_t *code_ptr, int type, tcg_target_long value, tcg_target_long addend); +/* The CIE and FDE header definitions will be common to all hosts. */ +typedef struct { + uint32_t len __attribute__((aligned((sizeof(void *))))); + uint32_t id; + uint8_t version; + char augmentation[1]; + uint8_t code_align; + uint8_t data_align; + uint8_t return_column; +} DebugFrameCIE; + +typedef struct QEMU_PACKED { + uint32_t len __attribute__((aligned((sizeof(void *))))); + uint32_t cie_offset; + tcg_target_long func_start; + tcg_target_long func_len; +} DebugFrameFDEHeader; + static void tcg_register_jit_int(void *buf, size_t size, void *debug_frame, size_t debug_frame_size) __attribute__((unused)); @@ -1160,9 +1178,7 @@ void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs) i = 0; for (op = 0; op < ARRAY_SIZE(tcg_op_defs); op++) { const TCGOpDef *def = &tcg_op_defs[op]; - if (op < INDEX_op_call - || op == INDEX_op_debug_insn_start - || (def->flags & TCG_OPF_NOT_PRESENT)) { + if (def->flags & TCG_OPF_NOT_PRESENT) { /* Wrong entry in op definitions? */ if (def->used) { fprintf(stderr, "Invalid op definition for %s\n", def->name); @@ -2659,9 +2675,9 @@ static void tcg_register_jit_int(void *buf_ptr, size_t buf_size, img->sym[1].st_size = buf_size; img->di.cu_low_pc = buf; - img->di.cu_high_pc = buf_size; + img->di.cu_high_pc = buf + buf_size; img->di.fn_low_pc = buf; - img->di.fn_high_pc = buf_size; + img->di.fn_high_pc = buf + buf_size; #ifdef DEBUG_JIT /* Enable this block to be able to debug the ELF image file creation. @@ -60,6 +60,7 @@ typedef uint64_t TCGRegSet; #if TCG_TARGET_REG_BITS == 32 /* Turn some undef macros into false macros. */ #define TCG_TARGET_HAS_div_i64 0 +#define TCG_TARGET_HAS_rem_i64 0 #define TCG_TARGET_HAS_div2_i64 0 #define TCG_TARGET_HAS_rot_i64 0 #define TCG_TARGET_HAS_ext8s_i64 0 @@ -102,11 +103,13 @@ typedef uint64_t TCGRegSet; #define TCG_TARGET_HAS_div2_i32 0 #elif defined(TCG_TARGET_HAS_div2_i32) #define TCG_TARGET_HAS_div_i32 0 +#define TCG_TARGET_HAS_rem_i32 0 #endif #if defined(TCG_TARGET_HAS_div_i64) #define TCG_TARGET_HAS_div2_i64 0 #elif defined(TCG_TARGET_HAS_div2_i64) #define TCG_TARGET_HAS_div_i64 0 +#define TCG_TARGET_HAS_rem_i64 0 #endif typedef enum TCGOpcode { @@ -593,7 +596,8 @@ enum { TCG_OPF_SIDE_EFFECTS = 0x04, /* Instruction operands are 64-bits (otherwise 32-bits). */ TCG_OPF_64BIT = 0x08, - /* Instruction is optional and not implemented by the host. */ + /* Instruction is optional and not implemented by the host, or insn + is generic and should not be implemened by the host. */ TCG_OPF_NOT_PRESENT = 0x10, }; diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index 0395bbb8e4..d7fc14eb17 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -59,9 +59,8 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -/* Not more than one of the next two defines must be 1. */ #define TCG_TARGET_HAS_div_i32 1 -#define TCG_TARGET_HAS_div2_i32 0 +#define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_ext8s_i32 1 #define TCG_TARGET_HAS_ext16s_i32 1 #define TCG_TARGET_HAS_ext8u_i32 1 @@ -83,9 +82,8 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_deposit_i64 1 -/* Not more than one of the next two defines must be 1. */ #define TCG_TARGET_HAS_div_i64 0 -#define TCG_TARGET_HAS_div2_i64 0 +#define TCG_TARGET_HAS_rem_i64 0 #define TCG_TARGET_HAS_ext8s_i64 1 #define TCG_TARGET_HAS_ext16s_i64 1 #define TCG_TARGET_HAS_ext32s_i64 1 diff --git a/user-exec.c b/user-exec.c index 26cde7c57c..d45ca8e877 100644 --- a/user-exec.c +++ b/user-exec.c @@ -20,6 +20,7 @@ #include "cpu.h" #include "disas/disas.h" #include "tcg.h" +#include "qemu/bitops.h" #undef EAX #undef ECX @@ -442,8 +443,11 @@ int cpu_signal_handler(int host_signum, void *pinfo, #else pc = uc->uc_mcontext.arm_pc; #endif - /* XXX: compute is_write */ - is_write = 0; + + /* error_code is the FSR value, in which bit 11 is WnR (assuming a v6 or + * later processor; on v5 we will always report this as a read). + */ + is_write = extract32(uc->uc_mcontext.error_code, 11, 1); return handle_cpu_signal(pc, (unsigned long)info->si_addr, is_write, &uc->uc_sigmask, puc); diff --git a/util/qemu-option.c b/util/qemu-option.c index 412c425518..e0ef426daa 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -706,16 +706,12 @@ QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id) QemuOpts *opts; QTAILQ_FOREACH(opts, &list->head, next) { - if (!opts->id) { - if (!id) { - return opts; - } - continue; + if (!opts->id && !id) { + return opts; } - if (strcmp(opts->id, id) != 0) { - continue; + if (opts->id && id && !strcmp(opts->id, id)) { + return opts; } - return opts; } return NULL; } @@ -918,15 +914,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, get_opt_value(value, sizeof(value), p+4); id = value; } - if (defaults) { - if (!id && !QTAILQ_EMPTY(&list->head)) { - opts = qemu_opts_find(list, NULL); - } else { - opts = qemu_opts_create(list, id, 0, &local_err); - } - } else { - opts = qemu_opts_create(list, id, 1, &local_err); - } + opts = qemu_opts_create(list, id, !defaults, &local_err); if (opts == NULL) { if (error_is_set(&local_err)) { qerror_report_err(local_err); @@ -409,7 +409,7 @@ static QemuOptsList qemu_machine_opts = { .help = "Dump current dtb to a file and quit", }, { .name = "phandle_start", - .type = QEMU_OPT_STRING, + .type = QEMU_OPT_NUMBER, .help = "The first phandle ID we may generate dynamically", }, { .name = "dt_compatible", @@ -516,6 +516,25 @@ static QemuOptsList qemu_realtime_opts = { }, }; +/** + * Get machine options + * + * Returns: machine options (never null). + */ +QemuOpts *qemu_get_machine_opts(void) +{ + QemuOptsList *list; + QemuOpts *opts; + + list = qemu_find_opts("machine"); + assert(list); + opts = qemu_opts_find(list, NULL); + if (!opts) { + opts = qemu_opts_create_nofail(list); + } + return opts; +} + const char *qemu_get_vm_name(void) { return qemu_name; @@ -1017,15 +1036,9 @@ static int parse_sandbox(QemuOpts *opts, void *opaque) return 0; } -/*********QEMU USB setting******/ bool usb_enabled(bool default_usb) { - QemuOpts *mach_opts; - mach_opts = qemu_opts_find(qemu_find_opts("machine"), 0); - if (mach_opts) { - return qemu_opt_get_bool(mach_opts, "usb", default_usb); - } - return default_usb; + return qemu_opt_get_bool(qemu_get_machine_opts(), "usb", default_usb); } #ifndef _WIN32 @@ -2672,17 +2685,13 @@ static struct { static int configure_accelerator(void) { - const char *p = NULL; + const char *p; char buf[10]; int i, ret; bool accel_initialised = false; bool init_failed = false; - QemuOptsList *list = qemu_find_opts("machine"); - if (!QTAILQ_EMPTY(&list->head)) { - p = qemu_opt_get(QTAILQ_FIRST(&list->head), "accel"); - } - + p = qemu_opt_get(qemu_get_machine_opts(), "accel"); if (p == NULL) { /* Use the default "accelerator", tcg */ p = "tcg"; @@ -4080,14 +4089,10 @@ int main(int argc, char **argv, char **envp) qtest_init(); } - machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); - if (machine_opts) { - kernel_filename = qemu_opt_get(machine_opts, "kernel"); - initrd_filename = qemu_opt_get(machine_opts, "initrd"); - kernel_cmdline = qemu_opt_get(machine_opts, "append"); - } else { - kernel_filename = initrd_filename = kernel_cmdline = NULL; - } + machine_opts = qemu_get_machine_opts(); + kernel_filename = qemu_opt_get(machine_opts, "kernel"); + initrd_filename = qemu_opt_get(machine_opts, "initrd"); + kernel_cmdline = qemu_opt_get(machine_opts, "append"); if (!boot_order) { boot_order = machine->boot_order; @@ -4130,7 +4135,7 @@ int main(int argc, char **argv, char **envp) exit(1); } - if (!linux_boot && machine_opts && qemu_opt_get(machine_opts, "dtb")) { + if (!linux_boot && qemu_opt_get(machine_opts, "dtb")) { fprintf(stderr, "-dtb only allowed with -kernel option\n"); exit(1); } |