diff options
58 files changed, 1249 insertions, 958 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index b692c8fbee..06642d9799 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1827,6 +1827,7 @@ USB M: Gerd Hoffmann <kraxel@redhat.com> S: Maintained F: hw/usb/* +F: stubs/usb-dev-stub.c F: tests/qtest/usb-*-test.c F: docs/usb2.txt F: docs/usb-storage.txt diff --git a/configure b/configure index 54f8475444..f3fe75db9d 100755 --- a/configure +++ b/configure @@ -5440,9 +5440,16 @@ if { test "$cpu" = "i386" || test "$cpu" = "x86_64"; } && \ fi # Only build s390-ccw bios if we're on s390x and the compiler has -march=z900 +# or -march=z10 (which is the lowest architecture level that Clang supports) if test "$cpu" = "s390x" ; then write_c_skeleton - if compile_prog "-march=z900" ""; then + compile_prog "-march=z900" "" + has_z900=$? + if [ $has_z900 = 0 ] || compile_prog "-march=z10" ""; then + if [ $has_z900 != 0 ]; then + echo "WARNING: Your compiler does not support the z900!" + echo " The s390-ccw bios will only work with guest CPUs >= z10." + fi roms="$roms s390-ccw" # SLOF is required for building the s390-ccw firmware on s390x, # since it is using the libnet code from SLOF for network booting. diff --git a/disas/arm-a64.cc b/disas/arm-a64.cc index 27613d4b25..a1402a2e07 100644 --- a/disas/arm-a64.cc +++ b/disas/arm-a64.cc @@ -18,9 +18,7 @@ */ #include "qemu/osdep.h" -extern "C" { #include "disas/dis-asm.h" -} #include "vixl/a64/disasm-a64.h" diff --git a/disas/nanomips.cpp b/disas/nanomips.cpp index 8ddef897f0..9be8df75dd 100644 --- a/disas/nanomips.cpp +++ b/disas/nanomips.cpp @@ -28,9 +28,7 @@ */ #include "qemu/osdep.h" -extern "C" { #include "disas/dis-asm.h" -} #include <cstring> #include <stdexcept> diff --git a/docs/system/arm/mps2.rst b/docs/system/arm/mps2.rst index f83b151787..8a75beb3a0 100644 --- a/docs/system/arm/mps2.rst +++ b/docs/system/arm/mps2.rst @@ -45,3 +45,13 @@ Differences between QEMU and real hardware: flash, but only as simple ROM, so attempting to rewrite the flash from the guest will fail - QEMU does not model the USB controller in MPS3 boards + +Machine-specific options +"""""""""""""""""""""""" + +The following machine-specific options are supported: + +remap + Supported for ``mps3-an524`` only. + Set ``BRAM``/``QSPI`` to select the initial memory mapping. The + default is ``BRAM``. diff --git a/docs/system/arm/sbsa.rst b/docs/system/arm/sbsa.rst index b8ecfdb62f..27b0999aac 100644 --- a/docs/system/arm/sbsa.rst +++ b/docs/system/arm/sbsa.rst @@ -4,7 +4,7 @@ Arm Server Base System Architecture Reference board (``sbsa-ref``) While the `virt` board is a generic board platform that doesn't match any real hardware the `sbsa-ref` board intends to look like real hardware. The `Server Base System Architecture -<https://developer.arm.com/documentation/den0029/latest>` defines a +<https://developer.arm.com/documentation/den0029/latest>`_ defines a minimum base line of hardware support and importantly how the firmware reports that to any operating system. It is a static system that reports a very minimal DT to the firmware for non-discoverable diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c index 11426e5ec0..bd16acd4d9 100644 --- a/hw/arm/imx25_pdk.c +++ b/hw/arm/imx25_pdk.c @@ -65,7 +65,6 @@ static struct arm_boot_info imx25_pdk_binfo; static void imx25_pdk_init(MachineState *machine) { - MachineClass *mc = MACHINE_GET_CLASS(machine); IMX25PDK *s = g_new0(IMX25PDK, 1); unsigned int ram_size; unsigned int alias_offset; @@ -77,8 +76,8 @@ static void imx25_pdk_init(MachineState *machine) /* We need to initialize our memory */ if (machine->ram_size > (FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE)) { - char *sz = size_to_str(mc->default_ram_size); - error_report("Invalid RAM size, should be %s", sz); + char *sz = size_to_str(FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE); + error_report("RAM size more than %s is not supported", sz); g_free(sz); exit(EXIT_FAILURE); } diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 25016e464d..70aa31a7f6 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -55,6 +55,7 @@ #include "hw/boards.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" +#include "sysemu/reset.h" #include "hw/misc/unimp.h" #include "hw/char/cmsdk-apb-uart.h" #include "hw/timer/cmsdk-apb-timer.h" @@ -72,6 +73,7 @@ #include "hw/core/split-irq.h" #include "hw/qdev-clock.h" #include "qom/object.h" +#include "hw/irq.h" #define MPS2TZ_NUMIRQ_MAX 96 #define MPS2TZ_RAM_MAX 5 @@ -153,6 +155,9 @@ struct MPS2TZMachineState { SplitIRQ cpu_irq_splitter[MPS2TZ_NUMIRQ_MAX]; Clock *sysclk; Clock *s32kclk; + + bool remap; + qemu_irq remap_irq; }; #define TYPE_MPS2TZ_MACHINE "mps2tz" @@ -228,6 +233,10 @@ static const RAMInfo an505_raminfo[] = { { }, }; +/* + * Note that the addresses and MPC numbering here should match up + * with those used in remap_memory(), which can swap the BRAM and QSPI. + */ static const RAMInfo an524_raminfo[] = { { .name = "bram", .base = 0x00000000, @@ -457,6 +466,7 @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque, object_initialize_child(OBJECT(mms), "scc", scc, TYPE_MPS2_SCC); sccdev = DEVICE(scc); + qdev_prop_set_uint32(sccdev, "scc-cfg0", mms->remap ? 1 : 0); qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2); qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008); qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id); @@ -573,6 +583,52 @@ static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque, return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0); } +static hwaddr boot_mem_base(MPS2TZMachineState *mms) +{ + /* + * Return the canonical address of the block which will be mapped + * at address 0x0 (i.e. where the vector table is). + * This is usually 0, but if the AN524 alternate memory map is + * enabled it will be the base address of the QSPI block. + */ + return mms->remap ? 0x28000000 : 0; +} + +static void remap_memory(MPS2TZMachineState *mms, int map) +{ + /* + * Remap the memory for the AN524. 'map' is the value of + * SCC CFG_REG0 bit 0, i.e. 0 for the default map and 1 + * for the "option 1" mapping where QSPI is at address 0. + * + * Effectively we need to swap around the "upstream" ends of + * MPC 0 and MPC 1. + */ + MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); + int i; + + if (mmc->fpga_type != FPGA_AN524) { + return; + } + + memory_region_transaction_begin(); + for (i = 0; i < 2; i++) { + TZMPC *mpc = &mms->mpc[i]; + MemoryRegion *upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1); + hwaddr addr = (i ^ map) ? 0x28000000 : 0; + + memory_region_set_address(upstream, addr); + } + memory_region_transaction_commit(); +} + +static void remap_irq_fn(void *opaque, int n, int level) +{ + MPS2TZMachineState *mms = opaque; + + remap_memory(mms, level); +} + static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque, const char *name, hwaddr size, const int *irqs) @@ -711,7 +767,7 @@ static uint32_t boot_ram_size(MPS2TZMachineState *mms) MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); for (p = mmc->raminfo; p->name; p++) { - if (p->base == 0) { + if (p->base == boot_mem_base(mms)) { return p->size; } } @@ -1095,6 +1151,16 @@ static void mps2tz_common_init(MachineState *machine) create_non_mpc_ram(mms); + if (mmc->fpga_type == FPGA_AN524) { + /* + * Connect the line from the SCC so that we can remap when the + * guest updates that register. + */ + mms->remap_irq = qemu_allocate_irq(remap_irq_fn, mms, 0); + qdev_connect_gpio_out_named(DEVICE(&mms->scc), "remap", 0, + mms->remap_irq); + } + armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, boot_ram_size(mms)); } @@ -1117,12 +1183,47 @@ static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address, *iregion = region; } +static char *mps2_get_remap(Object *obj, Error **errp) +{ + MPS2TZMachineState *mms = MPS2TZ_MACHINE(obj); + const char *val = mms->remap ? "QSPI" : "BRAM"; + return g_strdup(val); +} + +static void mps2_set_remap(Object *obj, const char *value, Error **errp) +{ + MPS2TZMachineState *mms = MPS2TZ_MACHINE(obj); + + if (!strcmp(value, "BRAM")) { + mms->remap = false; + } else if (!strcmp(value, "QSPI")) { + mms->remap = true; + } else { + error_setg(errp, "Invalid remap value"); + error_append_hint(errp, "Valid values are BRAM and QSPI.\n"); + } +} + +static void mps2_machine_reset(MachineState *machine) +{ + MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine); + + /* + * Set the initial memory mapping before triggering the reset of + * the rest of the system, so that the guest image loader and CPU + * reset see the correct mapping. + */ + remap_memory(mms, mms->remap); + qemu_devices_reset(); +} + static void mps2tz_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc); mc->init = mps2tz_common_init; + mc->reset = mps2_machine_reset; iic->check = mps2_tz_idau_check; } @@ -1225,6 +1326,11 @@ static void mps3tz_an524_class_init(ObjectClass *oc, void *data) mmc->raminfo = an524_raminfo; mmc->armsse_type = TYPE_SSE200; mps2tz_set_default_ram_info(mmc); + + object_class_property_add_str(oc, "remap", mps2_get_remap, mps2_set_remap); + object_class_property_set_description(oc, "remap", + "Set memory mapping. Valid values " + "are BRAM (default) and QSPI."); } static void mps3tz_an547_class_init(ObjectClass *oc, void *data) diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 85f25d15db..81af32dc42 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -118,7 +118,7 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qdev_set_nic_properties(dev, nd); } - object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort); + object_property_set_int(OBJECT(dev), "phy-addr", 7, &error_abort); s = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, base); diff --git a/hw/misc/mps2-scc.c b/hw/misc/mps2-scc.c index c56aca86ad..b3b42a792c 100644 --- a/hw/misc/mps2-scc.c +++ b/hw/misc/mps2-scc.c @@ -23,6 +23,7 @@ #include "qemu/bitops.h" #include "trace.h" #include "hw/sysbus.h" +#include "hw/irq.h" #include "migration/vmstate.h" #include "hw/registerfields.h" #include "hw/misc/mps2-scc.h" @@ -186,10 +187,13 @@ static void mps2_scc_write(void *opaque, hwaddr offset, uint64_t value, switch (offset) { case A_CFG0: /* - * TODO on some boards bit 0 controls RAM remapping; - * on others bit 1 is CPU_WAIT. + * On some boards bit 0 controls board-specific remapping; + * we always reflect bit 0 in the 'remap' GPIO output line, + * and let the board wire it up or not as it chooses. + * TODO on some boards bit 1 is CPU_WAIT. */ s->cfg0 = value; + qemu_set_irq(s->remap, s->cfg0 & 1); break; case A_CFG1: s->cfg1 = value; @@ -283,7 +287,7 @@ static void mps2_scc_reset(DeviceState *dev) int i; trace_mps2_scc_reset(); - s->cfg0 = 0; + s->cfg0 = s->cfg0_reset; s->cfg1 = 0; s->cfg2 = 0; s->cfg5 = 0; @@ -308,6 +312,7 @@ static void mps2_scc_init(Object *obj) memory_region_init_io(&s->iomem, obj, &mps2_scc_ops, s, "mps2-scc", 0x1000); sysbus_init_mmio(sbd, &s->iomem); + qdev_init_gpio_out_named(DEVICE(obj), &s->remap, "remap", 1); } static void mps2_scc_realize(DeviceState *dev, Error **errp) @@ -353,6 +358,8 @@ static Property mps2_scc_properties[] = { DEFINE_PROP_UINT32("scc-cfg4", MPS2SCC, cfg4, 0), DEFINE_PROP_UINT32("scc-aid", MPS2SCC, aid, 0), DEFINE_PROP_UINT32("scc-id", MPS2SCC, id, 0), + /* Reset value for CFG0 register */ + DEFINE_PROP_UINT32("scc-cfg0", MPS2SCC, cfg0_reset, 0), /* * These are the initial settings for the source clocks on the board. * In hardware they can be configured via a config file read by the diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c index 1f946908fe..b67def6381 100644 --- a/hw/sd/omap_mmc.c +++ b/hw/sd/omap_mmc.c @@ -318,7 +318,7 @@ void omap_mmc_reset(struct omap_mmc_s *host) * into any bus, and we must reset it manually. When omap_mmc is * QOMified this must move into the QOM reset function. */ - device_legacy_reset(DEVICE(host->card)); + device_cold_reset(DEVICE(host->card)); } static uint64_t omap_mmc_read(void *opaque, hwaddr offset, diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index eb5d2a6792..7b4dec1721 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -136,7 +136,36 @@ static void main_cpu_reset(void *opaque) env->regbase[6] = s->sp; } -void leon3_irq_ack(void *irq_manager, int intno) +static void leon3_cache_control_int(CPUSPARCState *env) +{ + uint32_t state = 0; + + if (env->cache_control & CACHE_CTRL_IF) { + /* Instruction cache state */ + state = env->cache_control & CACHE_STATE_MASK; + if (state == CACHE_ENABLED) { + state = CACHE_FROZEN; + trace_int_helper_icache_freeze(); + } + + env->cache_control &= ~CACHE_STATE_MASK; + env->cache_control |= state; + } + + if (env->cache_control & CACHE_CTRL_DF) { + /* Data cache state */ + state = (env->cache_control >> 2) & CACHE_STATE_MASK; + if (state == CACHE_ENABLED) { + state = CACHE_FROZEN; + trace_int_helper_dcache_freeze(); + } + + env->cache_control &= ~(CACHE_STATE_MASK << 2); + env->cache_control |= (state << 2); + } +} + +static void leon3_irq_ack(void *irq_manager, int intno) { grlib_irqmp_ack((DeviceState *)irq_manager, intno); } @@ -180,6 +209,12 @@ static void leon3_set_pil_in(void *opaque, int n, int level) } } +static void leon3_irq_manager(CPUSPARCState *env, void *irq_manager, int intno) +{ + leon3_irq_ack(irq_manager, intno); + leon3_cache_control_int(env); +} + static void leon3_generic_hw_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 1a00816d9a..42e139849e 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -107,6 +107,17 @@ struct sun4m_hwdef { uint8_t nvram_machine_id; }; +struct Sun4mMachineClass { + /*< private >*/ + MachineClass parent_obj; + /*< public >*/ + const struct sun4m_hwdef *hwdef; +}; +typedef struct Sun4mMachineClass Sun4mMachineClass; + +#define TYPE_SUN4M_MACHINE MACHINE_TYPE_NAME("sun4m-common") +DECLARE_CLASS_CHECKERS(Sun4mMachineClass, SUN4M_MACHINE, TYPE_SUN4M_MACHINE) + const char *fw_cfg_arch_key_name(uint16_t key) { static const struct { @@ -159,38 +170,6 @@ static void nvram_init(Nvram *nvram, uint8_t *macaddr, } } -void cpu_check_irqs(CPUSPARCState *env) -{ - CPUState *cs; - - /* We should be holding the BQL before we mess with IRQs */ - g_assert(qemu_mutex_iothread_locked()); - - if (env->pil_in && (env->interrupt_index == 0 || - (env->interrupt_index & ~15) == TT_EXTINT)) { - unsigned int i; - - for (i = 15; i > 0; i--) { - if (env->pil_in & (1 << i)) { - int old_interrupt = env->interrupt_index; - - env->interrupt_index = TT_EXTINT | i; - if (old_interrupt != env->interrupt_index) { - cs = env_cpu(env); - trace_sun4m_cpu_interrupt(i); - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } - break; - } - } - } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) { - cs = env_cpu(env); - trace_sun4m_cpu_reset_interrupt(env->interrupt_index & 15); - env->interrupt_index = 0; - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } -} - static void cpu_kick_irq(SPARCCPU *cpu) { CPUSPARCState *env = &cpu->env; @@ -837,9 +816,9 @@ static void dummy_fdc_tc(void *opaque, int irq, int level) { } -static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, - MachineState *machine) +static void sun4m_hw_init(MachineState *machine) { + const struct sun4m_hwdef *hwdef = SUN4M_MACHINE_GET_CLASS(machine)->hwdef; DeviceState *slavio_intctl; unsigned int i; Nvram *nvram; @@ -1127,9 +1106,22 @@ enum { ss600mp_id, }; -static const struct sun4m_hwdef sun4m_hwdefs[] = { - /* SS-5 */ - { +static void sun4m_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->init = sun4m_hw_init; + mc->block_default_type = IF_SCSI; + mc->default_boot_order = "c"; + mc->default_display = "tcx"; + mc->default_ram_id = "sun4m.ram"; +} + +static void ss5_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef ss5_hwdef = { .iommu_base = 0x10000000, .iommu_pad_base = 0x10004000, .iommu_pad_len = 0x0fffb000, @@ -1154,9 +1146,19 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .machine_id = ss5_id, .iommu_version = 0x05000000, .max_mem = 0x10000000, - }, - /* SS-10 */ - { + }; + + mc->desc = "Sun4m platform, SPARCstation 5"; + mc->is_default = true; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904"); + smc->hwdef = &ss5_hwdef; +} + +static void ss10_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef ss10_hwdef = { .iommu_base = 0xfe0000000ULL, .tcx_base = 0xe20000000ULL, .slavio_base = 0xff0000000ULL, @@ -1170,18 +1172,28 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .dma_base = 0xef0400000ULL, .esp_base = 0xef0800000ULL, .le_base = 0xef0c00000ULL, - .apc_base = 0xefa000000ULL, // XXX should not exist + .apc_base = 0xefa000000ULL, /* XXX should not exist */ .aux1_base = 0xff1800000ULL, .aux2_base = 0xff1a01000ULL, .ecc_base = 0xf00000000ULL, - .ecc_version = 0x10000000, // version 0, implementation 1 + .ecc_version = 0x10000000, /* version 0, implementation 1 */ .nvram_machine_id = 0x72, .machine_id = ss10_id, .iommu_version = 0x03000000, .max_mem = 0xf00000000ULL, - }, - /* SS-600MP */ - { + }; + + mc->desc = "Sun4m platform, SPARCstation 10"; + mc->max_cpus = 4; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-SuperSparc-II"); + smc->hwdef = &ss10_hwdef; +} + +static void ss600mp_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef ss600mp_hwdef = { .iommu_base = 0xfe0000000ULL, .tcx_base = 0xe20000000ULL, .slavio_base = 0xff0000000ULL, @@ -1193,18 +1205,28 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .dma_base = 0xef0081000ULL, .esp_base = 0xef0080000ULL, .le_base = 0xef0060000ULL, - .apc_base = 0xefa000000ULL, // XXX should not exist + .apc_base = 0xefa000000ULL, /* XXX should not exist */ .aux1_base = 0xff1800000ULL, - .aux2_base = 0xff1a01000ULL, // XXX should not exist + .aux2_base = 0xff1a01000ULL, /* XXX should not exist */ .ecc_base = 0xf00000000ULL, - .ecc_version = 0x00000000, // version 0, implementation 0 + .ecc_version = 0x00000000, /* version 0, implementation 0 */ .nvram_machine_id = 0x71, .machine_id = ss600mp_id, .iommu_version = 0x01000000, .max_mem = 0xf00000000ULL, - }, - /* SS-20 */ - { + }; + + mc->desc = "Sun4m platform, SPARCserver 600MP"; + mc->max_cpus = 4; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-SuperSparc-II"); + smc->hwdef = &ss600mp_hwdef; +} + +static void ss20_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef ss20_hwdef = { .iommu_base = 0xfe0000000ULL, .tcx_base = 0xe20000000ULL, .slavio_base = 0xff0000000ULL, @@ -1219,7 +1241,7 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .esp_base = 0xef0800000ULL, .le_base = 0xef0c00000ULL, .bpp_base = 0xef4800000ULL, - .apc_base = 0xefa000000ULL, // XXX should not exist + .apc_base = 0xefa000000ULL, /* XXX should not exist */ .aux1_base = 0xff1800000ULL, .aux2_base = 0xff1a01000ULL, .dbri_base = 0xee0000000ULL, @@ -1238,14 +1260,24 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { } }, .ecc_base = 0xf00000000ULL, - .ecc_version = 0x20000000, // version 0, implementation 2 + .ecc_version = 0x20000000, /* version 0, implementation 2 */ .nvram_machine_id = 0x72, .machine_id = ss20_id, .iommu_version = 0x13000000, .max_mem = 0xf00000000ULL, - }, - /* Voyager */ - { + }; + + mc->desc = "Sun4m platform, SPARCstation 20"; + mc->max_cpus = 4; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-SuperSparc-II"); + smc->hwdef = &ss20_hwdef; +} + +static void voyager_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef voyager_hwdef = { .iommu_base = 0x10000000, .tcx_base = 0x50000000, .slavio_base = 0x70000000, @@ -1259,16 +1291,25 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .dma_base = 0x78400000, .esp_base = 0x78800000, .le_base = 0x78c00000, - .apc_base = 0x71300000, // pmc + .apc_base = 0x71300000, /* pmc */ .aux1_base = 0x71900000, .aux2_base = 0x71910000, .nvram_machine_id = 0x80, .machine_id = vger_id, .iommu_version = 0x05000000, .max_mem = 0x10000000, - }, - /* LX */ - { + }; + + mc->desc = "Sun4m platform, SPARCstation Voyager"; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904"); + smc->hwdef = &voyager_hwdef; +} + +static void ss_lx_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef ss_lx_hwdef = { .iommu_base = 0x10000000, .iommu_pad_base = 0x10004000, .iommu_pad_len = 0x0fffb000, @@ -1290,9 +1331,18 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .machine_id = lx_id, .iommu_version = 0x04000000, .max_mem = 0x10000000, - }, - /* SS-4 */ - { + }; + + mc->desc = "Sun4m platform, SPARCstation LX"; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-MicroSparc-I"); + smc->hwdef = &ss_lx_hwdef; +} + +static void ss4_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef ss4_hwdef = { .iommu_base = 0x10000000, .tcx_base = 0x50000000, .cs_base = 0x6c000000, @@ -1314,9 +1364,18 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .machine_id = ss4_id, .iommu_version = 0x05000000, .max_mem = 0x10000000, - }, - /* SPARCClassic */ - { + }; + + mc->desc = "Sun4m platform, SPARCstation 4"; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904"); + smc->hwdef = &ss4_hwdef; +} + +static void scls_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef scls_hwdef = { .iommu_base = 0x10000000, .tcx_base = 0x50000000, .slavio_base = 0x70000000, @@ -1337,11 +1396,20 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .machine_id = scls_id, .iommu_version = 0x05000000, .max_mem = 0x10000000, - }, - /* SPARCbook */ - { + }; + + mc->desc = "Sun4m platform, SPARCClassic"; + mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-MicroSparc-I"); + smc->hwdef = &scls_hwdef; +} + +static void sbook_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); + static const struct sun4m_hwdef sbook_hwdef = { .iommu_base = 0x10000000, - .tcx_base = 0x50000000, // XXX + .tcx_base = 0x50000000, /* XXX */ .slavio_base = 0x70000000, .ms_kb_base = 0x71000000, .serial_base = 0x71100000, @@ -1360,254 +1428,67 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { .machine_id = sbook_id, .iommu_version = 0x05000000, .max_mem = 0x10000000, - }, -}; - -/* SPARCstation 5 hardware initialisation */ -static void ss5_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[0], machine); -} - -/* SPARCstation 10 hardware initialisation */ -static void ss10_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[1], machine); -} - -/* SPARCserver 600MP hardware initialisation */ -static void ss600mp_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[2], machine); -} - -/* SPARCstation 20 hardware initialisation */ -static void ss20_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[3], machine); -} - -/* SPARCstation Voyager hardware initialisation */ -static void vger_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[4], machine); -} - -/* SPARCstation LX hardware initialisation */ -static void ss_lx_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[5], machine); -} - -/* SPARCstation 4 hardware initialisation */ -static void ss4_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[6], machine); -} - -/* SPARCClassic hardware initialisation */ -static void scls_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[7], machine); -} - -/* SPARCbook hardware initialisation */ -static void sbook_init(MachineState *machine) -{ - sun4m_hw_init(&sun4m_hwdefs[8], machine); -} - -static void ss5_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCstation 5"; - mc->init = ss5_init; - mc->block_default_type = IF_SCSI; - mc->is_default = true; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo ss5_type = { - .name = MACHINE_TYPE_NAME("SS-5"), - .parent = TYPE_MACHINE, - .class_init = ss5_class_init, -}; - -static void ss10_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCstation 10"; - mc->init = ss10_init; - mc->block_default_type = IF_SCSI; - mc->max_cpus = 4; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-SuperSparc-II"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo ss10_type = { - .name = MACHINE_TYPE_NAME("SS-10"), - .parent = TYPE_MACHINE, - .class_init = ss10_class_init, -}; - -static void ss600mp_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCserver 600MP"; - mc->init = ss600mp_init; - mc->block_default_type = IF_SCSI; - mc->max_cpus = 4; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-SuperSparc-II"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo ss600mp_type = { - .name = MACHINE_TYPE_NAME("SS-600MP"), - .parent = TYPE_MACHINE, - .class_init = ss600mp_class_init, -}; - -static void ss20_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCstation 20"; - mc->init = ss20_init; - mc->block_default_type = IF_SCSI; - mc->max_cpus = 4; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-SuperSparc-II"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo ss20_type = { - .name = MACHINE_TYPE_NAME("SS-20"), - .parent = TYPE_MACHINE, - .class_init = ss20_class_init, -}; - -static void voyager_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCstation Voyager"; - mc->init = vger_init; - mc->block_default_type = IF_SCSI; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo voyager_type = { - .name = MACHINE_TYPE_NAME("Voyager"), - .parent = TYPE_MACHINE, - .class_init = voyager_class_init, -}; - -static void ss_lx_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCstation LX"; - mc->init = ss_lx_init; - mc->block_default_type = IF_SCSI; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-MicroSparc-I"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo ss_lx_type = { - .name = MACHINE_TYPE_NAME("LX"), - .parent = TYPE_MACHINE, - .class_init = ss_lx_class_init, -}; - -static void ss4_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCstation 4"; - mc->init = ss4_init; - mc->block_default_type = IF_SCSI; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo ss4_type = { - .name = MACHINE_TYPE_NAME("SS-4"), - .parent = TYPE_MACHINE, - .class_init = ss4_class_init, -}; - -static void scls_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "Sun4m platform, SPARCClassic"; - mc->init = scls_init; - mc->block_default_type = IF_SCSI; - mc->default_boot_order = "c"; - mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-MicroSparc-I"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; -} - -static const TypeInfo scls_type = { - .name = MACHINE_TYPE_NAME("SPARCClassic"), - .parent = TYPE_MACHINE, - .class_init = scls_class_init, -}; - -static void sbook_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); + }; mc->desc = "Sun4m platform, SPARCbook"; - mc->init = sbook_init; - mc->block_default_type = IF_SCSI; - mc->default_boot_order = "c"; mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-MicroSparc-I"); - mc->default_display = "tcx"; - mc->default_ram_id = "sun4m.ram"; + smc->hwdef = &sbook_hwdef; } -static const TypeInfo sbook_type = { - .name = MACHINE_TYPE_NAME("SPARCbook"), - .parent = TYPE_MACHINE, - .class_init = sbook_class_init, +static const TypeInfo sun4m_machine_types[] = { + { + .name = MACHINE_TYPE_NAME("SS-5"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = ss5_class_init, + }, { + .name = MACHINE_TYPE_NAME("SS-10"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = ss10_class_init, + }, { + .name = MACHINE_TYPE_NAME("SS-600MP"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = ss600mp_class_init, + }, { + .name = MACHINE_TYPE_NAME("SS-20"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = ss20_class_init, + }, { + .name = MACHINE_TYPE_NAME("Voyager"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = voyager_class_init, + }, { + .name = MACHINE_TYPE_NAME("LX"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = ss_lx_class_init, + }, { + .name = MACHINE_TYPE_NAME("SS-4"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = ss4_class_init, + }, { + .name = MACHINE_TYPE_NAME("SPARCClassic"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = scls_class_init, + }, { + .name = MACHINE_TYPE_NAME("SPARCbook"), + .parent = TYPE_SUN4M_MACHINE, + .class_init = sbook_class_init, + }, { + .name = TYPE_SUN4M_MACHINE, + .parent = TYPE_MACHINE, + .class_size = sizeof(Sun4mMachineClass), + .class_init = sun4m_machine_class_init, + .abstract = true, + } }; +DEFINE_TYPES(sun4m_machine_types) + static void sun4m_register_types(void) { type_register_static(&idreg_info); type_register_static(&afx_info); type_register_static(&prom_info); type_register_static(&ram_info); - - type_register_static(&ss5_type); - type_register_static(&ss10_type); - type_register_static(&ss600mp_type); - type_register_static(&ss20_type); - type_register_static(&voyager_type); - type_register_static(&ss_lx_type); - type_register_static(&ss4_type); - type_register_static(&scls_type); - type_register_static(&sbook_type); } type_init(sun4m_register_types) diff --git a/hw/sparc/trace-events b/hw/sparc/trace-events index 355b07ae05..d3a30a816a 100644 --- a/hw/sparc/trace-events +++ b/hw/sparc/trace-events @@ -1,8 +1,6 @@ # See docs/devel/tracing.txt for syntax documentation. # sun4m.c -sun4m_cpu_interrupt(unsigned int level) "Set CPU IRQ %d" -sun4m_cpu_reset_interrupt(unsigned int level) "Reset CPU IRQ %d" sun4m_cpu_set_irq_raise(int level) "Raise CPU IRQ %d" sun4m_cpu_set_irq_lower(int level) "Lower CPU IRQ %d" @@ -19,3 +17,5 @@ sun4m_iommu_bad_addr(uint64_t addr) "bad addr 0x%"PRIx64 # leon3.c leon3_set_irq(int intno) "Set CPU IRQ %d" leon3_reset_irq(int intno) "Reset CPU IRQ %d" +int_helper_icache_freeze(void) "Instruction cache: freeze" +int_helper_dcache_freeze(void) "Data cache: freeze" diff --git a/hw/sparc64/sparc64.c b/hw/sparc64/sparc64.c index e3f9219a10..8654e955eb 100644 --- a/hw/sparc64/sparc64.c +++ b/hw/sparc64/sparc64.c @@ -26,7 +26,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "hw/boards.h" -#include "hw/char/serial.h" #include "hw/sparc/sparc64.h" #include "qemu/timer.h" #include "sysemu/reset.h" @@ -35,68 +34,6 @@ #define TICK_MAX 0x7fffffffffffffffULL -void cpu_check_irqs(CPUSPARCState *env) -{ - CPUState *cs; - uint32_t pil = env->pil_in | - (env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER)); - - /* We should be holding the BQL before we mess with IRQs */ - g_assert(qemu_mutex_iothread_locked()); - - /* TT_IVEC has a higher priority (16) than TT_EXTINT (31..17) */ - if (env->ivec_status & 0x20) { - return; - } - cs = env_cpu(env); - /* check if TM or SM in SOFTINT are set - setting these also causes interrupt 14 */ - if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) { - pil |= 1 << 14; - } - - /* The bit corresponding to psrpil is (1<< psrpil), the next bit - is (2 << psrpil). */ - if (pil < (2 << env->psrpil)) { - if (cs->interrupt_request & CPU_INTERRUPT_HARD) { - trace_sparc64_cpu_check_irqs_reset_irq(env->interrupt_index); - env->interrupt_index = 0; - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } - return; - } - - if (cpu_interrupts_enabled(env)) { - - unsigned int i; - - for (i = 15; i > env->psrpil; i--) { - if (pil & (1 << i)) { - int old_interrupt = env->interrupt_index; - int new_interrupt = TT_EXTINT | i; - - if (unlikely(env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt - && ((cpu_tsptr(env)->tt & 0x1f0) == TT_EXTINT))) { - trace_sparc64_cpu_check_irqs_noset_irq(env->tl, - cpu_tsptr(env)->tt, - new_interrupt); - } else if (old_interrupt != new_interrupt) { - env->interrupt_index = new_interrupt; - trace_sparc64_cpu_check_irqs_set_irq(i, old_interrupt, - new_interrupt); - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } - break; - } - } - } else if (cs->interrupt_request & CPU_INTERRUPT_HARD) { - trace_sparc64_cpu_check_irqs_disabled(pil, env->pil_in, env->softint, - env->interrupt_index); - env->interrupt_index = 0; - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } -} - static void cpu_kick_irq(SPARCCPU *cpu) { CPUState *cs = CPU(cpu); diff --git a/hw/sparc64/trace-events b/hw/sparc64/trace-events index a0b29987d2..b85d14c30c 100644 --- a/hw/sparc64/trace-events +++ b/hw/sparc64/trace-events @@ -9,10 +9,6 @@ sun4u_iommu_mem_write(uint64_t addr, uint64_t val, int size) "addr: 0x%"PRIx64" sun4u_iommu_translate(uint64_t addr, uint64_t trans_addr, uint64_t tte) "xlate 0x%"PRIx64" => pa 0x%"PRIx64" tte: 0x%"PRIx64 # sparc64.c -sparc64_cpu_check_irqs_reset_irq(int intno) "Reset CPU IRQ (current interrupt 0x%x)" -sparc64_cpu_check_irqs_noset_irq(uint32_t tl, uint32_t tt, int intno) "Not setting CPU IRQ: TL=%d current 0x%x >= pending 0x%x" -sparc64_cpu_check_irqs_set_irq(unsigned int i, int old, int new) "Set CPU IRQ %d old=0x%x new=0x%x" -sparc64_cpu_check_irqs_disabled(uint32_t pil, uint32_t pil_in, uint32_t softint, int intno) "Interrupts disabled, pil=0x%08x pil_in=0x%08x softint=0x%08x current interrupt 0x%x" sparc64_cpu_ivec_raise_irq(int irq) "Raise IVEC IRQ %d" sparc64_cpu_ivec_lower_irq(int irq) "Lower IVEC IRQ %d" sparc64_cpu_tick_irq_disabled(void) "tick_irq: softint disabled" diff --git a/hw/usb/combined-packet.c b/hw/usb/combined-packet.c index 5d57e883dc..e56802f89a 100644 --- a/hw/usb/combined-packet.c +++ b/hw/usb/combined-packet.c @@ -171,7 +171,9 @@ void usb_ep_combine_input_packets(USBEndpoint *ep) if ((p->iov.size % ep->max_packet_size) != 0 || !p->short_not_ok || next == NULL || /* Work around for Linux usbfs bulk splitting + migration */ - (totalsize == (16 * KiB - 36) && p->int_req)) { + (totalsize == (16 * KiB - 36) && p->int_req) || + /* Next package may grow combined package over 1MiB */ + totalsize > 1 * MiB - ep->max_packet_size) { usb_device_handle_data(ep->dev, first); assert(first->status == USB_RET_ASYNC); if (first->combined) { diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index fc39bab79f..1c7ae97c30 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -656,7 +656,7 @@ static void usb_hid_handle_data(USBDevice *dev, USBPacket *p) { USBHIDState *us = USB_HID(dev); HIDState *hs = &us->hid; - uint8_t buf[p->iov.size]; + g_autofree uint8_t *buf = g_malloc(p->iov.size); int len = 0; switch (p->pid) { diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index bbb8274344..2a895a73b0 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -907,7 +907,8 @@ static MTPData *usb_mtp_get_object_handles(MTPState *s, MTPControl *c, MTPObject *o) { MTPData *d = usb_mtp_data_alloc(c); - uint32_t i = 0, handles[o->nchildren]; + uint32_t i = 0; + g_autofree uint32_t *handles = g_new(uint32_t, o->nchildren); MTPObject *iter; trace_usb_mtp_op_get_object_handles(s->dev.addr, o->handle, o->path); diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index b595048635..ed687bc9f1 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -301,7 +301,7 @@ static void usb_wacom_handle_control(USBDevice *dev, USBPacket *p, static void usb_wacom_handle_data(USBDevice *dev, USBPacket *p) { USBWacomState *s = (USBWacomState *) dev; - uint8_t buf[p->iov.size]; + g_autofree uint8_t *buf = g_malloc(p->iov.size); int len = 0; switch (p->pid) { diff --git a/hw/usb/host-stub.c b/hw/usb/host-stub.c index 538ed29684..80809ceba5 100644 --- a/hw/usb/host-stub.c +++ b/hw/usb/host-stub.c @@ -31,7 +31,6 @@ */ #include "qemu/osdep.h" -#include "ui/console.h" #include "hw/usb.h" #include "monitor/monitor.h" diff --git a/hw/usb/meson.build b/hw/usb/meson.build index fb7a74e73a..f357270d0b 100644 --- a/hw/usb/meson.build +++ b/hw/usb/meson.build @@ -1,17 +1,14 @@ hw_usb_modules = {} # usb subsystem core -softmmu_ss.add(files( +softmmu_ss.add(when: 'CONFIG_USB', if_true: files( 'bus.c', 'combined-packet.c', 'core.c', - 'pcap.c', - 'libhw.c' -)) - -softmmu_ss.add(when: 'CONFIG_USB', if_true: files( 'desc.c', 'desc-msos.c', + 'libhw.c', + 'pcap.c', )) # usb host adapters diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 17f06f3417..6a75b0dc4a 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -620,7 +620,7 @@ static void usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, .endpoint = ep, .length = p->iov.size }; - uint8_t buf[p->iov.size]; + g_autofree uint8_t *buf = g_malloc(p->iov.size); /* No id, we look at the ep when receiving a status back */ usb_packet_copy(p, buf, p->iov.size); usbredirparser_send_iso_packet(dev->parser, 0, &iso_packet, @@ -818,7 +818,7 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, usbredirparser_send_bulk_packet(dev->parser, p->id, &bulk_packet, NULL, 0); } else { - uint8_t buf[size]; + g_autofree uint8_t *buf = g_malloc(size); usb_packet_copy(p, buf, size); usbredir_log_data(dev, "bulk data out:", buf, size); usbredirparser_send_bulk_packet(dev->parser, p->id, @@ -923,7 +923,7 @@ static void usbredir_handle_interrupt_out_data(USBRedirDevice *dev, USBPacket *p, uint8_t ep) { struct usb_redir_interrupt_packet_header interrupt_packet; - uint8_t buf[p->iov.size]; + g_autofree uint8_t *buf = g_malloc(p->iov.size); DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id); diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index 13fa1edd41..4701445e80 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -9,6 +9,12 @@ #ifndef DISAS_DIS_ASM_H #define DISAS_DIS_ASM_H +#include "qemu/bswap.h" + +#ifdef __cplusplus +extern "C" { +#endif + typedef void *PTR; typedef uint64_t bfd_vma; typedef int64_t bfd_signed_vma; @@ -479,8 +485,6 @@ bool cap_disas_plugin(disassemble_info *info, uint64_t pc, size_t size); /* from libbfd */ -#include "qemu/bswap.h" - static inline bfd_vma bfd_getl64(const bfd_byte *addr) { return ldq_le_p(addr); @@ -508,4 +512,8 @@ static inline bfd_vma bfd_getb16(const bfd_byte *addr) typedef bool bfd_boolean; +#ifdef __cplusplus +} +#endif + #endif /* DISAS_DIS_ASM_H */ diff --git a/include/hw/misc/mps2-scc.h b/include/hw/misc/mps2-scc.h index 49d070616a..3b2d13ac9c 100644 --- a/include/hw/misc/mps2-scc.h +++ b/include/hw/misc/mps2-scc.h @@ -9,6 +9,24 @@ * (at your option) any later version. */ +/* + * This is a model of the Serial Communication Controller (SCC) + * block found in most MPS FPGA images. + * + * QEMU interface: + * + sysbus MMIO region 0: the register bank + * + QOM property "scc-cfg4": value of the read-only CFG4 register + * + QOM property "scc-aid": value of the read-only SCC_AID register + * + QOM property "scc-id": value of the read-only SCC_ID register + * + QOM property "scc-cfg0": reset value of the CFG0 register + * + QOM property array "oscclk": reset values of the OSCCLK registers + * (which are accessed via the SYS_CFG channel provided by this device) + * + named GPIO output "remap": this tracks the value of CFG0 register + * bit 0. Boards where this bit controls memory remapping should + * connect this GPIO line to a function performing that mapping. + * Boards where bit 0 has no special function should leave the GPIO + * output disconnected. + */ #ifndef MPS2_SCC_H #define MPS2_SCC_H @@ -43,6 +61,9 @@ struct MPS2SCC { uint32_t num_oscclk; uint32_t *oscclk; uint32_t *oscclk_reset; + uint32_t cfg0_reset; + + qemu_irq remap; }; #endif diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 4aaf992b5d..2d3bb8bbed 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -1,8 +1,6 @@ #ifndef BSWAP_H #define BSWAP_H -#include "fpu/softfloat-types.h" - #ifdef CONFIG_MACHINE_BSWAP_H # include <sys/endian.h> # include <machine/bswap.h> @@ -12,7 +10,18 @@ # include <endian.h> #elif defined(CONFIG_BYTESWAP_H) # include <byteswap.h> +#define BSWAP_FROM_BYTESWAP +# else +#define BSWAP_FROM_FALLBACKS +#endif /* ! CONFIG_MACHINE_BSWAP_H */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "fpu/softfloat-types.h" + +#ifdef BSWAP_FROM_BYTESWAP static inline uint16_t bswap16(uint16_t x) { return bswap_16(x); @@ -27,7 +36,9 @@ static inline uint64_t bswap64(uint64_t x) { return bswap_64(x); } -# else +#endif + +#ifdef BSWAP_FROM_FALLBACKS static inline uint16_t bswap16(uint16_t x) { return (((x & 0x00ff) << 8) | @@ -53,7 +64,10 @@ static inline uint64_t bswap64(uint64_t x) ((x & 0x00ff000000000000ULL) >> 40) | ((x & 0xff00000000000000ULL) >> 56)); } -#endif /* ! CONFIG_MACHINE_BSWAP_H */ +#endif + +#undef BSWAP_FROM_BYTESWAP +#undef BSWAP_FROM_FALLBACKS static inline void bswap16s(uint16_t *s) { @@ -494,4 +508,8 @@ DO_STN_LDN_P(be) #undef le_bswaps #undef be_bswaps +#ifdef __cplusplus +} +#endif + #endif /* BSWAP_H */ diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index cb2a07e472..4c6f2390be 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -131,10 +131,6 @@ QEMU_EXTERN_C int daemon(int, int); */ #include "glib-compat.h" -#ifdef __cplusplus -extern "C" { -#endif - #ifdef _WIN32 #include "sysemu/os-win32.h" #endif @@ -143,6 +139,10 @@ extern "C" { #include "sysemu/os-posix.h" #endif +#ifdef __cplusplus +extern "C" { +#endif + #include "qemu/typedefs.h" /* diff --git a/include/sysemu/os-posix.h b/include/sysemu/os-posix.h index 629c8c648b..2edf33658a 100644 --- a/include/sysemu/os-posix.h +++ b/include/sysemu/os-posix.h @@ -38,6 +38,10 @@ #include <sys/sysmacros.h> #endif +#ifdef __cplusplus +extern "C" { +#endif + void os_set_line_buffering(void); void os_set_proc_name(const char *s); void os_setup_signal_handling(void); @@ -92,4 +96,8 @@ static inline void qemu_funlockfile(FILE *f) funlockfile(f); } +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h index 5346d51e89..43f569b5c2 100644 --- a/include/sysemu/os-win32.h +++ b/include/sysemu/os-win32.h @@ -30,6 +30,10 @@ #include <windows.h> #include <ws2tcpip.h> +#ifdef __cplusplus +extern "C" { +#endif + #if defined(_WIN64) /* On w64, setjmp is implemented by _setjmp which needs a second parameter. * If this parameter is NULL, longjump does no stack unwinding. @@ -194,4 +198,8 @@ ssize_t qemu_recv_wrap(int sockfd, void *buf, size_t len, int flags); ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen); +#ifdef __cplusplus +} +#endif + #endif diff --git a/linux-user/elfload.c b/linux-user/elfload.c index c6731013fd..fc9c4f12be 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -586,6 +586,16 @@ enum { ARM_HWCAP2_A64_SVESM4 = 1 << 6, ARM_HWCAP2_A64_FLAGM2 = 1 << 7, ARM_HWCAP2_A64_FRINT = 1 << 8, + ARM_HWCAP2_A64_SVEI8MM = 1 << 9, + ARM_HWCAP2_A64_SVEF32MM = 1 << 10, + ARM_HWCAP2_A64_SVEF64MM = 1 << 11, + ARM_HWCAP2_A64_SVEBF16 = 1 << 12, + ARM_HWCAP2_A64_I8MM = 1 << 13, + ARM_HWCAP2_A64_BF16 = 1 << 14, + ARM_HWCAP2_A64_DGH = 1 << 15, + ARM_HWCAP2_A64_RNG = 1 << 16, + ARM_HWCAP2_A64_BTI = 1 << 17, + ARM_HWCAP2_A64_MTE = 1 << 18, }; #define ELF_HWCAP get_elf_hwcap() @@ -640,6 +650,9 @@ static uint32_t get_elf_hwcap2(void) GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP); GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2); GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT); + GET_FEATURE_ID(aa64_rndr, ARM_HWCAP2_A64_RNG); + GET_FEATURE_ID(aa64_bti, ARM_HWCAP2_A64_BTI); + GET_FEATURE_ID(aa64_mte, ARM_HWCAP2_A64_MTE); return hwcaps; } diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img index 5aaeac9f79..a560c1272f 100644 --- a/pc-bios/s390-ccw.img +++ b/pc-bios/s390-ccw.img Binary files differdiff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index 29fd9019b8..cee9d2c63b 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -6,8 +6,8 @@ include ../../config-host.mak CFLAGS = -O2 -g quiet-command = $(if $(V),$1,$(if $(2),@printf " %-7s %s\n" $2 $3 && $1, @$1)) -cc-option = $(if $(shell $(CC) $1 -S -o /dev/null -xc /dev/null > /dev/null \ - 2>&1 && echo OK), $1, $2) +cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \ + >/dev/null 2>&1 && echo OK),$2,$3) VPATH_SUFFIXES = %.c %.h %.S %.m %.mak %.sh %.rc Kconfig% %.json.in set-vpath = $(if $1,$(foreach PATTERN,$(VPATH_SUFFIXES),$(eval vpath $(PATTERN) $1))) @@ -30,10 +30,12 @@ OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o \ virtio.o virtio-scsi.o virtio-blkdev.o libc.o cio.o dasd-ipl.o QEMU_CFLAGS := -Wall $(filter -W%, $(QEMU_CFLAGS)) +QEMU_CFLAGS += $(call cc-option,-Werror $(QEMU_CFLAGS),-Wno-stringop-overflow) QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -fno-common -fPIE QEMU_CFLAGS += -fwrapv -fno-strict-aliasing -fno-asynchronous-unwind-tables QEMU_CFLAGS += $(call cc-option, $(QEMU_CFLAGS), -fno-stack-protector) -QEMU_CFLAGS += -msoft-float -march=z900 +QEMU_CFLAGS += -msoft-float +QEMU_CFLAGS += $(call cc-option, $(QEMU_CFLAGS),-march=z900,-march=z10) QEMU_CFLAGS += -std=gnu99 LDFLAGS += -Wl,-pie -nostdlib diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c index 44df7d16af..56411ab3b6 100644 --- a/pc-bios/s390-ccw/bootmap.c +++ b/pc-bios/s390-ccw/bootmap.c @@ -213,7 +213,7 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr) next_block_nr = eckd_block_num(&s1b->seek[i + 1].chs); } - if (next_block_nr) { + if (next_block_nr && !is_null_block_number(next_block_nr)) { read_block(next_block_nr, s2_next_blk, "Cannot read stage2 boot loader"); } @@ -299,7 +299,7 @@ static void ipl_eckd_cdl(void) sclp_print("Bad block size in zIPL section of IPL2 record.\n"); return; } - if (!mbr->dev_type == DEV_TYPE_ECKD) { + if (mbr->dev_type != DEV_TYPE_ECKD) { sclp_print("Non-ECKD device type in zIPL section of IPL2 record.\n"); return; } diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c index b9c70d64a5..73e4367e09 100644 --- a/pc-bios/s390-ccw/jump2ipl.c +++ b/pc-bios/s390-ccw/jump2ipl.c @@ -82,8 +82,8 @@ void jump_to_low_kernel(void) jump_to_IPL_code(KERN_IMAGE_START); } - /* Trying to get PSW at zero address */ - if (*((uint64_t *)0) & RESET_PSW_MASK) { + /* Trying to get PSW at zero address (pointed to by reset_psw) */ + if (*reset_psw & RESET_PSW_MASK) { /* * Surely nobody will try running directly from lowcore, so * let's use 0 as an indication that we want to load the reset diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak index 577c023afe..68b4d7edcb 100644 --- a/pc-bios/s390-ccw/netboot.mak +++ b/pc-bios/s390-ccw/netboot.mak @@ -6,7 +6,7 @@ NETOBJS := start.o sclp.o cio.o virtio.o virtio-net.o jump2ipl.o netmain.o LIBC_INC := -nostdinc -I$(SLOF_DIR)/lib/libc/include LIBNET_INC := -I$(SLOF_DIR)/lib/libnet -NETLDFLAGS := $(LDFLAGS) -Ttext=0x7800000 +NETLDFLAGS := $(LDFLAGS) -Wl,-Ttext=0x7800000 $(NETOBJS): QEMU_CFLAGS += $(LIBC_INC) $(LIBNET_INC) diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h index 6cd92669e9..79db69ff54 100644 --- a/pc-bios/s390-ccw/s390-ccw.h +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -89,6 +89,7 @@ bool menu_is_enabled_enum(void); #define MAX_BOOT_ENTRIES 31 +__attribute__ ((__noreturn__)) static inline void panic(const char *string) { sclp_print(string); diff --git a/pc-bios/s390-netboot.img b/pc-bios/s390-netboot.img index 120bd40ca9..bc34af8a28 100644 --- a/pc-bios/s390-netboot.img +++ b/pc-bios/s390-netboot.img Binary files differdiff --git a/stubs/meson.build b/stubs/meson.build index be6f6d609e..3faef16892 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -50,6 +50,7 @@ if have_block endif if have_system stub_ss.add(files('semihost.c')) + stub_ss.add(files('usb-dev-stub.c')) stub_ss.add(files('xen-hw-stub.c')) else stub_ss.add(files('qdev.c')) diff --git a/stubs/usb-dev-stub.c b/stubs/usb-dev-stub.c new file mode 100644 index 0000000000..b1adeeb454 --- /dev/null +++ b/stubs/usb-dev-stub.c @@ -0,0 +1,25 @@ +/* + * QEMU USB device emulation stubs + * + * Copyright (C) 2021 Philippe Mathieu-Daudé <f4bug@amsat.org> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "sysemu/sysemu.h" +#include "monitor/monitor.h" +#include "hw/usb.h" + +USBDevice *usbdevice_create(const char *driver) +{ + error_report("Support for USB devices not built-in"); + + return NULL; +} + +void hmp_info_usb(Monitor *mon, const QDict *qdict) +{ + monitor_printf(mon, "Support for USB devices not built-in\n"); +} diff --git a/target/arm/helper.c b/target/arm/helper.c index 9b1b98705f..3b365a78cb 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -4742,7 +4742,7 @@ static void tlbi_aa64_vae2is_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t pageaddr = sextract64(value << 12, 0, 56); bool secure = arm_is_secure_below_el3(env); int mask = secure ? ARMMMUIdxBit_SE2 : ARMMMUIdxBit_E2; - int bits = tlbbits_for_regime(env, secure ? ARMMMUIdx_E2 : ARMMMUIdx_SE2, + int bits = tlbbits_for_regime(env, secure ? ARMMMUIdx_SE2 : ARMMMUIdx_E2, pageaddr); tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits); diff --git a/target/arm/meson.build b/target/arm/meson.build index 15b936c101..5bfaf43b50 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -1,11 +1,11 @@ gen = [ decodetree.process('sve.decode', extra_args: '--decode=disas_sve'), - decodetree.process('neon-shared.decode', extra_args: '--static-decode=disas_neon_shared'), - decodetree.process('neon-dp.decode', extra_args: '--static-decode=disas_neon_dp'), - decodetree.process('neon-ls.decode', extra_args: '--static-decode=disas_neon_ls'), - decodetree.process('vfp.decode', extra_args: '--static-decode=disas_vfp'), - decodetree.process('vfp-uncond.decode', extra_args: '--static-decode=disas_vfp_uncond'), - decodetree.process('m-nocp.decode', extra_args: '--static-decode=disas_m_nocp'), + decodetree.process('neon-shared.decode', extra_args: '--decode=disas_neon_shared'), + decodetree.process('neon-dp.decode', extra_args: '--decode=disas_neon_dp'), + decodetree.process('neon-ls.decode', extra_args: '--decode=disas_neon_ls'), + decodetree.process('vfp.decode', extra_args: '--decode=disas_vfp'), + decodetree.process('vfp-uncond.decode', extra_args: '--decode=disas_vfp_uncond'), + decodetree.process('m-nocp.decode', extra_args: '--decode=disas_m_nocp'), decodetree.process('a32.decode', extra_args: '--static-decode=disas_a32'), decodetree.process('a32-uncond.decode', extra_args: '--static-decode=disas_a32_uncond'), decodetree.process('t32.decode', extra_args: '--static-decode=disas_t32'), @@ -26,6 +26,9 @@ arm_ss.add(files( 'op_helper.c', 'tlb_helper.c', 'translate.c', + 'translate-m-nocp.c', + 'translate-neon.c', + 'translate-vfp.c', 'vec_helper.c', 'vfp_helper.c', 'cpu_tcg.c', diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 78b831f181..efcb600992 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -228,6 +228,7 @@ void HELPER(setend)(CPUARMState *env) arm_rebuild_hflags(env); } +#ifndef CONFIG_USER_ONLY /* Function checks whether WFx (WFI/WFE) instructions are set up to be trapped. * The function returns the target EL (1-3) if the instruction is to be trapped; * otherwise it returns 0 indicating it is not trapped. @@ -282,9 +283,21 @@ static inline int check_wfx_trap(CPUARMState *env, bool is_wfe) return 0; } +#endif void HELPER(wfi)(CPUARMState *env, uint32_t insn_len) { +#ifdef CONFIG_USER_ONLY + /* + * WFI in the user-mode emulator is technically permitted but not + * something any real-world code would do. AArch64 Linux kernels + * trap it via SCTRL_EL1.nTWI and make it an (expensive) NOP; + * AArch32 kernels don't trap it so it will delay a bit. + * For QEMU, make it NOP here, because trying to raise EXCP_HLT + * would trigger an abort. + */ + return; +#else CPUState *cs = env_cpu(env); int target_el = check_wfx_trap(env, false); @@ -309,6 +322,7 @@ void HELPER(wfi)(CPUARMState *env, uint32_t insn_len) cs->exception_index = EXCP_HLT; cs->halted = 1; cpu_loop_exit(cs); +#endif } void HELPER(wfe)(CPUARMState *env) diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h new file mode 100644 index 0000000000..c997f4e321 --- /dev/null +++ b/target/arm/translate-a32.h @@ -0,0 +1,144 @@ +/* + * AArch32 translation, common definitions. + * + * Copyright (c) 2021 Linaro, Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TARGET_ARM_TRANSLATE_A64_H +#define TARGET_ARM_TRANSLATE_A64_H + +/* Prototypes for autogenerated disassembler functions */ +bool disas_m_nocp(DisasContext *dc, uint32_t insn); +bool disas_vfp(DisasContext *s, uint32_t insn); +bool disas_vfp_uncond(DisasContext *s, uint32_t insn); +bool disas_neon_dp(DisasContext *s, uint32_t insn); +bool disas_neon_ls(DisasContext *s, uint32_t insn); +bool disas_neon_shared(DisasContext *s, uint32_t insn); + +void load_reg_var(DisasContext *s, TCGv_i32 var, int reg); +void arm_gen_condlabel(DisasContext *s); +bool vfp_access_check(DisasContext *s); +void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop); +void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop); +void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop); +void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop); +TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs); +void gen_set_cpsr(TCGv_i32 var, uint32_t mask); +void gen_set_condexec(DisasContext *s); +void gen_set_pc_im(DisasContext *s, target_ulong val); +void gen_lookup_tb(DisasContext *s); +long vfp_reg_offset(bool dp, unsigned reg); +long neon_full_reg_offset(unsigned reg); +long neon_element_offset(int reg, int element, MemOp memop); +void gen_rev16(TCGv_i32 dest, TCGv_i32 var); + +static inline TCGv_i32 load_cpu_offset(int offset) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_ld_i32(tmp, cpu_env, offset); + return tmp; +} + +#define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name)) + +static inline void store_cpu_offset(TCGv_i32 var, int offset) +{ + tcg_gen_st_i32(var, cpu_env, offset); + tcg_temp_free_i32(var); +} + +#define store_cpu_field(var, name) \ + store_cpu_offset(var, offsetof(CPUARMState, name)) + +/* Create a new temporary and set it to the value of a CPU register. */ +static inline TCGv_i32 load_reg(DisasContext *s, int reg) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + load_reg_var(s, tmp, reg); + return tmp; +} + +void store_reg(DisasContext *s, int reg, TCGv_i32 var); + +void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val, + TCGv_i32 a32, int index, MemOp opc); +void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val, + TCGv_i32 a32, int index, MemOp opc); +void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val, + TCGv_i32 a32, int index, MemOp opc); +void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val, + TCGv_i32 a32, int index, MemOp opc); +void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, + int index, MemOp opc); +void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, + int index, MemOp opc); +void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, + int index, MemOp opc); +void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, + int index, MemOp opc); + +#define DO_GEN_LD(SUFF, OPC) \ + static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val, \ + TCGv_i32 a32, int index) \ + { \ + gen_aa32_ld_i32(s, val, a32, index, OPC); \ + } + +#define DO_GEN_ST(SUFF, OPC) \ + static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val, \ + TCGv_i32 a32, int index) \ + { \ + gen_aa32_st_i32(s, val, a32, index, OPC); \ + } + +static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val, + TCGv_i32 a32, int index) +{ + gen_aa32_ld_i64(s, val, a32, index, MO_Q); +} + +static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val, + TCGv_i32 a32, int index) +{ + gen_aa32_st_i64(s, val, a32, index, MO_Q); +} + +DO_GEN_LD(8u, MO_UB) +DO_GEN_LD(16u, MO_UW) +DO_GEN_LD(32u, MO_UL) +DO_GEN_ST(8, MO_UB) +DO_GEN_ST(16, MO_UW) +DO_GEN_ST(32, MO_UL) + +#undef DO_GEN_LD +#undef DO_GEN_ST + +#if defined(CONFIG_USER_ONLY) +#define IS_USER(s) 1 +#else +#define IS_USER(s) (s->user) +#endif + +/* Set NZCV flags from the high 4 bits of var. */ +#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV) + +/* Swap low and high halfwords. */ +static inline void gen_swap_half(TCGv_i32 dest, TCGv_i32 var) +{ + tcg_gen_rotri_i32(dest, var, 16); +} + +#endif diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 95897e63af..0c80d0b505 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -359,14 +359,6 @@ static void gen_exception_internal_insn(DisasContext *s, uint64_t pc, int excp) s->base.is_jmp = DISAS_NORETURN; } -static void gen_exception_insn(DisasContext *s, uint64_t pc, int excp, - uint32_t syndrome, uint32_t target_el) -{ - gen_a64_set_pc_im(pc); - gen_exception(excp, syndrome, target_el); - s->base.is_jmp = DISAS_NORETURN; -} - static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syndrome) { TCGv_i32 tcg_syn; @@ -437,13 +429,6 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest) } } -void unallocated_encoding(DisasContext *s) -{ - /* Unallocated and reserved encodings are uncategorized */ - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(), - default_exception_el(s)); -} - static void init_tmp_a64_array(DisasContext *s) { #ifdef CONFIG_DEBUG_TCG diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h index 868d355048..89437276e7 100644 --- a/target/arm/translate-a64.h +++ b/target/arm/translate-a64.h @@ -18,8 +18,6 @@ #ifndef TARGET_ARM_TRANSLATE_A64_H #define TARGET_ARM_TRANSLATE_A64_H -void unallocated_encoding(DisasContext *s); - #define unsupported_encoding(s, insn) \ do { \ qemu_log_mask(LOG_UNIMP, \ diff --git a/target/arm/translate-m-nocp.c b/target/arm/translate-m-nocp.c new file mode 100644 index 0000000000..d47eb8e153 --- /dev/null +++ b/target/arm/translate-m-nocp.c @@ -0,0 +1,221 @@ +/* + * ARM translation: M-profile NOCP special-case instructions + * + * Copyright (c) 2020 Linaro, Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "tcg/tcg-op.h" +#include "translate.h" +#include "translate-a32.h" + +#include "decode-m-nocp.c.inc" + +/* + * Decode VLLDM and VLSTM are nonstandard because: + * * if there is no FPU then these insns must NOP in + * Secure state and UNDEF in Nonsecure state + * * if there is an FPU then these insns do not have + * the usual behaviour that vfp_access_check() provides of + * being controlled by CPACR/NSACR enable bits or the + * lazy-stacking logic. + */ +static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a) +{ + TCGv_i32 fptr; + + if (!arm_dc_feature(s, ARM_FEATURE_M) || + !arm_dc_feature(s, ARM_FEATURE_V8)) { + return false; + } + + if (a->op) { + /* + * T2 encoding ({D0-D31} reglist): v8.1M and up. We choose not + * to take the IMPDEF option to make memory accesses to the stack + * slots that correspond to the D16-D31 registers (discarding + * read data and writing UNKNOWN values), so for us the T2 + * encoding behaves identically to the T1 encoding. + */ + if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { + return false; + } + } else { + /* + * T1 encoding ({D0-D15} reglist); undef if we have 32 Dregs. + * This is currently architecturally impossible, but we add the + * check to stay in line with the pseudocode. Note that we must + * emit code for the UNDEF so it takes precedence over the NOCP. + */ + if (dc_isar_feature(aa32_simd_r32, s)) { + unallocated_encoding(s); + return true; + } + } + + /* + * If not secure, UNDEF. We must emit code for this + * rather than returning false so that this takes + * precedence over the m-nocp.decode NOCP fallback. + */ + if (!s->v8m_secure) { + unallocated_encoding(s); + return true; + } + /* If no fpu, NOP. */ + if (!dc_isar_feature(aa32_vfp, s)) { + return true; + } + + fptr = load_reg(s, a->rn); + if (a->l) { + gen_helper_v7m_vlldm(cpu_env, fptr); + } else { + gen_helper_v7m_vlstm(cpu_env, fptr); + } + tcg_temp_free_i32(fptr); + + /* End the TB, because we have updated FP control bits */ + s->base.is_jmp = DISAS_UPDATE_EXIT; + return true; +} + +static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a) +{ + int btmreg, topreg; + TCGv_i64 zero; + TCGv_i32 aspen, sfpa; + + if (!dc_isar_feature(aa32_m_sec_state, s)) { + /* Before v8.1M, fall through in decode to NOCP check */ + return false; + } + + /* Explicitly UNDEF because this takes precedence over NOCP */ + if (!arm_dc_feature(s, ARM_FEATURE_M_MAIN) || !s->v8m_secure) { + unallocated_encoding(s); + return true; + } + + if (!dc_isar_feature(aa32_vfp_simd, s)) { + /* NOP if we have neither FP nor MVE */ + return true; + } + + /* + * If FPCCR.ASPEN != 0 && CONTROL_S.SFPA == 0 then there is no + * active floating point context so we must NOP (without doing + * any lazy state preservation or the NOCP check). + */ + aspen = load_cpu_field(v7m.fpccr[M_REG_S]); + sfpa = load_cpu_field(v7m.control[M_REG_S]); + tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); + tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); + tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK); + tcg_gen_or_i32(sfpa, sfpa, aspen); + arm_gen_condlabel(s); + tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel); + + if (s->fp_excp_el != 0) { + gen_exception_insn(s, s->pc_curr, EXCP_NOCP, + syn_uncategorized(), s->fp_excp_el); + return true; + } + + topreg = a->vd + a->imm - 1; + btmreg = a->vd; + + /* Convert to Sreg numbers if the insn specified in Dregs */ + if (a->size == 3) { + topreg = topreg * 2 + 1; + btmreg *= 2; + } + + if (topreg > 63 || (topreg > 31 && !(topreg & 1))) { + /* UNPREDICTABLE: we choose to undef */ + unallocated_encoding(s); + return true; + } + + /* Silently ignore requests to clear D16-D31 if they don't exist */ + if (topreg > 31 && !dc_isar_feature(aa32_simd_r32, s)) { + topreg = 31; + } + + if (!vfp_access_check(s)) { + return true; + } + + /* Zero the Sregs from btmreg to topreg inclusive. */ + zero = tcg_const_i64(0); + if (btmreg & 1) { + write_neon_element64(zero, btmreg >> 1, 1, MO_32); + btmreg++; + } + for (; btmreg + 1 <= topreg; btmreg += 2) { + write_neon_element64(zero, btmreg >> 1, 0, MO_64); + } + if (btmreg == topreg) { + write_neon_element64(zero, btmreg >> 1, 0, MO_32); + btmreg++; + } + assert(btmreg == topreg + 1); + /* TODO: when MVE is implemented, zero VPR here */ + return true; +} + +static bool trans_NOCP(DisasContext *s, arg_nocp *a) +{ + /* + * Handle M-profile early check for disabled coprocessor: + * all we need to do here is emit the NOCP exception if + * the coprocessor is disabled. Otherwise we return false + * and the real VFP/etc decode will handle the insn. + */ + assert(arm_dc_feature(s, ARM_FEATURE_M)); + + if (a->cp == 11) { + a->cp = 10; + } + if (arm_dc_feature(s, ARM_FEATURE_V8_1M) && + (a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) { + /* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */ + a->cp = 10; + } + + if (a->cp != 10) { + gen_exception_insn(s, s->pc_curr, EXCP_NOCP, + syn_uncategorized(), default_exception_el(s)); + return true; + } + + if (s->fp_excp_el != 0) { + gen_exception_insn(s, s->pc_curr, EXCP_NOCP, + syn_uncategorized(), s->fp_excp_el); + return true; + } + + return false; +} + +static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a) +{ + /* This range needs a coprocessor check for v8.1M and later only */ + if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { + return false; + } + return trans_NOCP(s, a); +} diff --git a/target/arm/translate-neon.c.inc b/target/arm/translate-neon.c index a02b8369a1..658bd275da 100644 --- a/target/arm/translate-neon.c.inc +++ b/target/arm/translate-neon.c @@ -20,11 +20,13 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -/* - * This file is intended to be included from translate.c; it uses - * some macros and definitions provided by that file. - * It might be possible to convert it to a standalone .c file eventually. - */ +#include "qemu/osdep.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "exec/exec-all.h" +#include "exec/gen-icount.h" +#include "translate.h" +#include "translate-a32.h" static inline int plus1(DisasContext *s, int x) { @@ -60,6 +62,13 @@ static inline int neon_3same_fp_size(DisasContext *s, int x) #include "decode-neon-ls.c.inc" #include "decode-neon-shared.c.inc" +static TCGv_ptr vfp_reg_ptr(bool dp, int reg) +{ + TCGv_ptr ret = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(ret, cpu_env, vfp_reg_offset(dp, reg)); + return ret; +} + static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop) { long offset = neon_element_offset(reg, ele, mop & MO_SIZE); diff --git a/target/arm/translate-vfp.c.inc b/target/arm/translate-vfp.c index e20d9c7ba6..3da84f30a0 100644 --- a/target/arm/translate-vfp.c.inc +++ b/target/arm/translate-vfp.c @@ -20,16 +20,38 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -/* - * This file is intended to be included from translate.c; it uses - * some macros and definitions provided by that file. - * It might be possible to convert it to a standalone .c file eventually. - */ +#include "qemu/osdep.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "exec/exec-all.h" +#include "exec/gen-icount.h" +#include "translate.h" +#include "translate-a32.h" /* Include the generated VFP decoder */ #include "decode-vfp.c.inc" #include "decode-vfp-uncond.c.inc" +static inline void vfp_load_reg64(TCGv_i64 var, int reg) +{ + tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(true, reg)); +} + +static inline void vfp_store_reg64(TCGv_i64 var, int reg) +{ + tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(true, reg)); +} + +static inline void vfp_load_reg32(TCGv_i32 var, int reg) +{ + tcg_gen_ld_i32(var, cpu_env, vfp_reg_offset(false, reg)); +} + +static inline void vfp_store_reg32(TCGv_i32 var, int reg) +{ + tcg_gen_st_i32(var, cpu_env, vfp_reg_offset(false, reg)); +} + /* * The imm8 encodes the sign bit, enough bits to represent an exponent in * the range 01....1xx to 10....0xx, and the most significant 4 bits of @@ -191,7 +213,7 @@ static bool full_vfp_access_check(DisasContext *s, bool ignore_vfp_enabled) * The most usual kind of VFP access check, for everything except * FMXR/FMRX to the always-available special registers. */ -static bool vfp_access_check(DisasContext *s) +bool vfp_access_check(DisasContext *s) { return full_vfp_access_check(s, false); } @@ -3800,202 +3822,6 @@ static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a) return true; } -/* - * Decode VLLDM and VLSTM are nonstandard because: - * * if there is no FPU then these insns must NOP in - * Secure state and UNDEF in Nonsecure state - * * if there is an FPU then these insns do not have - * the usual behaviour that vfp_access_check() provides of - * being controlled by CPACR/NSACR enable bits or the - * lazy-stacking logic. - */ -static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a) -{ - TCGv_i32 fptr; - - if (!arm_dc_feature(s, ARM_FEATURE_M) || - !arm_dc_feature(s, ARM_FEATURE_V8)) { - return false; - } - - if (a->op) { - /* - * T2 encoding ({D0-D31} reglist): v8.1M and up. We choose not - * to take the IMPDEF option to make memory accesses to the stack - * slots that correspond to the D16-D31 registers (discarding - * read data and writing UNKNOWN values), so for us the T2 - * encoding behaves identically to the T1 encoding. - */ - if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { - return false; - } - } else { - /* - * T1 encoding ({D0-D15} reglist); undef if we have 32 Dregs. - * This is currently architecturally impossible, but we add the - * check to stay in line with the pseudocode. Note that we must - * emit code for the UNDEF so it takes precedence over the NOCP. - */ - if (dc_isar_feature(aa32_simd_r32, s)) { - unallocated_encoding(s); - return true; - } - } - - /* - * If not secure, UNDEF. We must emit code for this - * rather than returning false so that this takes - * precedence over the m-nocp.decode NOCP fallback. - */ - if (!s->v8m_secure) { - unallocated_encoding(s); - return true; - } - /* If no fpu, NOP. */ - if (!dc_isar_feature(aa32_vfp, s)) { - return true; - } - - fptr = load_reg(s, a->rn); - if (a->l) { - gen_helper_v7m_vlldm(cpu_env, fptr); - } else { - gen_helper_v7m_vlstm(cpu_env, fptr); - } - tcg_temp_free_i32(fptr); - - /* End the TB, because we have updated FP control bits */ - s->base.is_jmp = DISAS_UPDATE_EXIT; - return true; -} - -static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a) -{ - int btmreg, topreg; - TCGv_i64 zero; - TCGv_i32 aspen, sfpa; - - if (!dc_isar_feature(aa32_m_sec_state, s)) { - /* Before v8.1M, fall through in decode to NOCP check */ - return false; - } - - /* Explicitly UNDEF because this takes precedence over NOCP */ - if (!arm_dc_feature(s, ARM_FEATURE_M_MAIN) || !s->v8m_secure) { - unallocated_encoding(s); - return true; - } - - if (!dc_isar_feature(aa32_vfp_simd, s)) { - /* NOP if we have neither FP nor MVE */ - return true; - } - - /* - * If FPCCR.ASPEN != 0 && CONTROL_S.SFPA == 0 then there is no - * active floating point context so we must NOP (without doing - * any lazy state preservation or the NOCP check). - */ - aspen = load_cpu_field(v7m.fpccr[M_REG_S]); - sfpa = load_cpu_field(v7m.control[M_REG_S]); - tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); - tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); - tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK); - tcg_gen_or_i32(sfpa, sfpa, aspen); - arm_gen_condlabel(s); - tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel); - - if (s->fp_excp_el != 0) { - gen_exception_insn(s, s->pc_curr, EXCP_NOCP, - syn_uncategorized(), s->fp_excp_el); - return true; - } - - topreg = a->vd + a->imm - 1; - btmreg = a->vd; - - /* Convert to Sreg numbers if the insn specified in Dregs */ - if (a->size == 3) { - topreg = topreg * 2 + 1; - btmreg *= 2; - } - - if (topreg > 63 || (topreg > 31 && !(topreg & 1))) { - /* UNPREDICTABLE: we choose to undef */ - unallocated_encoding(s); - return true; - } - - /* Silently ignore requests to clear D16-D31 if they don't exist */ - if (topreg > 31 && !dc_isar_feature(aa32_simd_r32, s)) { - topreg = 31; - } - - if (!vfp_access_check(s)) { - return true; - } - - /* Zero the Sregs from btmreg to topreg inclusive. */ - zero = tcg_const_i64(0); - if (btmreg & 1) { - write_neon_element64(zero, btmreg >> 1, 1, MO_32); - btmreg++; - } - for (; btmreg + 1 <= topreg; btmreg += 2) { - write_neon_element64(zero, btmreg >> 1, 0, MO_64); - } - if (btmreg == topreg) { - write_neon_element64(zero, btmreg >> 1, 0, MO_32); - btmreg++; - } - assert(btmreg == topreg + 1); - /* TODO: when MVE is implemented, zero VPR here */ - return true; -} - -static bool trans_NOCP(DisasContext *s, arg_nocp *a) -{ - /* - * Handle M-profile early check for disabled coprocessor: - * all we need to do here is emit the NOCP exception if - * the coprocessor is disabled. Otherwise we return false - * and the real VFP/etc decode will handle the insn. - */ - assert(arm_dc_feature(s, ARM_FEATURE_M)); - - if (a->cp == 11) { - a->cp = 10; - } - if (arm_dc_feature(s, ARM_FEATURE_V8_1M) && - (a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) { - /* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */ - a->cp = 10; - } - - if (a->cp != 10) { - gen_exception_insn(s, s->pc_curr, EXCP_NOCP, - syn_uncategorized(), default_exception_el(s)); - return true; - } - - if (s->fp_excp_el != 0) { - gen_exception_insn(s, s->pc_curr, EXCP_NOCP, - syn_uncategorized(), s->fp_excp_el); - return true; - } - - return false; -} - -static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a) -{ - /* This range needs a coprocessor check for v8.1M and later only */ - if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { - return false; - } - return trans_NOCP(s, a); -} - static bool trans_VINS(DisasContext *s, arg_VINS *a) { TCGv_i32 rd, rm; diff --git a/target/arm/translate.c b/target/arm/translate.c index 43ff0d4b8a..455352bcf6 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -50,12 +50,7 @@ #define ENABLE_ARCH_8 arm_dc_feature(s, ARM_FEATURE_V8) #include "translate.h" - -#if defined(CONFIG_USER_ONLY) -#define IS_USER(s) 1 -#else -#define IS_USER(s) (s->user) -#endif +#include "translate-a32.h" /* These are TCG temporaries used only by the legacy iwMMXt decoder */ static TCGv_i64 cpu_V0, cpu_V1, cpu_M0; @@ -71,11 +66,6 @@ static const char * const regnames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" }; -/* Function prototypes for gen_ functions calling Neon helpers. */ -typedef void NeonGenThreeOpEnvFn(TCGv_i32, TCGv_env, TCGv_i32, - TCGv_i32, TCGv_i32); -/* Function prototypes for gen_ functions for fix point conversions */ -typedef void VFPGenFixPointFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr); /* initialize TCG globals. */ void arm_translate_init(void) @@ -101,7 +91,7 @@ void arm_translate_init(void) } /* Generate a label used for skipping this instruction */ -static void arm_gen_condlabel(DisasContext *s) +void arm_gen_condlabel(DisasContext *s) { if (!s->condjmp) { s->condlabel = gen_new_label(); @@ -109,30 +99,6 @@ static void arm_gen_condlabel(DisasContext *s) } } -/* - * Constant expanders for the decoders. - */ - -static int negate(DisasContext *s, int x) -{ - return -x; -} - -static int plus_2(DisasContext *s, int x) -{ - return x + 2; -} - -static int times_2(DisasContext *s, int x) -{ - return x * 2; -} - -static int times_4(DisasContext *s, int x) -{ - return x * 4; -} - /* Flags for the disas_set_da_iss info argument: * lower bits hold the Rt register number, higher bits are flags. */ @@ -211,24 +177,6 @@ static inline int get_a32_user_mem_index(DisasContext *s) } } -static inline TCGv_i32 load_cpu_offset(int offset) -{ - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_ld_i32(tmp, cpu_env, offset); - return tmp; -} - -#define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name)) - -static inline void store_cpu_offset(TCGv_i32 var, int offset) -{ - tcg_gen_st_i32(var, cpu_env, offset); - tcg_temp_free_i32(var); -} - -#define store_cpu_field(var, name) \ - store_cpu_offset(var, offsetof(CPUARMState, name)) - /* The architectural value of PC. */ static uint32_t read_pc(DisasContext *s) { @@ -236,7 +184,7 @@ static uint32_t read_pc(DisasContext *s) } /* Set a variable to the value of a CPU register. */ -static void load_reg_var(DisasContext *s, TCGv_i32 var, int reg) +void load_reg_var(DisasContext *s, TCGv_i32 var, int reg) { if (reg == 15) { tcg_gen_movi_i32(var, read_pc(s)); @@ -245,20 +193,12 @@ static void load_reg_var(DisasContext *s, TCGv_i32 var, int reg) } } -/* Create a new temporary and set it to the value of a CPU register. */ -static inline TCGv_i32 load_reg(DisasContext *s, int reg) -{ - TCGv_i32 tmp = tcg_temp_new_i32(); - load_reg_var(s, tmp, reg); - return tmp; -} - /* * Create a new temp, REG + OFS, except PC is ALIGN(PC, 4). * This is used for load/store for which use of PC implies (literal), * or ADD that implies ADR. */ -static TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs) +TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs) { TCGv_i32 tmp = tcg_temp_new_i32(); @@ -272,7 +212,7 @@ static TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs) /* Set a CPU register. The source must be a temporary and will be marked as dead. */ -static void store_reg(DisasContext *s, int reg, TCGv_i32 var) +void store_reg(DisasContext *s, int reg, TCGv_i32 var) { if (reg == 15) { /* In Thumb mode, we must ignore bit 0. @@ -313,15 +253,12 @@ static void store_sp_checked(DisasContext *s, TCGv_i32 var) #define gen_sxtb16(var) gen_helper_sxtb16(var, var) #define gen_uxtb16(var) gen_helper_uxtb16(var, var) - -static inline void gen_set_cpsr(TCGv_i32 var, uint32_t mask) +void gen_set_cpsr(TCGv_i32 var, uint32_t mask) { TCGv_i32 tmp_mask = tcg_const_i32(mask); gen_helper_cpsr_write(cpu_env, var, tmp_mask); tcg_temp_free_i32(tmp_mask); } -/* Set NZCV flags from the high 4 bits of var. */ -#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV) static void gen_exception_internal(int excp) { @@ -388,7 +325,7 @@ static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b) } /* Byteswap each halfword. */ -static void gen_rev16(TCGv_i32 dest, TCGv_i32 var) +void gen_rev16(TCGv_i32 dest, TCGv_i32 var) { TCGv_i32 tmp = tcg_temp_new_i32(); TCGv_i32 mask = tcg_const_i32(0x00ff00ff); @@ -409,12 +346,6 @@ static void gen_revsh(TCGv_i32 dest, TCGv_i32 var) tcg_gen_ext16s_i32(dest, var); } -/* Swap low and high halfwords. */ -static void gen_swap_half(TCGv_i32 dest, TCGv_i32 var) -{ - tcg_gen_rotri_i32(dest, var, 16); -} - /* Dual 16-bit add. Result placed in t0 and t1 is marked as dead. tmp = (t0 ^ t1) & 0x8000; t0 &= ~0x8000; @@ -746,7 +677,7 @@ void arm_gen_test_cc(int cc, TCGLabel *label) arm_free_cc(&cmp); } -static inline void gen_set_condexec(DisasContext *s) +void gen_set_condexec(DisasContext *s) { if (s->condexec_mask) { uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1); @@ -756,7 +687,7 @@ static inline void gen_set_condexec(DisasContext *s) } } -static inline void gen_set_pc_im(DisasContext *s, target_ulong val) +void gen_set_pc_im(DisasContext *s, target_ulong val) { tcg_gen_movi_i32(cpu_R[15], val); } @@ -948,24 +879,24 @@ static TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, MemOp op) * Internal routines are used for NEON cases where the endianness * and/or alignment has already been taken into account and manipulated. */ -static void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val, - TCGv_i32 a32, int index, MemOp opc) +void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val, + TCGv_i32 a32, int index, MemOp opc) { TCGv addr = gen_aa32_addr(s, a32, opc); tcg_gen_qemu_ld_i32(val, addr, index, opc); tcg_temp_free(addr); } -static void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val, - TCGv_i32 a32, int index, MemOp opc) +void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val, + TCGv_i32 a32, int index, MemOp opc) { TCGv addr = gen_aa32_addr(s, a32, opc); tcg_gen_qemu_st_i32(val, addr, index, opc); tcg_temp_free(addr); } -static void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val, - TCGv_i32 a32, int index, MemOp opc) +void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val, + TCGv_i32 a32, int index, MemOp opc) { TCGv addr = gen_aa32_addr(s, a32, opc); @@ -978,8 +909,8 @@ static void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val, tcg_temp_free(addr); } -static void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val, - TCGv_i32 a32, int index, MemOp opc) +void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val, + TCGv_i32 a32, int index, MemOp opc) { TCGv addr = gen_aa32_addr(s, a32, opc); @@ -995,26 +926,26 @@ static void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val, tcg_temp_free(addr); } -static void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, - int index, MemOp opc) +void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, + int index, MemOp opc) { gen_aa32_ld_internal_i32(s, val, a32, index, finalize_memop(s, opc)); } -static void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, - int index, MemOp opc) +void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, + int index, MemOp opc) { gen_aa32_st_internal_i32(s, val, a32, index, finalize_memop(s, opc)); } -static void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, - int index, MemOp opc) +void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, + int index, MemOp opc) { gen_aa32_ld_internal_i64(s, val, a32, index, finalize_memop(s, opc)); } -static void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, - int index, MemOp opc) +void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, + int index, MemOp opc) { gen_aa32_st_internal_i64(s, val, a32, index, finalize_memop(s, opc)); } @@ -1033,25 +964,6 @@ static void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, gen_aa32_st_i32(s, val, a32, index, OPC); \ } -static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val, - TCGv_i32 a32, int index) -{ - gen_aa32_ld_i64(s, val, a32, index, MO_Q); -} - -static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val, - TCGv_i32 a32, int index) -{ - gen_aa32_st_i64(s, val, a32, index, MO_Q); -} - -DO_GEN_LD(8u, MO_UB) -DO_GEN_LD(16u, MO_UW) -DO_GEN_LD(32u, MO_UL) -DO_GEN_ST(8, MO_UB) -DO_GEN_ST(16, MO_UW) -DO_GEN_ST(32, MO_UL) - static inline void gen_hvc(DisasContext *s, int imm16) { /* The pre HVC helper handles cases when HVC gets trapped @@ -1093,11 +1005,15 @@ static void gen_exception_internal_insn(DisasContext *s, uint32_t pc, int excp) s->base.is_jmp = DISAS_NORETURN; } -static void gen_exception_insn(DisasContext *s, uint32_t pc, int excp, - int syn, uint32_t target_el) +void gen_exception_insn(DisasContext *s, uint64_t pc, int excp, + uint32_t syn, uint32_t target_el) { - gen_set_condexec(s); - gen_set_pc_im(s, pc); + if (s->aarch64) { + gen_a64_set_pc_im(pc); + } else { + gen_set_condexec(s); + gen_set_pc_im(s, pc); + } gen_exception(excp, syn, target_el); s->base.is_jmp = DISAS_NORETURN; } @@ -1114,7 +1030,7 @@ static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn) s->base.is_jmp = DISAS_NORETURN; } -static void unallocated_encoding(DisasContext *s) +void unallocated_encoding(DisasContext *s) { /* Unallocated and reserved encodings are uncategorized */ gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(), @@ -1138,7 +1054,7 @@ static void gen_exception_el(DisasContext *s, int excp, uint32_t syn, } /* Force a TB lookup after an instruction that changes the CPU state. */ -static inline void gen_lookup_tb(DisasContext *s) +void gen_lookup_tb(DisasContext *s) { tcg_gen_movi_i32(cpu_R[15], s->base.pc_next); s->base.is_jmp = DISAS_EXIT; @@ -1173,7 +1089,7 @@ static inline void gen_hlt(DisasContext *s, int imm) /* * Return the offset of a "full" NEON Dreg. */ -static long neon_full_reg_offset(unsigned reg) +long neon_full_reg_offset(unsigned reg) { return offsetof(CPUARMState, vfp.zregs[reg >> 1].d[reg & 1]); } @@ -1182,7 +1098,7 @@ static long neon_full_reg_offset(unsigned reg) * Return the offset of a 2**SIZE piece of a NEON register, at index ELE, * where 0 is the least significant end of the register. */ -static long neon_element_offset(int reg, int element, MemOp memop) +long neon_element_offset(int reg, int element, MemOp memop) { int element_size = 1 << (memop & MO_SIZE); int ofs = element * element_size; @@ -1199,7 +1115,7 @@ static long neon_element_offset(int reg, int element, MemOp memop) } /* Return the offset of a VFP Dreg (dp = true) or VFP Sreg (dp = false). */ -static long vfp_reg_offset(bool dp, unsigned reg) +long vfp_reg_offset(bool dp, unsigned reg) { if (dp) { return neon_element_offset(reg, 0, MO_64); @@ -1208,27 +1124,7 @@ static long vfp_reg_offset(bool dp, unsigned reg) } } -static inline void vfp_load_reg64(TCGv_i64 var, int reg) -{ - tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(true, reg)); -} - -static inline void vfp_store_reg64(TCGv_i64 var, int reg) -{ - tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(true, reg)); -} - -static inline void vfp_load_reg32(TCGv_i32 var, int reg) -{ - tcg_gen_ld_i32(var, cpu_env, vfp_reg_offset(false, reg)); -} - -static inline void vfp_store_reg32(TCGv_i32 var, int reg) -{ - tcg_gen_st_i32(var, cpu_env, vfp_reg_offset(false, reg)); -} - -static void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop) +void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop) { long off = neon_element_offset(reg, ele, memop); @@ -1254,7 +1150,7 @@ static void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop) } } -static void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop) +void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop) { long off = neon_element_offset(reg, ele, memop); @@ -1273,7 +1169,7 @@ static void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop) } } -static void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop) +void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop) { long off = neon_element_offset(reg, ele, memop); @@ -1292,7 +1188,7 @@ static void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop) } } -static void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop) +void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop) { long off = neon_element_offset(reg, ele, memop); @@ -1308,20 +1204,8 @@ static void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop) } } -static TCGv_ptr vfp_reg_ptr(bool dp, int reg) -{ - TCGv_ptr ret = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(ret, cpu_env, vfp_reg_offset(dp, reg)); - return ret; -} - #define ARM_CP_RW_BIT (1 << 20) -/* Include the VFP and Neon decoders */ -#include "decode-m-nocp.c.inc" -#include "translate-vfp.c.inc" -#include "translate-neon.c.inc" - static inline void iwmmxt_load_reg(TCGv_i64 var, int reg) { tcg_gen_ld_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg])); diff --git a/target/arm/translate.h b/target/arm/translate.h index ccf60c96d8..12c28b0d32 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -118,6 +118,30 @@ extern TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF; extern TCGv_i64 cpu_exclusive_addr; extern TCGv_i64 cpu_exclusive_val; +/* + * Constant expanders for the decoders. + */ + +static inline int negate(DisasContext *s, int x) +{ + return -x; +} + +static inline int plus_2(DisasContext *s, int x) +{ + return x + 2; +} + +static inline int times_2(DisasContext *s, int x) +{ + return x * 2; +} + +static inline int times_4(DisasContext *s, int x) +{ + return x * 4; +} + static inline int arm_dc_feature(DisasContext *dc, int feature) { return (dc->features & (1ULL << feature)) != 0; @@ -205,6 +229,9 @@ void arm_free_cc(DisasCompare *cmp); void arm_jump_cc(DisasCompare *cmp, TCGLabel *label); void arm_gen_test_cc(int cc, TCGLabel *label); MemOp pow2_align(unsigned i); +void unallocated_encoding(DisasContext *s); +void gen_exception_insn(DisasContext *s, uint64_t pc, int excp, + uint32_t syn, uint32_t target_el); /* Return state of Alternate Half-precision flag, caller frees result */ static inline TCGv_i32 get_ahp_flag(void) @@ -382,6 +409,8 @@ typedef void NeonGenOneOpFn(TCGv_i32, TCGv_i32); typedef void NeonGenOneOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32); typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32); typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32); +typedef void NeonGenThreeOpEnvFn(TCGv_i32, TCGv_env, TCGv_i32, + TCGv_i32, TCGv_i32); typedef void NeonGenTwo64OpFn(TCGv_i64, TCGv_i64, TCGv_i64); typedef void NeonGenTwo64OpEnvFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64); typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64); diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index 4b2290650b..ff8ae73002 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -615,15 +615,9 @@ int cpu_cwp_inc(CPUSPARCState *env1, int cwp); int cpu_cwp_dec(CPUSPARCState *env1, int cwp); void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); -/* int_helper.c */ -void leon3_irq_manager(CPUSPARCState *env, void *irq_manager, int intno); - /* sun4m.c, sun4u.c */ void cpu_check_irqs(CPUSPARCState *env); -/* leon3.c */ -void leon3_irq_ack(void *irq_manager, int intno); - #if defined (TARGET_SPARC64) static inline int compare_masked(uint64_t x, uint64_t y, uint64_t mask) diff --git a/target/sparc/int32_helper.c b/target/sparc/int32_helper.c index 817a463a17..82e8418e46 100644 --- a/target/sparc/int32_helper.c +++ b/target/sparc/int32_helper.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/main-loop.h" #include "cpu.h" #include "trace.h" #include "exec/log.h" @@ -64,6 +65,38 @@ static const char *excp_name_str(int32_t exception_index) return excp_names[exception_index]; } +void cpu_check_irqs(CPUSPARCState *env) +{ + CPUState *cs; + + /* We should be holding the BQL before we mess with IRQs */ + g_assert(qemu_mutex_iothread_locked()); + + if (env->pil_in && (env->interrupt_index == 0 || + (env->interrupt_index & ~15) == TT_EXTINT)) { + unsigned int i; + + for (i = 15; i > 0; i--) { + if (env->pil_in & (1 << i)) { + int old_interrupt = env->interrupt_index; + + env->interrupt_index = TT_EXTINT | i; + if (old_interrupt != env->interrupt_index) { + cs = env_cpu(env); + trace_sun4m_cpu_interrupt(i); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } + break; + } + } + } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) { + cs = env_cpu(env); + trace_sun4m_cpu_reset_interrupt(env->interrupt_index & 15); + env->interrupt_index = 0; + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } +} + void sparc_cpu_do_interrupt(CPUState *cs) { SPARCCPU *cpu = SPARC_CPU(cs); @@ -136,40 +169,3 @@ void sparc_cpu_do_interrupt(CPUState *cs) } #endif } - -#if !defined(CONFIG_USER_ONLY) -static void leon3_cache_control_int(CPUSPARCState *env) -{ - uint32_t state = 0; - - if (env->cache_control & CACHE_CTRL_IF) { - /* Instruction cache state */ - state = env->cache_control & CACHE_STATE_MASK; - if (state == CACHE_ENABLED) { - state = CACHE_FROZEN; - trace_int_helper_icache_freeze(); - } - - env->cache_control &= ~CACHE_STATE_MASK; - env->cache_control |= state; - } - - if (env->cache_control & CACHE_CTRL_DF) { - /* Data cache state */ - state = (env->cache_control >> 2) & CACHE_STATE_MASK; - if (state == CACHE_ENABLED) { - state = CACHE_FROZEN; - trace_int_helper_dcache_freeze(); - } - - env->cache_control &= ~(CACHE_STATE_MASK << 2); - env->cache_control |= (state << 2); - } -} - -void leon3_irq_manager(CPUSPARCState *env, void *irq_manager, int intno) -{ - leon3_irq_ack(irq_manager, intno); - leon3_cache_control_int(env); -} -#endif diff --git a/target/sparc/int64_helper.c b/target/sparc/int64_helper.c index 7fb8ab211c..793e57c536 100644 --- a/target/sparc/int64_helper.c +++ b/target/sparc/int64_helper.c @@ -62,6 +62,72 @@ static const char * const excp_names[0x80] = { }; #endif +void cpu_check_irqs(CPUSPARCState *env) +{ + CPUState *cs; + uint32_t pil = env->pil_in | + (env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER)); + + /* We should be holding the BQL before we mess with IRQs */ + g_assert(qemu_mutex_iothread_locked()); + + /* TT_IVEC has a higher priority (16) than TT_EXTINT (31..17) */ + if (env->ivec_status & 0x20) { + return; + } + cs = env_cpu(env); + /* + * check if TM or SM in SOFTINT are set + * setting these also causes interrupt 14 + */ + if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) { + pil |= 1 << 14; + } + + /* + * The bit corresponding to psrpil is (1<< psrpil), + * the next bit is (2 << psrpil). + */ + if (pil < (2 << env->psrpil)) { + if (cs->interrupt_request & CPU_INTERRUPT_HARD) { + trace_sparc64_cpu_check_irqs_reset_irq(env->interrupt_index); + env->interrupt_index = 0; + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } + return; + } + + if (cpu_interrupts_enabled(env)) { + + unsigned int i; + + for (i = 15; i > env->psrpil; i--) { + if (pil & (1 << i)) { + int old_interrupt = env->interrupt_index; + int new_interrupt = TT_EXTINT | i; + + if (unlikely(env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt + && ((cpu_tsptr(env)->tt & 0x1f0) == TT_EXTINT))) { + trace_sparc64_cpu_check_irqs_noset_irq(env->tl, + cpu_tsptr(env)->tt, + new_interrupt); + } else if (old_interrupt != new_interrupt) { + env->interrupt_index = new_interrupt; + trace_sparc64_cpu_check_irqs_set_irq(i, old_interrupt, + new_interrupt); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } + break; + } + } + } else if (cs->interrupt_request & CPU_INTERRUPT_HARD) { + trace_sparc64_cpu_check_irqs_disabled(pil, env->pil_in, env->softint, + env->interrupt_index); + env->interrupt_index = 0; + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } +} + void sparc_cpu_do_interrupt(CPUState *cs) { SPARCCPU *cpu = SPARC_CPU(cs); diff --git a/target/sparc/trace-events b/target/sparc/trace-events index 6a064e2327..75e7093d5f 100644 --- a/target/sparc/trace-events +++ b/target/sparc/trace-events @@ -10,14 +10,18 @@ mmu_helper_get_phys_addr_code(uint32_t tl, int mmu_idx, uint64_t prim_context, u mmu_helper_get_phys_addr_data(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=0x%"PRIx64" secondary context=0x%"PRIx64" address=0x%"PRIx64 mmu_helper_mmu_fault(uint64_t address, uint64_t paddr, int mmu_idx, uint32_t tl, uint64_t prim_context, uint64_t sec_context) "Translate at 0x%"PRIx64" -> 0x%"PRIx64", mmu_idx=%d tl=%d primary context=0x%"PRIx64" secondary context=0x%"PRIx64 +# int32_helper.c +sun4m_cpu_interrupt(unsigned int level) "Set CPU IRQ %d" +sun4m_cpu_reset_interrupt(unsigned int level) "Reset CPU IRQ %d" + # int64_helper.c int_helper_set_softint(uint32_t softint) "new 0x%08x" int_helper_clear_softint(uint32_t softint) "new 0x%08x" int_helper_write_softint(uint32_t softint) "new 0x%08x" - -# int32_helper.c -int_helper_icache_freeze(void) "Instruction cache: freeze" -int_helper_dcache_freeze(void) "Data cache: freeze" +sparc64_cpu_check_irqs_reset_irq(int intno) "Reset CPU IRQ (current interrupt 0x%x)" +sparc64_cpu_check_irqs_noset_irq(uint32_t tl, uint32_t tt, int intno) "Not setting CPU IRQ: TL=%d current 0x%x >= pending 0x%x" +sparc64_cpu_check_irqs_set_irq(unsigned int i, int old, int new) "Set CPU IRQ %d old=0x%x new=0x%x" +sparc64_cpu_check_irqs_disabled(uint32_t pil, uint32_t pil_in, uint32_t softint, int intno) "Interrupts disabled, pil=0x%08x pil_in=0x%08x softint=0x%08x current interrupt 0x%x" # win_helper.c win_helper_gregset_error(uint32_t pstate) "ERROR in get_gregset: active pstate bits=0x%x" diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c index 58e32fc963..7fe2cef1eb 100644 --- a/tools/virtiofsd/fuse_lowlevel.c +++ b/tools/virtiofsd/fuse_lowlevel.c @@ -106,7 +106,7 @@ static void list_add_req(struct fuse_req *req, struct fuse_req *next) static void destroy_req(fuse_req_t req) { pthread_mutex_destroy(&req->lock); - free(req); + g_free(req); } void fuse_free_req(fuse_req_t req) @@ -130,7 +130,7 @@ static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se) { struct fuse_req *req; - req = (struct fuse_req *)calloc(1, sizeof(struct fuse_req)); + req = g_try_new0(struct fuse_req, 1); if (req == NULL) { fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate request\n"); } else { @@ -217,9 +217,9 @@ static int send_reply(fuse_req_t req, int error, const void *arg, int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count) { int res; - struct iovec *padded_iov; + g_autofree struct iovec *padded_iov = NULL; - padded_iov = malloc((count + 1) * sizeof(struct iovec)); + padded_iov = g_try_new(struct iovec, count + 1); if (padded_iov == NULL) { return fuse_reply_err(req, ENOMEM); } @@ -228,7 +228,6 @@ int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count) count++; res = send_reply_iov(req, 0, padded_iov, count); - free(padded_iov); return res; } @@ -568,7 +567,7 @@ static struct fuse_ioctl_iovec *fuse_ioctl_iovec_copy(const struct iovec *iov, struct fuse_ioctl_iovec *fiov; size_t i; - fiov = malloc(sizeof(fiov[0]) * count); + fiov = g_try_new(struct fuse_ioctl_iovec, count); if (!fiov) { return NULL; } @@ -586,8 +585,8 @@ int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, size_t out_count) { struct fuse_ioctl_out arg; - struct fuse_ioctl_iovec *in_fiov = NULL; - struct fuse_ioctl_iovec *out_fiov = NULL; + g_autofree struct fuse_ioctl_iovec *in_fiov = NULL; + g_autofree struct fuse_ioctl_iovec *out_fiov = NULL; struct iovec iov[4]; size_t count = 1; int res; @@ -603,13 +602,14 @@ int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, /* Can't handle non-compat 64bit ioctls on 32bit */ if (sizeof(void *) == 4 && req->ioctl_64bit) { res = fuse_reply_err(req, EINVAL); - goto out; + return res; } if (in_count) { in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count); if (!in_fiov) { - goto enomem; + res = fuse_reply_err(req, ENOMEM); + return res; } iov[count].iov_base = (void *)in_fiov; @@ -619,7 +619,8 @@ int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, if (out_count) { out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count); if (!out_fiov) { - goto enomem; + res = fuse_reply_err(req, ENOMEM); + return res; } iov[count].iov_base = (void *)out_fiov; @@ -628,15 +629,8 @@ int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, } res = send_reply_iov(req, 0, iov, count); -out: - free(in_fiov); - free(out_fiov); return res; - -enomem: - res = fuse_reply_err(req, ENOMEM); - goto out; } int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size) @@ -663,11 +657,11 @@ int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size) int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count) { - struct iovec *padded_iov; + g_autofree struct iovec *padded_iov = NULL; struct fuse_ioctl_out arg; int res; - padded_iov = malloc((count + 2) * sizeof(struct iovec)); + padded_iov = g_try_new(struct iovec, count + 2); if (padded_iov == NULL) { return fuse_reply_err(req, ENOMEM); } @@ -680,7 +674,6 @@ int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, memcpy(&padded_iov[2], iov, count * sizeof(struct iovec)); res = send_reply_iov(req, 0, padded_iov, count + 2); - free(padded_iov); return res; } @@ -1684,7 +1677,7 @@ static struct fuse_req *check_interrupt(struct fuse_session *se, if (curr->u.i.unique == req->unique) { req->interrupted = 1; list_del_req(curr); - free(curr); + g_free(curr); return NULL; } } @@ -2477,7 +2470,7 @@ void fuse_session_destroy(struct fuse_session *se) free(se->vu_socket_path); se->vu_socket_path = NULL; - free(se); + g_free(se); } @@ -2500,7 +2493,7 @@ struct fuse_session *fuse_session_new(struct fuse_args *args, return NULL; } - se = (struct fuse_session *)calloc(1, sizeof(struct fuse_session)); + se = g_try_new0(struct fuse_session, 1); if (se == NULL) { fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n"); goto out1; @@ -2560,7 +2553,7 @@ struct fuse_session *fuse_session_new(struct fuse_args *args, out4: fuse_opt_free_args(args); out2: - free(se); + g_free(se); out1: return NULL; } diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c index 3e13997406..1170f375a5 100644 --- a/tools/virtiofsd/fuse_virtio.c +++ b/tools/virtiofsd/fuse_virtio.c @@ -129,18 +129,55 @@ static void fv_panic(VuDev *dev, const char *err) * Copy from an iovec into a fuse_buf (memory only) * Caller must ensure there is space */ -static void copy_from_iov(struct fuse_buf *buf, size_t out_num, - const struct iovec *out_sg) +static size_t copy_from_iov(struct fuse_buf *buf, size_t out_num, + const struct iovec *out_sg, + size_t max) { void *dest = buf->mem; + size_t copied = 0; - while (out_num) { + while (out_num && max) { size_t onelen = out_sg->iov_len; + onelen = MIN(onelen, max); memcpy(dest, out_sg->iov_base, onelen); dest += onelen; + copied += onelen; out_sg++; out_num--; + max -= onelen; } + + return copied; +} + +/* + * Skip 'skip' bytes in the iov; 'sg_1stindex' is set as + * the index for the 1st iovec to read data from, and + * 'sg_1stskip' is the number of bytes to skip in that entry. + * + * Returns True if there are at least 'skip' bytes in the iovec + * + */ +static bool skip_iov(const struct iovec *sg, size_t sg_size, + size_t skip, + size_t *sg_1stindex, size_t *sg_1stskip) +{ + size_t vec; + + for (vec = 0; vec < sg_size; vec++) { + if (sg[vec].iov_len > skip) { + *sg_1stskip = skip; + *sg_1stindex = vec; + + return true; + } + + skip -= sg[vec].iov_len; + } + + *sg_1stindex = vec; + *sg_1stskip = 0; + return skip == 0; } /* @@ -294,6 +331,7 @@ int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, VuVirtq *q = vu_get_queue(dev, qi->qidx); VuVirtqElement *elem = &req->elem; int ret = 0; + g_autofree struct iovec *in_sg_cpy = NULL; assert(count >= 1); assert(iov[0].iov_len >= sizeof(struct fuse_out_header)); @@ -347,8 +385,7 @@ int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, * Build a copy of the the in_sg iov so we can skip bits in it, * including changing the offsets */ - struct iovec *in_sg_cpy = calloc(sizeof(struct iovec), in_num); - assert(in_sg_cpy); + in_sg_cpy = g_new(struct iovec, in_num); memcpy(in_sg_cpy, in_sg, sizeof(struct iovec) * in_num); /* These get updated as we skip */ struct iovec *in_sg_ptr = in_sg_cpy; @@ -386,7 +423,6 @@ int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, ret = errno; fuse_log(FUSE_LOG_DEBUG, "%s: preadv failed (%m) len=%zd\n", __func__, len); - free(in_sg_cpy); goto err; } fuse_log(FUSE_LOG_DEBUG, "%s: preadv ret=%d len=%zd\n", __func__, @@ -410,13 +446,11 @@ int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, if (ret != len) { fuse_log(FUSE_LOG_DEBUG, "%s: ret!=len\n", __func__); ret = EIO; - free(in_sg_cpy); goto err; } in_sg_left -= ret; len -= ret; } while (in_sg_left); - free(in_sg_cpy); /* Need to fix out->len on EOF */ if (len) { @@ -457,6 +491,7 @@ static void fv_queue_worker(gpointer data, gpointer user_data) bool allocated_bufv = false; struct fuse_bufvec bufv; struct fuse_bufvec *pbufv; + struct fuse_in_header inh; assert(se->bufsize > sizeof(struct fuse_in_header)); @@ -476,8 +511,7 @@ static void fv_queue_worker(gpointer data, gpointer user_data) * They're spread over multiple descriptors in a scatter/gather set * and we can't trust the guest to keep them still; so copy in/out. */ - fbuf.mem = malloc(se->bufsize); - assert(fbuf.mem); + fbuf.mem = g_malloc(se->bufsize); fuse_mutex_init(&req->ch.lock); req->ch.fd = -1; @@ -505,14 +539,15 @@ static void fv_queue_worker(gpointer data, gpointer user_data) elem->index); assert(0); /* TODO */ } - /* Copy just the first element and look at it */ - copy_from_iov(&fbuf, 1, out_sg); + /* Copy just the fuse_in_header and look at it */ + copy_from_iov(&fbuf, out_num, out_sg, + sizeof(struct fuse_in_header)); + memcpy(&inh, fbuf.mem, sizeof(struct fuse_in_header)); pbufv = NULL; /* Compiler thinks an unitialised path */ - if (out_num > 2 && - out_sg[0].iov_len == sizeof(struct fuse_in_header) && - ((struct fuse_in_header *)fbuf.mem)->opcode == FUSE_WRITE && - out_sg[1].iov_len == sizeof(struct fuse_write_in)) { + if (inh.opcode == FUSE_WRITE && + out_len >= (sizeof(struct fuse_in_header) + + sizeof(struct fuse_write_in))) { /* * For a write we don't actually need to copy the * data, we can just do it straight out of guest memory @@ -521,15 +556,15 @@ static void fv_queue_worker(gpointer data, gpointer user_data) */ fuse_log(FUSE_LOG_DEBUG, "%s: Write special case\n", __func__); - /* copy the fuse_write_in header afte rthe fuse_in_header */ - fbuf.mem += out_sg->iov_len; - copy_from_iov(&fbuf, 1, out_sg + 1); - fbuf.mem -= out_sg->iov_len; - fbuf.size = out_sg[0].iov_len + out_sg[1].iov_len; + fbuf.size = copy_from_iov(&fbuf, out_num, out_sg, + sizeof(struct fuse_in_header) + + sizeof(struct fuse_write_in)); + /* That copy reread the in_header, make sure we use the original */ + memcpy(fbuf.mem, &inh, sizeof(struct fuse_in_header)); /* Allocate the bufv, with space for the rest of the iov */ - pbufv = malloc(sizeof(struct fuse_bufvec) + - sizeof(struct fuse_buf) * (out_num - 2)); + pbufv = g_try_malloc(sizeof(struct fuse_bufvec) + + sizeof(struct fuse_buf) * out_num); if (!pbufv) { fuse_log(FUSE_LOG_ERR, "%s: pbufv malloc failed\n", __func__); @@ -540,24 +575,37 @@ static void fv_queue_worker(gpointer data, gpointer user_data) pbufv->count = 1; pbufv->buf[0] = fbuf; - size_t iovindex, pbufvindex; - iovindex = 2; /* 2 headers, separate iovs */ + size_t iovindex, pbufvindex, iov_bytes_skip; pbufvindex = 1; /* 2 headers, 1 fusebuf */ + if (!skip_iov(out_sg, out_num, + sizeof(struct fuse_in_header) + + sizeof(struct fuse_write_in), + &iovindex, &iov_bytes_skip)) { + fuse_log(FUSE_LOG_ERR, "%s: skip failed\n", + __func__); + goto out; + } + for (; iovindex < out_num; iovindex++, pbufvindex++) { pbufv->count++; pbufv->buf[pbufvindex].pos = ~0; /* Dummy */ pbufv->buf[pbufvindex].flags = 0; pbufv->buf[pbufvindex].mem = out_sg[iovindex].iov_base; pbufv->buf[pbufvindex].size = out_sg[iovindex].iov_len; + + if (iov_bytes_skip) { + pbufv->buf[pbufvindex].mem += iov_bytes_skip; + pbufv->buf[pbufvindex].size -= iov_bytes_skip; + iov_bytes_skip = 0; + } } } else { /* Normal (non fast write) path */ - /* Copy the rest of the buffer */ - fbuf.mem += out_sg->iov_len; - copy_from_iov(&fbuf, out_num - 1, out_sg + 1); - fbuf.mem -= out_sg->iov_len; + copy_from_iov(&fbuf, out_num, out_sg, se->bufsize); + /* That copy reread the in_header, make sure we use the original */ + memcpy(fbuf.mem, &inh, sizeof(struct fuse_in_header)); fbuf.size = out_len; /* TODO! Endianness of header */ @@ -573,7 +621,7 @@ static void fv_queue_worker(gpointer data, gpointer user_data) out: if (allocated_bufv) { - free(pbufv); + g_free(pbufv); } /* If the request has no reply, still recycle the virtqueue element */ @@ -592,7 +640,7 @@ out: } pthread_mutex_destroy(&req->ch.lock); - free(fbuf.mem); + g_free(fbuf.mem); free(req); } @@ -733,7 +781,7 @@ static void fv_queue_cleanup_thread(struct fv_VuDev *vud, int qidx) pthread_mutex_destroy(&ourqi->vq_lock); close(ourqi->kill_fd); ourqi->kick_fd = -1; - free(vud->qi[qidx]); + g_free(vud->qi[qidx]); vud->qi[qidx] = NULL; } @@ -764,15 +812,13 @@ static void fv_queue_set_started(VuDev *dev, int qidx, bool started) if (started) { /* Fire up a thread to watch this queue */ if (qidx >= vud->nqueues) { - vud->qi = realloc(vud->qi, (qidx + 1) * sizeof(vud->qi[0])); - assert(vud->qi); + vud->qi = g_realloc_n(vud->qi, qidx + 1, sizeof(vud->qi[0])); memset(vud->qi + vud->nqueues, 0, sizeof(vud->qi[0]) * (1 + (qidx - vud->nqueues))); vud->nqueues = qidx + 1; } if (!vud->qi[qidx]) { - vud->qi[qidx] = calloc(sizeof(struct fv_QueueInfo), 1); - assert(vud->qi[qidx]); + vud->qi[qidx] = g_new0(struct fv_QueueInfo, 1); vud->qi[qidx]->virtio_dev = vud; vud->qi[qidx]->qidx = qidx; } else { @@ -1038,12 +1084,7 @@ int virtio_session_mount(struct fuse_session *se) __func__); /* TODO: Some cleanup/deallocation! */ - se->virtio_dev = calloc(sizeof(struct fv_VuDev), 1); - if (!se->virtio_dev) { - fuse_log(FUSE_LOG_ERR, "%s: virtio_dev calloc failed\n", __func__); - close(data_sock); - return -1; - } + se->virtio_dev = g_new0(struct fv_VuDev, 1); se->vu_socketfd = data_sock; se->virtio_dev->se = se; @@ -1065,8 +1106,8 @@ void virtio_session_close(struct fuse_session *se) return; } - free(se->virtio_dev->qi); + g_free(se->virtio_dev->qi); pthread_rwlock_destroy(&se->virtio_dev->vu_dispatch_rwlock); - free(se->virtio_dev); + g_free(se->virtio_dev); se->virtio_dev = NULL; } diff --git a/tools/virtiofsd/helper.c b/tools/virtiofsd/helper.c index 28243b51b2..5e98ed702b 100644 --- a/tools/virtiofsd/helper.c +++ b/tools/virtiofsd/helper.c @@ -172,6 +172,9 @@ void fuse_cmdline_help(void) " default: no_writeback\n" " -o xattr|no_xattr enable/disable xattr\n" " default: no_xattr\n" + " -o xattrmap=<mapping> Enable xattr mapping (enables xattr)\n" + " <mapping> is a string consists of a series of rules\n" + " e.g. -o xattrmap=:map::user.virtiofs.:\n" " -o modcaps=CAPLIST Modify the list of capabilities\n" " e.g. -o modcaps=+sys_admin:-chown\n" " --rlimit-nofile=<num> set maximum number of file descriptors\n" diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c index 1553d2ef45..49c21fd855 100644 --- a/tools/virtiofsd/passthrough_ll.c +++ b/tools/virtiofsd/passthrough_ll.c @@ -406,7 +406,7 @@ static void lo_map_init(struct lo_map *map) static void lo_map_destroy(struct lo_map *map) { - free(map->elems); + g_free(map->elems); } static int lo_map_grow(struct lo_map *map, size_t new_nelems) @@ -418,7 +418,7 @@ static int lo_map_grow(struct lo_map *map, size_t new_nelems) return 1; } - new_elems = realloc(map->elems, sizeof(map->elems[0]) * new_nelems); + new_elems = g_try_realloc_n(map->elems, new_nelems, sizeof(map->elems[0])); if (!new_elems) { return 0; } @@ -1653,7 +1653,7 @@ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, struct lo_data *lo = lo_data(req); struct lo_dirp *d = NULL; struct lo_inode *dinode; - char *buf = NULL; + g_autofree char *buf = NULL; char *p; size_t rem = size; int err = EBADF; @@ -1669,7 +1669,7 @@ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, } err = ENOMEM; - buf = calloc(1, size); + buf = g_try_malloc0(size); if (!buf) { goto error; } @@ -1755,7 +1755,6 @@ error: } else { fuse_reply_buf(req, buf, size - rem); } - free(buf); } static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, @@ -2011,10 +2010,10 @@ static void lo_getlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, fuse_log(FUSE_LOG_DEBUG, "lo_getlk(ino=%" PRIu64 ", flags=%d)" - " owner=0x%lx, l_type=%d l_start=0x%lx" - " l_len=0x%lx\n", - ino, fi->flags, fi->lock_owner, lock->l_type, lock->l_start, - lock->l_len); + " owner=0x%" PRIx64 ", l_type=%d l_start=0x%" PRIx64 + " l_len=0x%" PRIx64 "\n", + ino, fi->flags, fi->lock_owner, lock->l_type, + (uint64_t)lock->l_start, (uint64_t)lock->l_len); if (!lo->posix_lock) { fuse_reply_err(req, ENOSYS); @@ -2061,10 +2060,10 @@ static void lo_setlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, fuse_log(FUSE_LOG_DEBUG, "lo_setlk(ino=%" PRIu64 ", flags=%d)" - " cmd=%d pid=%d owner=0x%lx sleep=%d l_whence=%d" - " l_start=0x%lx l_len=0x%lx\n", + " cmd=%d pid=%d owner=0x%" PRIx64 " sleep=%d l_whence=%d" + " l_start=0x%" PRIx64 " l_len=0x%" PRIx64 "\n", ino, fi->flags, lock->l_type, lock->l_pid, fi->lock_owner, sleep, - lock->l_whence, lock->l_start, lock->l_len); + lock->l_whence, (uint64_t)lock->l_start, (uint64_t)lock->l_len); if (!lo->posix_lock) { fuse_reply_err(req, ENOSYS); @@ -2723,11 +2722,16 @@ static int xattr_map_server(const struct lo_data *lo, const char *server_name, return -ENODATA; } +#define FCHDIR_NOFAIL(fd) do { \ + int fchdir_res = fchdir(fd); \ + assert(fchdir_res == 0); \ + } while (0) + static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, size_t size) { struct lo_data *lo = lo_data(req); - char *value = NULL; + g_autofree char *value = NULL; char procname[64]; const char *name; char *mapped_name; @@ -2768,7 +2772,7 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, ino, name, size); if (size) { - value = malloc(size); + value = g_try_malloc(size); if (!value) { goto out_err; } @@ -2789,9 +2793,9 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, ret = fgetxattr(fd, name, value, size); } else { /* fchdir should not fail here */ - assert(fchdir(lo->proc_self_fd) == 0); + FCHDIR_NOFAIL(lo->proc_self_fd); ret = getxattr(procname, name, value, size); - assert(fchdir(lo->root.fd) == 0); + FCHDIR_NOFAIL(lo->root.fd); } if (ret == -1) { @@ -2807,8 +2811,6 @@ static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, fuse_reply_xattr(req, ret); } out_free: - free(value); - if (fd >= 0) { close(fd); } @@ -2827,7 +2829,7 @@ out: static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) { struct lo_data *lo = lo_data(req); - char *value = NULL; + g_autofree char *value = NULL; char procname[64]; struct lo_inode *inode; ssize_t ret; @@ -2849,7 +2851,7 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) size); if (size) { - value = malloc(size); + value = g_try_malloc(size); if (!value) { goto out_err; } @@ -2864,9 +2866,9 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) ret = flistxattr(fd, value, size); } else { /* fchdir should not fail here */ - assert(fchdir(lo->proc_self_fd) == 0); + FCHDIR_NOFAIL(lo->proc_self_fd); ret = listxattr(procname, value, size); - assert(fchdir(lo->root.fd) == 0); + FCHDIR_NOFAIL(lo->root.fd); } if (ret == -1) { @@ -2934,8 +2936,6 @@ static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) fuse_reply_xattr(req, ret); } out_free: - free(value); - if (fd >= 0) { close(fd); } @@ -3000,9 +3000,9 @@ static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *in_name, ret = fsetxattr(fd, name, value, size, flags); } else { /* fchdir should not fail here */ - assert(fchdir(lo->proc_self_fd) == 0); + FCHDIR_NOFAIL(lo->proc_self_fd); ret = setxattr(procname, name, value, size, flags); - assert(fchdir(lo->root.fd) == 0); + FCHDIR_NOFAIL(lo->root.fd); } saverr = ret == -1 ? errno : 0; @@ -3066,9 +3066,9 @@ static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *in_name) ret = fremovexattr(fd, name); } else { /* fchdir should not fail here */ - assert(fchdir(lo->proc_self_fd) == 0); + FCHDIR_NOFAIL(lo->proc_self_fd); ret = removexattr(procname, name); - assert(fchdir(lo->root.fd) == 0); + FCHDIR_NOFAIL(lo->root.fd); } saverr = ret == -1 ? errno : 0; @@ -3097,9 +3097,10 @@ static void lo_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in, fuse_log(FUSE_LOG_DEBUG, "lo_copy_file_range(ino=%" PRIu64 "/fd=%d, " - "off=%lu, ino=%" PRIu64 "/fd=%d, " - "off=%lu, size=%zd, flags=0x%x)\n", - ino_in, in_fd, off_in, ino_out, out_fd, off_out, len, flags); + "off=%ju, ino=%" PRIu64 "/fd=%d, " + "off=%ju, size=%zd, flags=0x%x)\n", + ino_in, in_fd, (intmax_t)off_in, + ino_out, out_fd, (intmax_t)off_out, len, flags); res = copy_file_range(in_fd, &off_in, out_fd, &off_out, len, flags); if (res < 0) { @@ -3826,6 +3827,7 @@ int main(int argc, char *argv[]) } if (lo.xattrmap) { + lo.xattr = 1; parse_xattrmap(&lo); } |