diff options
101 files changed, 3664 insertions, 881 deletions
@@ -76,6 +76,8 @@ GENERATED_HEADERS += trace/generated-ust-provider.h GENERATED_SOURCES += trace/generated-ust.c endif +GENERATED_HEADERS += module_block.h + # Don't try to regenerate Makefile or configure # We don't generate any of them Makefile: ; @@ -245,9 +247,6 @@ Makefile: $(version-obj-y) $(version-lobj-y) libqemustub.a: $(stub-obj-y) libqemuutil.a: $(util-obj-y) -block-modules = $(foreach o,$(block-obj-m),"$(basename $(subst /,-,$o))",) NULL -util/module.o-cflags = -D'CONFIG_BLOCK_MODULES=$(block-modules)' - ###################################################################### qemu-img.o: qemu-img-cmds.h @@ -352,6 +351,11 @@ ivshmem-client$(EXESUF): $(ivshmem-client-obj-y) libqemuutil.a libqemustub.a ivshmem-server$(EXESUF): $(ivshmem-server-obj-y) libqemuutil.a libqemustub.a $(call LINK, $^) +module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak + $(call quiet-command,$(PYTHON) $< $@ \ + $(addprefix $(SRC_PATH)/,$(patsubst %.mo,%.c,$(block-obj-m))), \ + " GEN $@") + clean: # avoid old build problems by removing potentially incorrect old files rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h @@ -27,6 +27,7 @@ #include "block/blockjob.h" #include "block/nbd.h" #include "qemu/error-report.h" +#include "module_block.h" #include "qemu/module.h" #include "qapi/qmp/qerror.h" #include "qapi/qmp/qbool.h" @@ -242,17 +243,40 @@ BlockDriverState *bdrv_new(void) return bs; } -BlockDriver *bdrv_find_format(const char *format_name) +static BlockDriver *bdrv_do_find_format(const char *format_name) { BlockDriver *drv1; + QLIST_FOREACH(drv1, &bdrv_drivers, list) { if (!strcmp(drv1->format_name, format_name)) { return drv1; } } + return NULL; } +BlockDriver *bdrv_find_format(const char *format_name) +{ + BlockDriver *drv1; + int i; + + drv1 = bdrv_do_find_format(format_name); + if (drv1) { + return drv1; + } + + /* The driver isn't registered, maybe we need to load a module */ + for (i = 0; i < (int)ARRAY_SIZE(block_driver_modules); ++i) { + if (!strcmp(block_driver_modules[i].format_name, format_name)) { + block_module_load_one(block_driver_modules[i].library_name); + break; + } + } + + return bdrv_do_find_format(format_name); +} + static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) { static const char *whitelist_rw[] = { @@ -461,6 +485,19 @@ static BlockDriver *find_hdev_driver(const char *filename) return drv; } +static BlockDriver *bdrv_do_find_protocol(const char *protocol) +{ + BlockDriver *drv1; + + QLIST_FOREACH(drv1, &bdrv_drivers, list) { + if (drv1->protocol_name && !strcmp(drv1->protocol_name, protocol)) { + return drv1; + } + } + + return NULL; +} + BlockDriver *bdrv_find_protocol(const char *filename, bool allow_protocol_prefix, Error **errp) @@ -469,6 +506,7 @@ BlockDriver *bdrv_find_protocol(const char *filename, char protocol[128]; int len; const char *p; + int i; /* TODO Drivers without bdrv_file_open must be specified explicitly */ @@ -495,15 +533,25 @@ BlockDriver *bdrv_find_protocol(const char *filename, len = sizeof(protocol) - 1; memcpy(protocol, filename, len); protocol[len] = '\0'; - QLIST_FOREACH(drv1, &bdrv_drivers, list) { - if (drv1->protocol_name && - !strcmp(drv1->protocol_name, protocol)) { - return drv1; + + drv1 = bdrv_do_find_protocol(protocol); + if (drv1) { + return drv1; + } + + for (i = 0; i < (int)ARRAY_SIZE(block_driver_modules); ++i) { + if (block_driver_modules[i].protocol_name && + !strcmp(block_driver_modules[i].protocol_name, protocol)) { + block_module_load_one(block_driver_modules[i].library_name); + break; } } - error_setg(errp, "Unknown protocol '%s'", protocol); - return NULL; + drv1 = bdrv_do_find_protocol(protocol); + if (!drv1) { + error_setg(errp, "Unknown protocol '%s'", protocol); + } + return drv1; } /* diff --git a/block/Makefile.objs b/block/Makefile.objs index 55da6266fe..cb158e9275 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -1,4 +1,4 @@ -block-obj-y += raw_bsd.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o +block-obj-y += raw_bsd.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o block-obj-y += qed-check.o @@ -29,6 +29,7 @@ block-obj-y += crypto.o common-obj-y += stream.o +nfs.o-libs := $(LIBNFS_LIBS) iscsi.o-cflags := $(LIBISCSI_CFLAGS) iscsi.o-libs := $(LIBISCSI_LIBS) curl.o-cflags := $(CURL_CFLAGS) @@ -40,7 +41,6 @@ gluster.o-libs := $(GLUSTERFS_LIBS) ssh.o-cflags := $(LIBSSH2_CFLAGS) ssh.o-libs := $(LIBSSH2_LIBS) archipelago.o-libs := $(ARCHIPELAGO_LIBS) -block-obj-m += dmg.o dmg.o-libs := $(BZIP2_LIBS) qcow.o-libs := -lz linux-aio.o-libs := -laio diff --git a/block/commit.c b/block/commit.c index 553e18da52..a02539bacc 100644 --- a/block/commit.c +++ b/block/commit.c @@ -83,7 +83,7 @@ static void commit_complete(BlockJob *job, void *opaque) BlockDriverState *active = s->active; BlockDriverState *top = blk_bs(s->top); BlockDriverState *base = blk_bs(s->base); - BlockDriverState *overlay_bs; + BlockDriverState *overlay_bs = bdrv_find_overlay(active, top); int ret = data->ret; if (!block_job_is_cancelled(&s->common) && ret == 0) { @@ -97,7 +97,6 @@ static void commit_complete(BlockJob *job, void *opaque) if (s->base_flags != bdrv_get_flags(base)) { bdrv_reopen(base, s->base_flags, NULL); } - overlay_bs = bdrv_find_overlay(active, top); if (overlay_bs && s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) { bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL); } diff --git a/block/iscsi.c b/block/iscsi.c index b2b4e5d2a9..8a940317d6 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -2013,45 +2013,9 @@ static BlockDriver bdrv_iscsi = { .bdrv_attach_aio_context = iscsi_attach_aio_context, }; -static QemuOptsList qemu_iscsi_opts = { - .name = "iscsi", - .head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head), - .desc = { - { - .name = "user", - .type = QEMU_OPT_STRING, - .help = "username for CHAP authentication to target", - },{ - .name = "password", - .type = QEMU_OPT_STRING, - .help = "password for CHAP authentication to target", - },{ - .name = "password-secret", - .type = QEMU_OPT_STRING, - .help = "ID of the secret providing password for CHAP " - "authentication to target", - },{ - .name = "header-digest", - .type = QEMU_OPT_STRING, - .help = "HeaderDigest setting. " - "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}", - },{ - .name = "initiator-name", - .type = QEMU_OPT_STRING, - .help = "Initiator iqn name to use when connecting", - },{ - .name = "timeout", - .type = QEMU_OPT_NUMBER, - .help = "Request timeout in seconds (default 0 = no timeout)", - }, - { /* end of list */ } - }, -}; - static void iscsi_block_init(void) { bdrv_register(&bdrv_iscsi); - qemu_add_opts(&qemu_iscsi_opts); } block_init(iscsi_block_init); @@ -4578,7 +4578,6 @@ if test "$libnfs" != "no" ; then if $pkg_config --atleast-version=1.9.3 libnfs; then libnfs="yes" libnfs_libs=$($pkg_config --libs libnfs) - LIBS="$LIBS $libnfs_libs" else if test "$libnfs" = "yes" ; then feature_not_found "libnfs" "Install libnfs devel >= 1.9.3" @@ -5351,7 +5350,8 @@ if test "$libiscsi" = "yes" ; then fi if test "$libnfs" = "yes" ; then - echo "CONFIG_LIBNFS=y" >> $config_host_mak + echo "CONFIG_LIBNFS=m" >> $config_host_mak + echo "LIBNFS_LIBS=$libnfs_libs" >> $config_host_mak fi if test "$seccomp" = "yes"; then diff --git a/disas/arm.c b/disas/arm.c index 426270fe82..93c650344c 100644 --- a/disas/arm.c +++ b/disas/arm.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "disas/bfd.h" -#define ISSPACE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n') #define ARM_EXT_V1 0 #define ARM_EXT_V2 0 @@ -73,15 +72,6 @@ static void floatformat_to_double (unsigned char *data, double *dest) /* End of qemu specific additions. */ -/* FIXME: Belongs in global header. */ -#ifndef strneq -#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) -#endif - -#ifndef NUM_ELEM -#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0]) -#endif - struct opcode32 { unsigned long arch; /* Architecture defining this insn. */ @@ -1528,7 +1518,6 @@ static const char *const iwmmxt_cregnames[] = /* Default to GCC register name set. */ static unsigned int regname_selected = 1; -#define NUM_ARM_REGNAMES NUM_ELEM (regnames) #define arm_regnames regnames[regname_selected].reg_names static bfd_boolean force_thumb = false; diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 12764ef2b7..4c5c4ee76c 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -17,4 +17,4 @@ obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o -obj-$(CONFIG_ASPEED_SOC) += ast2400.o palmetto-bmc.o +obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c new file mode 100644 index 0000000000..6b18c7f172 --- /dev/null +++ b/hw/arm/aspeed.c @@ -0,0 +1,197 @@ +/* + * OpenPOWER Palmetto BMC + * + * Andrew Jeffery <andrew@aj.id.au> + * + * Copyright 2016 IBM Corp. + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" +#include "exec/address-spaces.h" +#include "hw/arm/arm.h" +#include "hw/arm/aspeed_soc.h" +#include "hw/boards.h" +#include "qemu/log.h" +#include "sysemu/block-backend.h" +#include "sysemu/blockdev.h" + +static struct arm_boot_info aspeed_board_binfo = { + .board_id = -1, /* device-tree-only board */ + .nb_cpus = 1, +}; + +typedef struct AspeedBoardState { + AspeedSoCState soc; + MemoryRegion ram; +} AspeedBoardState; + +typedef struct AspeedBoardConfig { + const char *soc_name; + uint32_t hw_strap1; +} AspeedBoardConfig; + +enum { + PALMETTO_BMC, + AST2500_EVB, +}; + +#define PALMETTO_BMC_HW_STRAP1 ( \ + SCU_AST2400_HW_STRAP_DRAM_SIZE(DRAM_SIZE_256MB) | \ + SCU_AST2400_HW_STRAP_DRAM_CONFIG(2 /* DDR3 with CL=6, CWL=5 */) | \ + SCU_AST2400_HW_STRAP_ACPI_DIS | \ + SCU_AST2400_HW_STRAP_SET_CLK_SOURCE(AST2400_CLK_48M_IN) | \ + SCU_HW_STRAP_VGA_CLASS_CODE | \ + SCU_HW_STRAP_LPC_RESET_PIN | \ + SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_M_S_EN) | \ + SCU_AST2400_HW_STRAP_SET_CPU_AHB_RATIO(AST2400_CPU_AHB_RATIO_2_1) | \ + SCU_HW_STRAP_SPI_WIDTH | \ + SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) | \ + SCU_AST2400_HW_STRAP_BOOT_MODE(AST2400_SPI_BOOT)) + +#define AST2500_EVB_HW_STRAP1 (( \ + AST2500_HW_STRAP1_DEFAULTS | \ + SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \ + SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE | \ + SCU_AST2500_HW_STRAP_UART_DEBUG | \ + SCU_AST2500_HW_STRAP_DDR4_ENABLE | \ + SCU_HW_STRAP_MAC1_RGMII | \ + SCU_HW_STRAP_MAC0_RGMII) & \ + ~SCU_HW_STRAP_2ND_BOOT_WDT) + +static const AspeedBoardConfig aspeed_boards[] = { + [PALMETTO_BMC] = { "ast2400-a0", PALMETTO_BMC_HW_STRAP1 }, + [AST2500_EVB] = { "ast2500-a1", AST2500_EVB_HW_STRAP1 }, +}; + +static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, + Error **errp) +{ + int i ; + + for (i = 0; i < s->num_cs; ++i) { + AspeedSMCFlash *fl = &s->flashes[i]; + DriveInfo *dinfo = drive_get_next(IF_MTD); + qemu_irq cs_line; + + /* + * FIXME: check that we are not using a flash module exceeding + * the controller segment size + */ + fl->flash = ssi_create_slave_no_init(s->spi, flashtype); + if (dinfo) { + qdev_prop_set_drive(fl->flash, "drive", blk_by_legacy_dinfo(dinfo), + errp); + } + qdev_init_nofail(fl->flash); + + cs_line = qdev_get_gpio_in_named(fl->flash, SSI_GPIO_CS, 0); + sysbus_connect_irq(SYS_BUS_DEVICE(s), i + 1, cs_line); + } +} + +static void aspeed_board_init(MachineState *machine, + const AspeedBoardConfig *cfg) +{ + AspeedBoardState *bmc; + AspeedSoCClass *sc; + + bmc = g_new0(AspeedBoardState, 1); + object_initialize(&bmc->soc, (sizeof(bmc->soc)), cfg->soc_name); + object_property_add_child(OBJECT(machine), "soc", OBJECT(&bmc->soc), + &error_abort); + + sc = ASPEED_SOC_GET_CLASS(&bmc->soc); + + object_property_set_int(OBJECT(&bmc->soc), ram_size, "ram-size", + &error_abort); + object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap1, "hw-strap1", + &error_abort); + object_property_set_bool(OBJECT(&bmc->soc), true, "realized", + &error_abort); + + /* + * Allocate RAM after the memory controller has checked the size + * was valid. If not, a default value is used. + */ + ram_size = object_property_get_int(OBJECT(&bmc->soc), "ram-size", + &error_abort); + + memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size); + memory_region_add_subregion(get_system_memory(), sc->info->sdram_base, + &bmc->ram); + object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram), + &error_abort); + + aspeed_board_init_flashes(&bmc->soc.smc, "n25q256a", &error_abort); + aspeed_board_init_flashes(&bmc->soc.spi, "mx25l25635e", &error_abort); + + aspeed_board_binfo.kernel_filename = machine->kernel_filename; + aspeed_board_binfo.initrd_filename = machine->initrd_filename; + aspeed_board_binfo.kernel_cmdline = machine->kernel_cmdline; + aspeed_board_binfo.ram_size = ram_size; + aspeed_board_binfo.loader_start = sc->info->sdram_base; + + arm_load_kernel(ARM_CPU(first_cpu), &aspeed_board_binfo); +} + +static void palmetto_bmc_init(MachineState *machine) +{ + aspeed_board_init(machine, &aspeed_boards[PALMETTO_BMC]); +} + +static void palmetto_bmc_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "OpenPOWER Palmetto BMC (ARM926EJ-S)"; + mc->init = palmetto_bmc_init; + mc->max_cpus = 1; + mc->no_sdcard = 1; + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->no_parallel = 1; +} + +static const TypeInfo palmetto_bmc_type = { + .name = MACHINE_TYPE_NAME("palmetto-bmc"), + .parent = TYPE_MACHINE, + .class_init = palmetto_bmc_class_init, +}; + +static void ast2500_evb_init(MachineState *machine) +{ + aspeed_board_init(machine, &aspeed_boards[AST2500_EVB]); +} + +static void ast2500_evb_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Aspeed AST2500 EVB (ARM1176)"; + mc->init = ast2500_evb_init; + mc->max_cpus = 1; + mc->no_sdcard = 1; + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->no_parallel = 1; +} + +static const TypeInfo ast2500_evb_type = { + .name = MACHINE_TYPE_NAME("ast2500-evb"), + .parent = TYPE_MACHINE, + .class_init = ast2500_evb_class_init, +}; + +static void aspeed_machine_init(void) +{ + type_register_static(&palmetto_bmc_type); + type_register_static(&ast2500_evb_type); +} + +type_init(aspeed_machine_init) diff --git a/hw/arm/ast2400.c b/hw/arm/aspeed_soc.c index 136bf6464e..c0a3102058 100644 --- a/hw/arm/ast2400.c +++ b/hw/arm/aspeed_soc.c @@ -1,5 +1,5 @@ /* - * AST2400 SoC + * ASPEED SoC family * * Andrew Jeffery <andrew@aj.id.au> * Jeremy Kerr <jk@ozlabs.org> @@ -15,59 +15,68 @@ #include "qemu-common.h" #include "cpu.h" #include "exec/address-spaces.h" -#include "hw/arm/ast2400.h" +#include "hw/arm/aspeed_soc.h" #include "hw/char/serial.h" #include "qemu/log.h" #include "hw/i2c/aspeed_i2c.h" -#define AST2400_UART_5_BASE 0x00184000 -#define AST2400_IOMEM_SIZE 0x00200000 -#define AST2400_IOMEM_BASE 0x1E600000 -#define AST2400_SMC_BASE AST2400_IOMEM_BASE /* Legacy SMC */ -#define AST2400_FMC_BASE 0X1E620000 -#define AST2400_SPI_BASE 0X1E630000 -#define AST2400_VIC_BASE 0x1E6C0000 -#define AST2400_SDMC_BASE 0x1E6E0000 -#define AST2400_SCU_BASE 0x1E6E2000 -#define AST2400_TIMER_BASE 0x1E782000 -#define AST2400_I2C_BASE 0x1E78A000 - -#define AST2400_FMC_FLASH_BASE 0x20000000 -#define AST2400_SPI_FLASH_BASE 0x30000000 +#define ASPEED_SOC_UART_5_BASE 0x00184000 +#define ASPEED_SOC_IOMEM_SIZE 0x00200000 +#define ASPEED_SOC_IOMEM_BASE 0x1E600000 +#define ASPEED_SOC_FMC_BASE 0x1E620000 +#define ASPEED_SOC_SPI_BASE 0x1E630000 +#define ASPEED_SOC_VIC_BASE 0x1E6C0000 +#define ASPEED_SOC_SDMC_BASE 0x1E6E0000 +#define ASPEED_SOC_SCU_BASE 0x1E6E2000 +#define ASPEED_SOC_TIMER_BASE 0x1E782000 +#define ASPEED_SOC_I2C_BASE 0x1E78A000 + +#define ASPEED_SOC_FMC_FLASH_BASE 0x20000000 +#define ASPEED_SOC_SPI_FLASH_BASE 0x30000000 static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; +#define AST2400_SDRAM_BASE 0x40000000 +#define AST2500_SDRAM_BASE 0x80000000 + +static const AspeedSoCInfo aspeed_socs[] = { + { "ast2400-a0", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE }, + { "ast2400", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE }, + { "ast2500-a1", "arm1176", AST2500_A1_SILICON_REV, AST2500_SDRAM_BASE }, +}; + /* * IO handlers: simply catch any reads/writes to IO addresses that aren't * handled by a device mapping. */ -static uint64_t ast2400_io_read(void *p, hwaddr offset, unsigned size) +static uint64_t aspeed_soc_io_read(void *p, hwaddr offset, unsigned size) { qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n", __func__, offset, size); return 0; } -static void ast2400_io_write(void *opaque, hwaddr offset, uint64_t value, +static void aspeed_soc_io_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " <- 0x%" PRIx64 " [%u]\n", __func__, offset, value, size); } -static const MemoryRegionOps ast2400_io_ops = { - .read = ast2400_io_read, - .write = ast2400_io_write, +static const MemoryRegionOps aspeed_soc_io_ops = { + .read = aspeed_soc_io_read, + .write = aspeed_soc_io_write, .endianness = DEVICE_LITTLE_ENDIAN, }; -static void ast2400_init(Object *obj) +static void aspeed_soc_init(Object *obj) { - AST2400State *s = AST2400(obj); + AspeedSoCState *s = ASPEED_SOC(obj); + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); - s->cpu = cpu_arm_init("arm926"); + s->cpu = cpu_arm_init(sc->info->cpu_model); object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC); object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL); @@ -85,7 +94,7 @@ static void ast2400_init(Object *obj) object_property_add_child(obj, "scu", OBJECT(&s->scu), NULL); qdev_set_parent_bus(DEVICE(&s->scu), sysbus_get_default()); qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", - AST2400_A0_SILICON_REV); + sc->info->silicon_rev); object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), "hw-strap1", &error_abort); object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), @@ -103,20 +112,22 @@ static void ast2400_init(Object *obj) object_property_add_child(obj, "sdmc", OBJECT(&s->sdmc), NULL); qdev_set_parent_bus(DEVICE(&s->sdmc), sysbus_get_default()); qdev_prop_set_uint32(DEVICE(&s->sdmc), "silicon-rev", - AST2400_A0_SILICON_REV); + sc->info->silicon_rev); + object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc), + "ram-size", &error_abort); } -static void ast2400_realize(DeviceState *dev, Error **errp) +static void aspeed_soc_realize(DeviceState *dev, Error **errp) { int i; - AST2400State *s = AST2400(dev); + AspeedSoCState *s = ASPEED_SOC(dev); Error *err = NULL, *local_err = NULL; /* IO space */ - memory_region_init_io(&s->iomem, NULL, &ast2400_io_ops, NULL, - "ast2400.io", AST2400_IOMEM_SIZE); - memory_region_add_subregion_overlap(get_system_memory(), AST2400_IOMEM_BASE, - &s->iomem, -1); + memory_region_init_io(&s->iomem, NULL, &aspeed_soc_io_ops, NULL, + "aspeed_soc.io", ASPEED_SOC_IOMEM_SIZE); + memory_region_add_subregion_overlap(get_system_memory(), + ASPEED_SOC_IOMEM_BASE, &s->iomem, -1); /* VIC */ object_property_set_bool(OBJECT(&s->vic), true, "realized", &err); @@ -124,7 +135,7 @@ static void ast2400_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, AST2400_VIC_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, ASPEED_SOC_VIC_BASE); sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0, qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1, @@ -136,7 +147,7 @@ static void ast2400_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, AST2400_TIMER_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, ASPEED_SOC_TIMER_BASE); for (i = 0; i < ARRAY_SIZE(timer_irqs); i++) { qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->vic), timer_irqs[i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); @@ -148,12 +159,12 @@ static void ast2400_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, AST2400_SCU_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, ASPEED_SOC_SCU_BASE); /* UART - attach an 8250 to the IO space as our UART5 */ if (serial_hds[0]) { qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]); - serial_mm_init(&s->iomem, AST2400_UART_5_BASE, 2, + serial_mm_init(&s->iomem, ASPEED_SOC_UART_5_BASE, 2, uart5, 38400, serial_hds[0], DEVICE_LITTLE_ENDIAN); } @@ -163,7 +174,7 @@ static void ast2400_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, AST2400_I2C_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, ASPEED_SOC_I2C_BASE); sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0, qdev_get_gpio_in(DEVICE(&s->vic), 12)); @@ -175,8 +186,8 @@ static void ast2400_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 0, AST2400_FMC_BASE); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 1, AST2400_FMC_FLASH_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 0, ASPEED_SOC_FMC_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 1, ASPEED_SOC_FMC_FLASH_BASE); sysbus_connect_irq(SYS_BUS_DEVICE(&s->smc), 0, qdev_get_gpio_in(DEVICE(&s->vic), 19)); @@ -188,8 +199,8 @@ static void ast2400_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 0, AST2400_SPI_BASE); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, AST2400_SPI_FLASH_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 0, ASPEED_SOC_SPI_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, ASPEED_SOC_SPI_FLASH_BASE); /* SDMC - SDRAM Memory Controller */ object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err); @@ -197,14 +208,16 @@ static void ast2400_realize(DeviceState *dev, Error **errp) error_propagate(errp, err); return; } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, AST2400_SDMC_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE); } -static void ast2400_class_init(ObjectClass *oc, void *data) +static void aspeed_soc_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc); - dc->realize = ast2400_realize; + sc->info = (AspeedSoCInfo *) data; + dc->realize = aspeed_soc_realize; /* * Reason: creates an ARM CPU, thus use after free(), see @@ -213,17 +226,29 @@ static void ast2400_class_init(ObjectClass *oc, void *data) dc->cannot_destroy_with_object_finalize_yet = true; } -static const TypeInfo ast2400_type_info = { - .name = TYPE_AST2400, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(AST2400State), - .instance_init = ast2400_init, - .class_init = ast2400_class_init, +static const TypeInfo aspeed_soc_type_info = { + .name = TYPE_ASPEED_SOC, + .parent = TYPE_DEVICE, + .instance_init = aspeed_soc_init, + .instance_size = sizeof(AspeedSoCState), + .class_size = sizeof(AspeedSoCClass), + .abstract = true, }; -static void ast2400_register_types(void) +static void aspeed_soc_register_types(void) { - type_register_static(&ast2400_type_info); + int i; + + type_register_static(&aspeed_soc_type_info); + for (i = 0; i < ARRAY_SIZE(aspeed_socs); ++i) { + TypeInfo ti = { + .name = aspeed_socs[i].name, + .parent = TYPE_ASPEED_SOC, + .class_init = aspeed_soc_class_init, + .class_data = (void *) &aspeed_socs[i], + }; + type_register(&ti); + } } -type_init(ast2400_register_types) +type_init(aspeed_soc_register_types) diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index cc50ace13d..7527037c23 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -837,7 +837,7 @@ static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s, s->freq = freq; bh = qemu_bh_new(mv88w8618_timer_tick, s); - s->ptimer = ptimer_init(bh); + s->ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); } static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset, diff --git a/hw/arm/palmetto-bmc.c b/hw/arm/palmetto-bmc.c deleted file mode 100644 index 54e29a865d..0000000000 --- a/hw/arm/palmetto-bmc.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * OpenPOWER Palmetto BMC - * - * Andrew Jeffery <andrew@aj.id.au> - * - * Copyright 2016 IBM Corp. - * - * This code is licensed under the GPL version 2 or later. See - * the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" -#include "exec/address-spaces.h" -#include "hw/arm/arm.h" -#include "hw/arm/ast2400.h" -#include "hw/boards.h" -#include "qemu/log.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" - -static struct arm_boot_info palmetto_bmc_binfo = { - .loader_start = AST2400_SDRAM_BASE, - .board_id = 0, - .nb_cpus = 1, -}; - -typedef struct PalmettoBMCState { - AST2400State soc; - MemoryRegion ram; -} PalmettoBMCState; - -static void palmetto_bmc_init_flashes(AspeedSMCState *s, const char *flashtype, - Error **errp) -{ - int i ; - - for (i = 0; i < s->num_cs; ++i) { - AspeedSMCFlash *fl = &s->flashes[i]; - DriveInfo *dinfo = drive_get_next(IF_MTD); - qemu_irq cs_line; - - /* - * FIXME: check that we are not using a flash module exceeding - * the controller segment size - */ - fl->flash = ssi_create_slave_no_init(s->spi, flashtype); - if (dinfo) { - qdev_prop_set_drive(fl->flash, "drive", blk_by_legacy_dinfo(dinfo), - errp); - } - qdev_init_nofail(fl->flash); - - cs_line = qdev_get_gpio_in_named(fl->flash, SSI_GPIO_CS, 0); - sysbus_connect_irq(SYS_BUS_DEVICE(s), i + 1, cs_line); - } -} - -static void palmetto_bmc_init(MachineState *machine) -{ - PalmettoBMCState *bmc; - - bmc = g_new0(PalmettoBMCState, 1); - object_initialize(&bmc->soc, (sizeof(bmc->soc)), TYPE_AST2400); - object_property_add_child(OBJECT(machine), "soc", OBJECT(&bmc->soc), - &error_abort); - - memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size); - memory_region_add_subregion(get_system_memory(), AST2400_SDRAM_BASE, - &bmc->ram); - object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram), - &error_abort); - object_property_set_int(OBJECT(&bmc->soc), 0x120CE416, "hw-strap1", - &error_abort); - object_property_set_bool(OBJECT(&bmc->soc), true, "realized", - &error_abort); - - palmetto_bmc_init_flashes(&bmc->soc.smc, "n25q256a", &error_abort); - palmetto_bmc_init_flashes(&bmc->soc.spi, "mx25l25635e", &error_abort); - - palmetto_bmc_binfo.kernel_filename = machine->kernel_filename; - palmetto_bmc_binfo.initrd_filename = machine->initrd_filename; - palmetto_bmc_binfo.kernel_cmdline = machine->kernel_cmdline; - palmetto_bmc_binfo.ram_size = ram_size; - arm_load_kernel(ARM_CPU(first_cpu), &palmetto_bmc_binfo); -} - -static void palmetto_bmc_machine_init(MachineClass *mc) -{ - mc->desc = "OpenPOWER Palmetto BMC"; - mc->init = palmetto_bmc_init; - mc->max_cpus = 1; - mc->no_sdcard = 1; - mc->no_floppy = 1; - mc->no_cdrom = 1; - mc->no_sdcard = 1; - mc->no_parallel = 1; -} - -DEFINE_MACHINE("palmetto-bmc", palmetto_bmc_machine_init); diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 23c7199867..0d86ba35ae 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -332,6 +332,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qdev_set_nic_properties(DEVICE(&s->gem[i]), nd); } + object_property_set_int(OBJECT(&s->gem[i]), 2, "num-priority-queues", + &error_abort); object_property_set_bool(OBJECT(&s->gem[i]), true, "realized", &err); if (err) { error_propagate(errp, err); diff --git a/hw/core/loader.c b/hw/core/loader.c index 53e0e41554..6e022b5ad5 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -133,10 +133,16 @@ ssize_t read_targphys(const char *name, return did; } -/* return the size or -1 if error */ int load_image_targphys(const char *filename, hwaddr addr, uint64_t max_sz) { + return load_image_targphys_as(filename, addr, max_sz, NULL); +} + +/* return the size or -1 if error */ +int load_image_targphys_as(const char *filename, + hwaddr addr, uint64_t max_sz, AddressSpace *as) +{ int size; size = get_image_size(filename); @@ -144,7 +150,7 @@ int load_image_targphys(const char *filename, return -1; } if (size > 0) { - rom_add_file_fixed(filename, addr, -1); + rom_add_file_fixed_as(filename, addr, -1, as); } return size; } @@ -417,6 +423,18 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb, int data_swab) { + return load_elf_as(filename, translate_fn, translate_opaque, pentry, + lowaddr, highaddr, big_endian, elf_machine, clear_lsb, + data_swab, NULL); +} + +/* return < 0 if error, otherwise the number of bytes loaded in memory */ +int load_elf_as(const char *filename, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr, + uint64_t *highaddr, int big_endian, int elf_machine, + int clear_lsb, int data_swab, AddressSpace *as) +{ int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED; uint8_t e_ident[EI_NIDENT]; @@ -455,11 +473,11 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), if (e_ident[EI_CLASS] == ELFCLASS64) { ret = load_elf64(filename, fd, translate_fn, translate_opaque, must_swab, pentry, lowaddr, highaddr, elf_machine, clear_lsb, - data_swab); + data_swab, as); } else { ret = load_elf32(filename, fd, translate_fn, translate_opaque, must_swab, pentry, lowaddr, highaddr, elf_machine, clear_lsb, - data_swab); + data_swab, as); } fail: @@ -569,7 +587,7 @@ static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr, int *is_linux, uint8_t image_type, uint64_t (*translate_fn)(void *, uint64_t), - void *translate_opaque) + void *translate_opaque, AddressSpace *as) { int fd; int size; @@ -670,7 +688,7 @@ static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr, hdr->ih_size = bytes; } - rom_add_blob_fixed(filename, data, hdr->ih_size, address); + rom_add_blob_fixed_as(filename, data, hdr->ih_size, address, as); ret = hdr->ih_size; @@ -686,14 +704,23 @@ int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr, void *translate_opaque) { return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL, - translate_fn, translate_opaque); + translate_fn, translate_opaque, NULL); +} + +int load_uimage_as(const char *filename, hwaddr *ep, hwaddr *loadaddr, + int *is_linux, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque, AddressSpace *as) +{ + return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL, + translate_fn, translate_opaque, as); } /* Load a ramdisk. */ int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz) { return load_uboot_image(filename, NULL, &addr, NULL, IH_TYPE_RAMDISK, - NULL, NULL); + NULL, NULL, NULL); } /* Load a gzip-compressed kernel to a dynamically allocated buffer. */ @@ -777,6 +804,7 @@ struct Rom { uint8_t *data; MemoryRegion *mr; + AddressSpace *as; int isrom; char *fw_dir; char *fw_file; @@ -788,6 +816,12 @@ struct Rom { static FWCfgState *fw_cfg; static QTAILQ_HEAD(, Rom) roms = QTAILQ_HEAD_INITIALIZER(roms); +static inline bool rom_order_compare(Rom *rom, Rom *item) +{ + return (rom->as > item->as) || + (rom->as == item->as && rom->addr >= item->addr); +} + static void rom_insert(Rom *rom) { Rom *item; @@ -796,10 +830,16 @@ static void rom_insert(Rom *rom) hw_error ("ROM images must be loaded at startup\n"); } - /* list is ordered by load address */ + /* The user didn't specify an address space, this is the default */ + if (!rom->as) { + rom->as = &address_space_memory; + } + + /* List is ordered by load address in the same address space */ QTAILQ_FOREACH(item, &roms, next) { - if (rom->addr >= item->addr) + if (rom_order_compare(rom, item)) { continue; + } QTAILQ_INSERT_BEFORE(item, rom, next); return; } @@ -833,16 +873,25 @@ static void *rom_set_mr(Rom *rom, Object *owner, const char *name) int rom_add_file(const char *file, const char *fw_dir, hwaddr addr, int32_t bootindex, - bool option_rom, MemoryRegion *mr) + bool option_rom, MemoryRegion *mr, + AddressSpace *as) { MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); Rom *rom; int rc, fd = -1; char devpath[100]; + if (as && mr) { + fprintf(stderr, "Specifying an Address Space and Memory Region is " \ + "not valid when loading a rom\n"); + /* We haven't allocated anything so we don't need any cleanup */ + return -1; + } + rom = g_malloc0(sizeof(*rom)); rom->name = g_strdup(file); rom->path = qemu_find_file(QEMU_FILE_TYPE_BIOS, rom->name); + rom->as = as; if (rom->path == NULL) { rom->path = g_strdup(file); } @@ -969,7 +1018,7 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, * memory ownership of "data", so we don't have to allocate and copy the buffer. */ int rom_add_elf_program(const char *name, void *data, size_t datasize, - size_t romsize, hwaddr addr) + size_t romsize, hwaddr addr, AddressSpace *as) { Rom *rom; @@ -979,18 +1028,19 @@ int rom_add_elf_program(const char *name, void *data, size_t datasize, rom->datasize = datasize; rom->romsize = romsize; rom->data = data; + rom->as = as; rom_insert(rom); return 0; } int rom_add_vga(const char *file) { - return rom_add_file(file, "vgaroms", 0, -1, true, NULL); + return rom_add_file(file, "vgaroms", 0, -1, true, NULL, NULL); } int rom_add_option(const char *file, int32_t bootindex) { - return rom_add_file(file, "genroms", 0, bootindex, true, NULL); + return rom_add_file(file, "genroms", 0, bootindex, true, NULL, NULL); } static void rom_reset(void *unused) @@ -1008,8 +1058,8 @@ static void rom_reset(void *unused) void *host = memory_region_get_ram_ptr(rom->mr); memcpy(host, rom->data, rom->datasize); } else { - cpu_physical_memory_write_rom(&address_space_memory, - rom->addr, rom->data, rom->datasize); + cpu_physical_memory_write_rom(rom->as, rom->addr, rom->data, + rom->datasize); } if (rom->isrom) { /* rom needs to be written only once */ @@ -1031,12 +1081,13 @@ int rom_check_and_register_reset(void) hwaddr addr = 0; MemoryRegionSection section; Rom *rom; + AddressSpace *as = NULL; QTAILQ_FOREACH(rom, &roms, next) { if (rom->fw_file) { continue; } - if (addr > rom->addr) { + if ((addr > rom->addr) && (as == rom->as)) { fprintf(stderr, "rom: requested regions overlap " "(rom %s. free=0x" TARGET_FMT_plx ", addr=0x" TARGET_FMT_plx ")\n", @@ -1045,9 +1096,11 @@ int rom_check_and_register_reset(void) } addr = rom->addr; addr += rom->romsize; - section = memory_region_find(get_system_memory(), rom->addr, 1); + section = memory_region_find(rom->mr ? rom->mr : get_system_memory(), + rom->addr, 1); rom->isrom = int128_nz(section.size) && memory_region_is_rom(section.mr); memory_region_unref(section.mr); + as = rom->as; } qemu_register_reset(rom_reset, NULL); roms_loaded = 1; diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 30829ee97b..c45c835a17 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -11,6 +11,7 @@ #include "hw/ptimer.h" #include "qemu/host-utils.h" #include "sysemu/replay.h" +#include "sysemu/qtest.h" struct ptimer_state { @@ -21,6 +22,7 @@ struct ptimer_state int64_t period; int64_t last_event; int64_t next_event; + uint8_t policy_mask; QEMUBH *bh; QEMUTimer *timer; }; @@ -43,7 +45,10 @@ static void ptimer_reload(ptimer_state *s) s->delta = s->limit; } if (s->delta == 0 || s->period == 0) { - fprintf(stderr, "Timer with period zero, disabling\n"); + if (!qtest_enabled()) { + fprintf(stderr, "Timer with period zero, disabling\n"); + } + timer_del(s->timer); s->enabled = 0; return; } @@ -161,7 +166,9 @@ void ptimer_run(ptimer_state *s, int oneshot) bool was_disabled = !s->enabled; if (was_disabled && s->period == 0) { - fprintf(stderr, "Timer with period zero, disabling\n"); + if (!qtest_enabled()) { + fprintf(stderr, "Timer with period zero, disabling\n"); + } return; } s->enabled = oneshot ? 2 : 1; @@ -242,12 +249,13 @@ const VMStateDescription vmstate_ptimer = { } }; -ptimer_state *ptimer_init(QEMUBH *bh) +ptimer_state *ptimer_init(QEMUBH *bh, uint8_t policy_mask) { ptimer_state *s; s = (ptimer_state *)g_malloc0(sizeof(ptimer_state)); s->bh = bh; s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ptimer_tick, s); + s->policy_mask = policy_mask; return s; } diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c index 6d1faf44af..e182893157 100644 --- a/hw/display/ssd0323.c +++ b/hw/display/ssd0323.c @@ -48,18 +48,18 @@ typedef struct { SSISlave ssidev; QemuConsole *con; - int cmd_len; - int cmd; - int cmd_data[8]; - int row; - int row_start; - int row_end; - int col; - int col_start; - int col_end; - int redraw; - int remap; - enum ssd0323_mode mode; + uint32_t cmd_len; + int32_t cmd; + int32_t cmd_data[8]; + int32_t row; + int32_t row_start; + int32_t row_end; + int32_t col; + int32_t col_start; + int32_t col_end; + int32_t redraw; + int32_t remap; + uint32_t mode; uint8_t framebuffer[128 * 80 / 2]; } ssd0323_state; @@ -279,83 +279,62 @@ static void ssd0323_cd(void *opaque, int n, int level) s->mode = level ? SSD0323_DATA : SSD0323_CMD; } -static void ssd0323_save(QEMUFile *f, void *opaque) +static int ssd0323_post_load(void *opaque, int version_id) { - SSISlave *ss = SSI_SLAVE(opaque); ssd0323_state *s = (ssd0323_state *)opaque; - int i; - - qemu_put_be32(f, s->cmd_len); - qemu_put_be32(f, s->cmd); - for (i = 0; i < 8; i++) - qemu_put_be32(f, s->cmd_data[i]); - qemu_put_be32(f, s->row); - qemu_put_be32(f, s->row_start); - qemu_put_be32(f, s->row_end); - qemu_put_be32(f, s->col); - qemu_put_be32(f, s->col_start); - qemu_put_be32(f, s->col_end); - qemu_put_be32(f, s->redraw); - qemu_put_be32(f, s->remap); - qemu_put_be32(f, s->mode); - qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer)); - - qemu_put_be32(f, ss->cs); -} - -static int ssd0323_load(QEMUFile *f, void *opaque, int version_id) -{ - SSISlave *ss = SSI_SLAVE(opaque); - ssd0323_state *s = (ssd0323_state *)opaque; - int i; - if (version_id != 1) - return -EINVAL; - - s->cmd_len = qemu_get_be32(f); - if (s->cmd_len < 0 || s->cmd_len > ARRAY_SIZE(s->cmd_data)) { + if (s->cmd_len > ARRAY_SIZE(s->cmd_data)) { return -EINVAL; } - s->cmd = qemu_get_be32(f); - for (i = 0; i < 8; i++) - s->cmd_data[i] = qemu_get_be32(f); - s->row = qemu_get_be32(f); if (s->row < 0 || s->row >= 80) { return -EINVAL; } - s->row_start = qemu_get_be32(f); if (s->row_start < 0 || s->row_start >= 80) { return -EINVAL; } - s->row_end = qemu_get_be32(f); if (s->row_end < 0 || s->row_end >= 80) { return -EINVAL; } - s->col = qemu_get_be32(f); if (s->col < 0 || s->col >= 64) { return -EINVAL; } - s->col_start = qemu_get_be32(f); if (s->col_start < 0 || s->col_start >= 64) { return -EINVAL; } - s->col_end = qemu_get_be32(f); if (s->col_end < 0 || s->col_end >= 64) { return -EINVAL; } - s->redraw = qemu_get_be32(f); - s->remap = qemu_get_be32(f); - s->mode = qemu_get_be32(f); if (s->mode != SSD0323_CMD && s->mode != SSD0323_DATA) { return -EINVAL; } - qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer)); - - ss->cs = qemu_get_be32(f); return 0; } +static const VMStateDescription vmstate_ssd0323 = { + .name = "ssd0323_oled", + .version_id = 2, + .minimum_version_id = 2, + .post_load = ssd0323_post_load, + .fields = (VMStateField []) { + VMSTATE_UINT32(cmd_len, ssd0323_state), + VMSTATE_INT32(cmd, ssd0323_state), + VMSTATE_INT32_ARRAY(cmd_data, ssd0323_state, 8), + VMSTATE_INT32(row, ssd0323_state), + VMSTATE_INT32(row_start, ssd0323_state), + VMSTATE_INT32(row_end, ssd0323_state), + VMSTATE_INT32(col, ssd0323_state), + VMSTATE_INT32(col_start, ssd0323_state), + VMSTATE_INT32(col_end, ssd0323_state), + VMSTATE_INT32(redraw, ssd0323_state), + VMSTATE_INT32(remap, ssd0323_state), + VMSTATE_UINT32(mode, ssd0323_state), + VMSTATE_BUFFER(framebuffer, ssd0323_state), + VMSTATE_SSI_SLAVE(ssidev, ssd0323_state), + VMSTATE_END_OF_LIST() + } +}; + static const GraphicHwOps ssd0323_ops = { .invalidate = ssd0323_invalidate_display, .gfx_update = ssd0323_update_display, @@ -372,18 +351,17 @@ static void ssd0323_realize(SSISlave *d, Error **errp) qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY); qdev_init_gpio_in(dev, ssd0323_cd, 1); - - register_savevm(dev, "ssd0323_oled", -1, 1, - ssd0323_save, ssd0323_load, s); } static void ssd0323_class_init(ObjectClass *klass, void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass); k->realize = ssd0323_realize; k->transfer = ssd0323_transfer; k->cs_polarity = SSI_CS_HIGH; + dc->vmsd = &vmstate_ssd0323; } static const TypeInfo ssd0323_info = { diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index a4753e55a2..b135a5ff12 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -548,7 +548,7 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) st->nr = i; st->bh = qemu_bh_new(timer_hit, st); - st->ptimer = ptimer_init(st->bh); + st->ptimer = ptimer_init(st->bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(st->ptimer, s->freqhz); } return; diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c index e14896e529..b81901fdfd 100644 --- a/hw/m68k/mcf5206.c +++ b/hw/m68k/mcf5206.c @@ -139,7 +139,7 @@ static m5206_timer_state *m5206_timer_init(qemu_irq irq) s = (m5206_timer_state *)g_malloc0(sizeof(m5206_timer_state)); bh = qemu_bh_new(m5206_timer_trigger, s); - s->timer = ptimer_init(bh); + s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); s->irq = irq; m5206_timer_reset(s); return s; diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c index 24155574f2..9240ebf9af 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -183,7 +183,7 @@ static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic) for (i = 0; i < 2; i++) { s = (m5208_timer_state *)g_malloc0(sizeof(m5208_timer_state)); bh = qemu_bh_new(m5208_timer_trigger, s); - s->timer = ptimer_init(bh); + s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); memory_region_init_io(&s->iomem, NULL, &m5208_timer_ops, s, "m5208-timer", 0x00004000); memory_region_add_subregion(address_space, 0xfc080000 + 0x4000 * i, diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c index c7e2c8263f..b1f3e6f6b8 100644 --- a/hw/misc/aspeed_scu.c +++ b/hw/misc/aspeed_scu.c @@ -120,6 +120,41 @@ static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = { [BMC_DEV_ID] = 0x00002402U }; +/* SCU70 bit 23: 0 24Mhz. bit 11:9: 0b001 AXI:ABH ratio 2:1 */ +/* AST2500 revision A1 */ + +static const uint32_t ast2500_a1_resets[ASPEED_SCU_NR_REGS] = { + [SYS_RST_CTRL] = 0xFFCFFEDCU, + [CLK_SEL] = 0xF3F40000U, + [CLK_STOP_CTRL] = 0x19FC3E8BU, + [D2PLL_PARAM] = 0x00026108U, + [MPLL_PARAM] = 0x00030291U, + [HPLL_PARAM] = 0x93000400U, + [MISC_CTRL1] = 0x00000010U, + [PCI_CTRL1] = 0x20001A03U, + [PCI_CTRL2] = 0x20001A03U, + [PCI_CTRL3] = 0x04000030U, + [SYS_RST_STATUS] = 0x00000001U, + [SOC_SCRATCH1] = 0x000000C0U, /* SoC completed DRAM init */ + [MISC_CTRL2] = 0x00000023U, + [RNG_CTRL] = 0x0000000EU, + [PINMUX_CTRL2] = 0x0000F000U, + [PINMUX_CTRL3] = 0x03000000U, + [PINMUX_CTRL4] = 0x00000000U, + [PINMUX_CTRL5] = 0x0000A000U, + [WDT_RST_CTRL] = 0x023FFFF3U, + [PINMUX_CTRL8] = 0xFFFF0000U, + [PINMUX_CTRL9] = 0x000FFFFFU, + [FREE_CNTR4] = 0x000000FFU, + [FREE_CNTR4_EXT] = 0x000000FFU, + [CPU2_BASE_SEG1] = 0x80000000U, + [CPU2_BASE_SEG4] = 0x1E600000U, + [CPU2_BASE_SEG5] = 0xC0000000U, + [UART_HPLL_CLK] = 0x00001903U, + [PCIE_CTRL] = 0x0000007BU, + [BMC_DEV_ID] = 0x00002402U +}; + static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size) { AspeedSCUState *s = ASPEED_SCU(opaque); @@ -198,6 +233,10 @@ static void aspeed_scu_reset(DeviceState *dev) case AST2400_A0_SILICON_REV: reset = ast2400_a0_resets; break; + case AST2500_A0_SILICON_REV: + case AST2500_A1_SILICON_REV: + reset = ast2500_a1_resets; + break; default: g_assert_not_reached(); } @@ -208,7 +247,11 @@ static void aspeed_scu_reset(DeviceState *dev) s->regs[HW_STRAP2] = s->hw_strap2; } -static uint32_t aspeed_silicon_revs[] = { AST2400_A0_SILICON_REV, }; +static uint32_t aspeed_silicon_revs[] = { + AST2400_A0_SILICON_REV, + AST2500_A0_SILICON_REV, + AST2500_A1_SILICON_REV, +}; bool is_supported_silicon_rev(uint32_t silicon_rev) { diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c index fc4217b3ce..8830dc084c 100644 --- a/hw/misc/aspeed_sdmc.c +++ b/hw/misc/aspeed_sdmc.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" +#include "qemu/error-report.h" #include "hw/misc/aspeed_sdmc.h" #include "hw/misc/aspeed_scu.h" #include "hw/qdev-properties.h" @@ -139,9 +140,9 @@ static const MemoryRegionOps aspeed_sdmc_ops = { .valid.max_access_size = 4, }; -static int ast2400_rambits(void) +static int ast2400_rambits(AspeedSDMCState *s) { - switch (ram_size >> 20) { + switch (s->ram_size >> 20) { case 64: return ASPEED_SDMC_DRAM_64MB; case 128: @@ -151,18 +152,19 @@ static int ast2400_rambits(void) case 512: return ASPEED_SDMC_DRAM_512MB; default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid RAM size: 0x" - RAM_ADDR_FMT "\n", __func__, ram_size); break; } - /* set a minimum default */ - return ASPEED_SDMC_DRAM_64MB; + /* use a common default */ + error_report("warning: Invalid RAM size 0x%" PRIx64 + ". Using default 256M", s->ram_size); + s->ram_size = 256 << 20; + return ASPEED_SDMC_DRAM_256MB; } -static int ast2500_rambits(void) +static int ast2500_rambits(AspeedSDMCState *s) { - switch (ram_size >> 20) { + switch (s->ram_size >> 20) { case 128: return ASPEED_SDMC_AST2500_128MB; case 256: @@ -172,13 +174,14 @@ static int ast2500_rambits(void) case 1024: return ASPEED_SDMC_AST2500_1024MB; default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid RAM size: 0x" - RAM_ADDR_FMT "\n", __func__, ram_size); break; } - /* set a minimum default */ - return ASPEED_SDMC_AST2500_128MB; + /* use a common default */ + error_report("warning: Invalid RAM size 0x%" PRIx64 + ". Using default 512M", s->ram_size); + s->ram_size = 512 << 20; + return ASPEED_SDMC_AST2500_512MB; } static void aspeed_sdmc_reset(DeviceState *dev) @@ -192,14 +195,15 @@ static void aspeed_sdmc_reset(DeviceState *dev) case AST2400_A0_SILICON_REV: s->regs[R_CONF] |= ASPEED_SDMC_VGA_COMPAT | - ASPEED_SDMC_DRAM_SIZE(ast2400_rambits()); + ASPEED_SDMC_DRAM_SIZE(s->ram_bits); break; case AST2500_A0_SILICON_REV: + case AST2500_A1_SILICON_REV: s->regs[R_CONF] |= ASPEED_SDMC_HW_VERSION(1) | ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB) | - ASPEED_SDMC_DRAM_SIZE(ast2500_rambits()); + ASPEED_SDMC_DRAM_SIZE(s->ram_bits); break; default: @@ -218,6 +222,18 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error **errp) return; } + switch (s->silicon_rev) { + case AST2400_A0_SILICON_REV: + s->ram_bits = ast2400_rambits(s); + break; + case AST2500_A0_SILICON_REV: + case AST2500_A1_SILICON_REV: + s->ram_bits = ast2500_rambits(s); + break; + default: + g_assert_not_reached(); + } + memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sdmc_ops, s, TYPE_ASPEED_SDMC, 0x1000); sysbus_init_mmio(sbd, &s->iomem); @@ -235,6 +251,7 @@ static const VMStateDescription vmstate_aspeed_sdmc = { static Property aspeed_sdmc_properties[] = { DEFINE_PROP_UINT32("silicon-rev", AspeedSDMCState, silicon_rev, 0), + DEFINE_PROP_UINT64("ram-size", AspeedSDMCState, ram_size, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/misc/imx25_ccm.c b/hw/misc/imx25_ccm.c index 5cd8c0a9a7..19e948a52d 100644 --- a/hw/misc/imx25_ccm.c +++ b/hw/misc/imx25_ccm.c @@ -27,7 +27,7 @@ } \ } while (0) -static char const *imx25_ccm_reg_name(uint32_t reg) +static const char *imx25_ccm_reg_name(uint32_t reg) { static char unknown[20]; diff --git a/hw/misc/imx31_ccm.c b/hw/misc/imx31_ccm.c index 1c03e52c40..b890c383be 100644 --- a/hw/misc/imx31_ccm.c +++ b/hw/misc/imx31_ccm.c @@ -29,7 +29,7 @@ } \ } while (0) -static char const *imx31_ccm_reg_name(uint32_t reg) +static const char *imx31_ccm_reg_name(uint32_t reg) { static char unknown[20]; diff --git a/hw/misc/imx6_ccm.c b/hw/misc/imx6_ccm.c index 17e15d4c92..1b421013a3 100644 --- a/hw/misc/imx6_ccm.c +++ b/hw/misc/imx6_ccm.c @@ -26,7 +26,7 @@ } \ } while (0) -static char const *imx6_ccm_reg_name(uint32_t reg) +static const char *imx6_ccm_reg_name(uint32_t reg) { static char unknown[20]; @@ -99,7 +99,7 @@ static char const *imx6_ccm_reg_name(uint32_t reg) } } -static char const *imx6_analog_reg_name(uint32_t reg) +static const char *imx6_analog_reg_name(uint32_t reg) { static char unknown[20]; diff --git a/hw/misc/imx6_src.c b/hw/misc/imx6_src.c index 8bb6829575..55b817b8d7 100644 --- a/hw/misc/imx6_src.c +++ b/hw/misc/imx6_src.c @@ -27,7 +27,7 @@ } \ } while (0) -static char const *imx6_src_reg_name(uint32_t reg) +static const char *imx6_src_reg_name(uint32_t reg) { static char unknown[20]; diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index db1b301e7f..8618e7acac 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -26,6 +26,8 @@ #include <zlib.h> /* For crc32 */ #include "hw/net/cadence_gem.h" +#include "qapi/error.h" +#include "qemu/log.h" #include "net/checksum.h" #ifdef CADENCE_GEM_ERR_DEBUG @@ -141,6 +143,61 @@ #define GEM_DESCONF6 (0x00000294/4) #define GEM_DESCONF7 (0x00000298/4) +#define GEM_INT_Q1_STATUS (0x00000400 / 4) +#define GEM_INT_Q1_MASK (0x00000640 / 4) + +#define GEM_TRANSMIT_Q1_PTR (0x00000440 / 4) +#define GEM_TRANSMIT_Q15_PTR (GEM_TRANSMIT_Q1_PTR + 14) + +#define GEM_RECEIVE_Q1_PTR (0x00000480 / 4) +#define GEM_RECEIVE_Q15_PTR (GEM_RECEIVE_Q1_PTR + 14) + +#define GEM_INT_Q1_ENABLE (0x00000600 / 4) +#define GEM_INT_Q7_ENABLE (GEM_INT_Q1_ENABLE + 6) +#define GEM_INT_Q8_ENABLE (0x00000660 / 4) +#define GEM_INT_Q15_ENABLE (GEM_INT_Q8_ENABLE + 7) + +#define GEM_INT_Q1_DISABLE (0x00000620 / 4) +#define GEM_INT_Q7_DISABLE (GEM_INT_Q1_DISABLE + 6) +#define GEM_INT_Q8_DISABLE (0x00000680 / 4) +#define GEM_INT_Q15_DISABLE (GEM_INT_Q8_DISABLE + 7) + +#define GEM_INT_Q1_MASK (0x00000640 / 4) +#define GEM_INT_Q7_MASK (GEM_INT_Q1_MASK + 6) +#define GEM_INT_Q8_MASK (0x000006A0 / 4) +#define GEM_INT_Q15_MASK (GEM_INT_Q8_MASK + 7) + +#define GEM_SCREENING_TYPE1_REGISTER_0 (0x00000500 / 4) + +#define GEM_ST1R_UDP_PORT_MATCH_ENABLE (1 << 29) +#define GEM_ST1R_DSTC_ENABLE (1 << 28) +#define GEM_ST1R_UDP_PORT_MATCH_SHIFT (12) +#define GEM_ST1R_UDP_PORT_MATCH_WIDTH (27 - GEM_ST1R_UDP_PORT_MATCH_SHIFT + 1) +#define GEM_ST1R_DSTC_MATCH_SHIFT (4) +#define GEM_ST1R_DSTC_MATCH_WIDTH (11 - GEM_ST1R_DSTC_MATCH_SHIFT + 1) +#define GEM_ST1R_QUEUE_SHIFT (0) +#define GEM_ST1R_QUEUE_WIDTH (3 - GEM_ST1R_QUEUE_SHIFT + 1) + +#define GEM_SCREENING_TYPE2_REGISTER_0 (0x00000540 / 4) + +#define GEM_ST2R_COMPARE_A_ENABLE (1 << 18) +#define GEM_ST2R_COMPARE_A_SHIFT (13) +#define GEM_ST2R_COMPARE_WIDTH (17 - GEM_ST2R_COMPARE_A_SHIFT + 1) +#define GEM_ST2R_ETHERTYPE_ENABLE (1 << 12) +#define GEM_ST2R_ETHERTYPE_INDEX_SHIFT (9) +#define GEM_ST2R_ETHERTYPE_INDEX_WIDTH (11 - GEM_ST2R_ETHERTYPE_INDEX_SHIFT \ + + 1) +#define GEM_ST2R_QUEUE_SHIFT (0) +#define GEM_ST2R_QUEUE_WIDTH (3 - GEM_ST2R_QUEUE_SHIFT + 1) + +#define GEM_SCREENING_TYPE2_ETHERTYPE_REG_0 (0x000006e0 / 4) +#define GEM_TYPE2_COMPARE_0_WORD_0 (0x00000700 / 4) + +#define GEM_T2CW1_COMPARE_OFFSET_SHIFT (7) +#define GEM_T2CW1_COMPARE_OFFSET_WIDTH (8 - GEM_T2CW1_COMPARE_OFFSET_SHIFT + 1) +#define GEM_T2CW1_OFFSET_VALUE_SHIFT (0) +#define GEM_T2CW1_OFFSET_VALUE_WIDTH (6 - GEM_T2CW1_OFFSET_VALUE_SHIFT + 1) + /*****************************************/ #define GEM_NWCTRL_TXSTART 0x00000200 /* Transmit Enable */ #define GEM_NWCTRL_TXENA 0x00000008 /* Transmit Enable */ @@ -284,9 +341,9 @@ static inline unsigned tx_desc_get_length(unsigned *desc) return desc[1] & DESC_1_LENGTH; } -static inline void print_gem_tx_desc(unsigned *desc) +static inline void print_gem_tx_desc(unsigned *desc, uint8_t queue) { - DB_PRINT("TXDESC:\n"); + DB_PRINT("TXDESC (queue %" PRId8 "):\n", queue); DB_PRINT("bufaddr: 0x%08x\n", *desc); DB_PRINT("used_hw: %d\n", tx_desc_get_used(desc)); DB_PRINT("wrap: %d\n", tx_desc_get_wrap(desc)); @@ -416,6 +473,7 @@ static void phy_update_link(CadenceGEMState *s) static int gem_can_receive(NetClientState *nc) { CadenceGEMState *s; + int i; s = qemu_get_nic_opaque(nc); @@ -428,18 +486,20 @@ static int gem_can_receive(NetClientState *nc) return 0; } - if (rx_desc_get_ownership(s->rx_desc) == 1) { - if (s->can_rx_state != 2) { - s->can_rx_state = 2; - DB_PRINT("can't receive - busy buffer descriptor 0x%x\n", - s->rx_desc_addr); + for (i = 0; i < s->num_priority_queues; i++) { + if (rx_desc_get_ownership(s->rx_desc[i]) == 1) { + if (s->can_rx_state != 2) { + s->can_rx_state = 2; + DB_PRINT("can't receive - busy buffer descriptor (q%d) 0x%x\n", + i, s->rx_desc_addr[i]); + } + return 0; } - return 0; } if (s->can_rx_state != 0) { s->can_rx_state = 0; - DB_PRINT("can receive 0x%x\n", s->rx_desc_addr); + DB_PRINT("can receive\n"); } return 1; } @@ -450,9 +510,20 @@ static int gem_can_receive(NetClientState *nc) */ static void gem_update_int_status(CadenceGEMState *s) { - if (s->regs[GEM_ISR]) { - DB_PRINT("asserting int. (0x%08x)\n", s->regs[GEM_ISR]); - qemu_set_irq(s->irq, 1); + int i; + + if ((s->num_priority_queues == 1) && s->regs[GEM_ISR]) { + /* No priority queues, just trigger the interrupt */ + DB_PRINT("asserting int.\n", i); + qemu_set_irq(s->irq[0], 1); + return; + } + + for (i = 0; i < s->num_priority_queues; ++i) { + if (s->regs[GEM_INT_Q1_STATUS + i]) { + DB_PRINT("asserting int. (q=%d)\n", i); + qemu_set_irq(s->irq[i], 1); + } } } @@ -601,17 +672,137 @@ static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet) return GEM_RX_REJECT; } -static void gem_get_rx_desc(CadenceGEMState *s) +/* Figure out which queue the received data should be sent to */ +static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr, + unsigned rxbufsize) +{ + uint32_t reg; + bool matched, mismatched; + int i, j; + + for (i = 0; i < s->num_type1_screeners; i++) { + reg = s->regs[GEM_SCREENING_TYPE1_REGISTER_0 + i]; + matched = false; + mismatched = false; + + /* Screening is based on UDP Port */ + if (reg & GEM_ST1R_UDP_PORT_MATCH_ENABLE) { + uint16_t udp_port = rxbuf_ptr[14 + 22] << 8 | rxbuf_ptr[14 + 23]; + if (udp_port == extract32(reg, GEM_ST1R_UDP_PORT_MATCH_SHIFT, + GEM_ST1R_UDP_PORT_MATCH_WIDTH)) { + matched = true; + } else { + mismatched = true; + } + } + + /* Screening is based on DS/TC */ + if (reg & GEM_ST1R_DSTC_ENABLE) { + uint8_t dscp = rxbuf_ptr[14 + 1]; + if (dscp == extract32(reg, GEM_ST1R_DSTC_MATCH_SHIFT, + GEM_ST1R_DSTC_MATCH_WIDTH)) { + matched = true; + } else { + mismatched = true; + } + } + + if (matched && !mismatched) { + return extract32(reg, GEM_ST1R_QUEUE_SHIFT, GEM_ST1R_QUEUE_WIDTH); + } + } + + for (i = 0; i < s->num_type2_screeners; i++) { + reg = s->regs[GEM_SCREENING_TYPE2_REGISTER_0 + i]; + matched = false; + mismatched = false; + + if (reg & GEM_ST2R_ETHERTYPE_ENABLE) { + uint16_t type = rxbuf_ptr[12] << 8 | rxbuf_ptr[13]; + int et_idx = extract32(reg, GEM_ST2R_ETHERTYPE_INDEX_SHIFT, + GEM_ST2R_ETHERTYPE_INDEX_WIDTH); + + if (et_idx > s->num_type2_screeners) { + qemu_log_mask(LOG_GUEST_ERROR, "Out of range ethertype " + "register index: %d\n", et_idx); + } + if (type == s->regs[GEM_SCREENING_TYPE2_ETHERTYPE_REG_0 + + et_idx]) { + matched = true; + } else { + mismatched = true; + } + } + + /* Compare A, B, C */ + for (j = 0; j < 3; j++) { + uint32_t cr0, cr1, mask; + uint16_t rx_cmp; + int offset; + int cr_idx = extract32(reg, GEM_ST2R_COMPARE_A_SHIFT + j * 6, + GEM_ST2R_COMPARE_WIDTH); + + if (!(reg & (GEM_ST2R_COMPARE_A_ENABLE << (j * 6)))) { + continue; + } + if (cr_idx > s->num_type2_screeners) { + qemu_log_mask(LOG_GUEST_ERROR, "Out of range compare " + "register index: %d\n", cr_idx); + } + + cr0 = s->regs[GEM_TYPE2_COMPARE_0_WORD_0 + cr_idx * 2]; + cr1 = s->regs[GEM_TYPE2_COMPARE_0_WORD_0 + cr_idx * 2 + 1]; + offset = extract32(cr1, GEM_T2CW1_OFFSET_VALUE_SHIFT, + GEM_T2CW1_OFFSET_VALUE_WIDTH); + + switch (extract32(cr1, GEM_T2CW1_COMPARE_OFFSET_SHIFT, + GEM_T2CW1_COMPARE_OFFSET_WIDTH)) { + case 3: /* Skip UDP header */ + qemu_log_mask(LOG_UNIMP, "TCP compare offsets" + "unimplemented - assuming UDP\n"); + offset += 8; + /* Fallthrough */ + case 2: /* skip the IP header */ + offset += 20; + /* Fallthrough */ + case 1: /* Count from after the ethertype */ + offset += 14; + break; + case 0: + /* Offset from start of frame */ + break; + } + + rx_cmp = rxbuf_ptr[offset] << 8 | rxbuf_ptr[offset]; + mask = extract32(cr0, 0, 16); + + if ((rx_cmp & mask) == (extract32(cr0, 16, 16) & mask)) { + matched = true; + } else { + mismatched = true; + } + } + + if (matched && !mismatched) { + return extract32(reg, GEM_ST2R_QUEUE_SHIFT, GEM_ST2R_QUEUE_WIDTH); + } + } + + /* We made it here, assume it's queue 0 */ + return 0; +} + +static void gem_get_rx_desc(CadenceGEMState *s, int q) { - DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr); + DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[q]); /* read current descriptor */ - cpu_physical_memory_read(s->rx_desc_addr, - (uint8_t *)s->rx_desc, sizeof(s->rx_desc)); + cpu_physical_memory_read(s->rx_desc_addr[0], + (uint8_t *)s->rx_desc[0], sizeof(s->rx_desc[0])); /* Descriptor owned by software ? */ - if (rx_desc_get_ownership(s->rx_desc) == 1) { + if (rx_desc_get_ownership(s->rx_desc[q]) == 1) { DB_PRINT("descriptor 0x%x owned by sw.\n", - (unsigned)s->rx_desc_addr); + (unsigned)s->rx_desc_addr[q]); s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF; s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]); /* Handle interrupt consequences */ @@ -632,6 +823,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) uint8_t *rxbuf_ptr; bool first_desc = true; int maf; + int q = 0; s = qemu_get_nic_opaque(nc); @@ -710,6 +902,9 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size); + /* Find which queue we are targetting */ + q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize); + while (bytes_to_copy) { /* Do nothing if receive is not enabled. */ if (!gem_can_receive(nc)) { @@ -718,56 +913,59 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) } DB_PRINT("copy %d bytes to 0x%x\n", MIN(bytes_to_copy, rxbufsize), - rx_desc_get_buffer(s->rx_desc)); + rx_desc_get_buffer(s->rx_desc[q])); /* Copy packet data to emulated DMA buffer */ - cpu_physical_memory_write(rx_desc_get_buffer(s->rx_desc) + rxbuf_offset, + cpu_physical_memory_write(rx_desc_get_buffer(s->rx_desc[q]) + + rxbuf_offset, rxbuf_ptr, MIN(bytes_to_copy, rxbufsize)); rxbuf_ptr += MIN(bytes_to_copy, rxbufsize); bytes_to_copy -= MIN(bytes_to_copy, rxbufsize); /* Update the descriptor. */ if (first_desc) { - rx_desc_set_sof(s->rx_desc); + rx_desc_set_sof(s->rx_desc[q]); first_desc = false; } if (bytes_to_copy == 0) { - rx_desc_set_eof(s->rx_desc); - rx_desc_set_length(s->rx_desc, size); + rx_desc_set_eof(s->rx_desc[q]); + rx_desc_set_length(s->rx_desc[q], size); } - rx_desc_set_ownership(s->rx_desc); + rx_desc_set_ownership(s->rx_desc[q]); switch (maf) { case GEM_RX_PROMISCUOUS_ACCEPT: break; case GEM_RX_BROADCAST_ACCEPT: - rx_desc_set_broadcast(s->rx_desc); + rx_desc_set_broadcast(s->rx_desc[q]); break; case GEM_RX_UNICAST_HASH_ACCEPT: - rx_desc_set_unicast_hash(s->rx_desc); + rx_desc_set_unicast_hash(s->rx_desc[q]); break; case GEM_RX_MULTICAST_HASH_ACCEPT: - rx_desc_set_multicast_hash(s->rx_desc); + rx_desc_set_multicast_hash(s->rx_desc[q]); break; case GEM_RX_REJECT: abort(); default: /* SAR */ - rx_desc_set_sar(s->rx_desc, maf); + rx_desc_set_sar(s->rx_desc[q], maf); } /* Descriptor write-back. */ - cpu_physical_memory_write(s->rx_desc_addr, - (uint8_t *)s->rx_desc, sizeof(s->rx_desc)); + cpu_physical_memory_write(s->rx_desc_addr[q], + (uint8_t *)s->rx_desc[q], + sizeof(s->rx_desc[q])); /* Next descriptor */ - if (rx_desc_get_wrap(s->rx_desc)) { + if (rx_desc_get_wrap(s->rx_desc[q])) { DB_PRINT("wrapping RX descriptor list\n"); - s->rx_desc_addr = s->regs[GEM_RXQBASE]; + s->rx_desc_addr[q] = s->regs[GEM_RXQBASE]; } else { DB_PRINT("incrementing RX descriptor list\n"); - s->rx_desc_addr += 8; + s->rx_desc_addr[q] += 8; } - gem_get_rx_desc(s); + + gem_get_rx_desc(s, q); } /* Count it */ @@ -839,6 +1037,7 @@ static void gem_transmit(CadenceGEMState *s) uint8_t tx_packet[2048]; uint8_t *p; unsigned total_bytes; + int q = 0; /* Do nothing if transmit is not enabled. */ if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) { @@ -854,110 +1053,123 @@ static void gem_transmit(CadenceGEMState *s) p = tx_packet; total_bytes = 0; - /* read current descriptor */ - packet_desc_addr = s->tx_desc_addr; - - DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); - cpu_physical_memory_read(packet_desc_addr, - (uint8_t *)desc, sizeof(desc)); - /* Handle all descriptors owned by hardware */ - while (tx_desc_get_used(desc) == 0) { + for (q = s->num_priority_queues - 1; q >= 0; q--) { + /* read current descriptor */ + packet_desc_addr = s->tx_desc_addr[q]; - /* Do nothing if transmit is not enabled. */ - if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) { - return; - } - print_gem_tx_desc(desc); - - /* The real hardware would eat this (and possibly crash). - * For QEMU let's lend a helping hand. - */ - if ((tx_desc_get_buffer(desc) == 0) || - (tx_desc_get_length(desc) == 0)) { - DB_PRINT("Invalid TX descriptor @ 0x%x\n", - (unsigned)packet_desc_addr); - break; - } - - if (tx_desc_get_length(desc) > sizeof(tx_packet) - (p - tx_packet)) { - DB_PRINT("TX descriptor @ 0x%x too large: size 0x%x space 0x%x\n", - (unsigned)packet_desc_addr, - (unsigned)tx_desc_get_length(desc), - sizeof(tx_packet) - (p - tx_packet)); - break; - } - - /* Gather this fragment of the packet from "dma memory" to our contig. - * buffer. - */ - cpu_physical_memory_read(tx_desc_get_buffer(desc), p, - tx_desc_get_length(desc)); - p += tx_desc_get_length(desc); - total_bytes += tx_desc_get_length(desc); + DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); + cpu_physical_memory_read(packet_desc_addr, + (uint8_t *)desc, sizeof(desc)); + /* Handle all descriptors owned by hardware */ + while (tx_desc_get_used(desc) == 0) { - /* Last descriptor for this packet; hand the whole thing off */ - if (tx_desc_get_last(desc)) { - unsigned desc_first[2]; + /* Do nothing if transmit is not enabled. */ + if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) { + return; + } + print_gem_tx_desc(desc, q); - /* Modify the 1st descriptor of this packet to be owned by - * the processor. + /* The real hardware would eat this (and possibly crash). + * For QEMU let's lend a helping hand. */ - cpu_physical_memory_read(s->tx_desc_addr, (uint8_t *)desc_first, - sizeof(desc_first)); - tx_desc_set_used(desc_first); - cpu_physical_memory_write(s->tx_desc_addr, (uint8_t *)desc_first, - sizeof(desc_first)); - /* Advance the hardware current descriptor past this packet */ - if (tx_desc_get_wrap(desc)) { - s->tx_desc_addr = s->regs[GEM_TXQBASE]; - } else { - s->tx_desc_addr = packet_desc_addr + 8; + if ((tx_desc_get_buffer(desc) == 0) || + (tx_desc_get_length(desc) == 0)) { + DB_PRINT("Invalid TX descriptor @ 0x%x\n", + (unsigned)packet_desc_addr); + break; } - DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr); - - s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL; - s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]); - - /* Handle interrupt consequences */ - gem_update_int_status(s); - /* Is checksum offload enabled? */ - if (s->regs[GEM_DMACFG] & GEM_DMACFG_TXCSUM_OFFL) { - net_checksum_calculate(tx_packet, total_bytes); + if (tx_desc_get_length(desc) > sizeof(tx_packet) - + (p - tx_packet)) { + DB_PRINT("TX descriptor @ 0x%x too large: size 0x%x space " \ + "0x%x\n", (unsigned)packet_desc_addr, + (unsigned)tx_desc_get_length(desc), + sizeof(tx_packet) - (p - tx_packet)); + break; } - /* Update MAC statistics */ - gem_transmit_updatestats(s, tx_packet, total_bytes); + /* Gather this fragment of the packet from "dma memory" to our + * contig buffer. + */ + cpu_physical_memory_read(tx_desc_get_buffer(desc), p, + tx_desc_get_length(desc)); + p += tx_desc_get_length(desc); + total_bytes += tx_desc_get_length(desc); + + /* Last descriptor for this packet; hand the whole thing off */ + if (tx_desc_get_last(desc)) { + unsigned desc_first[2]; + + /* Modify the 1st descriptor of this packet to be owned by + * the processor. + */ + cpu_physical_memory_read(s->tx_desc_addr[q], + (uint8_t *)desc_first, + sizeof(desc_first)); + tx_desc_set_used(desc_first); + cpu_physical_memory_write(s->tx_desc_addr[q], + (uint8_t *)desc_first, + sizeof(desc_first)); + /* Advance the hardware current descriptor past this packet */ + if (tx_desc_get_wrap(desc)) { + s->tx_desc_addr[q] = s->regs[GEM_TXQBASE]; + } else { + s->tx_desc_addr[q] = packet_desc_addr + 8; + } + DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr[q]); + + s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL; + s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]); + + /* Update queue interrupt status */ + if (s->num_priority_queues > 1) { + s->regs[GEM_INT_Q1_STATUS + q] |= + GEM_INT_TXCMPL & ~(s->regs[GEM_INT_Q1_MASK + q]); + } + + /* Handle interrupt consequences */ + gem_update_int_status(s); + + /* Is checksum offload enabled? */ + if (s->regs[GEM_DMACFG] & GEM_DMACFG_TXCSUM_OFFL) { + net_checksum_calculate(tx_packet, total_bytes); + } + + /* Update MAC statistics */ + gem_transmit_updatestats(s, tx_packet, total_bytes); + + /* Send the packet somewhere */ + if (s->phy_loop || (s->regs[GEM_NWCTRL] & + GEM_NWCTRL_LOCALLOOP)) { + gem_receive(qemu_get_queue(s->nic), tx_packet, + total_bytes); + } else { + qemu_send_packet(qemu_get_queue(s->nic), tx_packet, + total_bytes); + } + + /* Prepare for next packet */ + p = tx_packet; + total_bytes = 0; + } - /* Send the packet somewhere */ - if (s->phy_loop || (s->regs[GEM_NWCTRL] & GEM_NWCTRL_LOCALLOOP)) { - gem_receive(qemu_get_queue(s->nic), tx_packet, total_bytes); + /* read next descriptor */ + if (tx_desc_get_wrap(desc)) { + tx_desc_set_last(desc); + packet_desc_addr = s->regs[GEM_TXQBASE]; } else { - qemu_send_packet(qemu_get_queue(s->nic), tx_packet, - total_bytes); + packet_desc_addr += 8; } - - /* Prepare for next packet */ - p = tx_packet; - total_bytes = 0; + DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); + cpu_physical_memory_read(packet_desc_addr, + (uint8_t *)desc, sizeof(desc)); } - /* read next descriptor */ - if (tx_desc_get_wrap(desc)) { - tx_desc_set_last(desc); - packet_desc_addr = s->regs[GEM_TXQBASE]; - } else { - packet_desc_addr += 8; + if (tx_desc_get_used(desc)) { + s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_USED; + s->regs[GEM_ISR] |= GEM_INT_TXUSED & ~(s->regs[GEM_IMR]); + gem_update_int_status(s); } - DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); - cpu_physical_memory_read(packet_desc_addr, - (uint8_t *)desc, sizeof(desc)); - } - - if (tx_desc_get_used(desc)) { - s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_USED; - s->regs[GEM_ISR] |= GEM_INT_TXUSED & ~(s->regs[GEM_IMR]); - gem_update_int_status(s); } } @@ -1065,7 +1277,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size) { CadenceGEMState *s; uint32_t retval; - + int i; s = (CadenceGEMState *)opaque; offset >>= 2; @@ -1075,8 +1287,10 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size) switch (offset) { case GEM_ISR: - DB_PRINT("lowering irq on ISR read\n"); - qemu_set_irq(s->irq, 0); + DB_PRINT("lowering irqs on ISR read\n"); + for (i = 0; i < s->num_priority_queues; ++i) { + qemu_set_irq(s->irq[i], 0); + } break; case GEM_PHYMNTNC: if (retval & GEM_PHYMNTNC_OP_R) { @@ -1101,6 +1315,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size) retval &= ~(s->regs_wo[offset]); DB_PRINT("0x%08x\n", retval); + gem_update_int_status(s); return retval; } @@ -1113,6 +1328,7 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, { CadenceGEMState *s = (CadenceGEMState *)opaque; uint32_t readonly; + int i; DB_PRINT("offset: 0x%04x write: 0x%08x ", (unsigned)offset, (unsigned)val); offset >>= 2; @@ -1132,14 +1348,18 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, switch (offset) { case GEM_NWCTRL: if (val & GEM_NWCTRL_RXENA) { - gem_get_rx_desc(s); + for (i = 0; i < s->num_priority_queues; ++i) { + gem_get_rx_desc(s, i); + } } if (val & GEM_NWCTRL_TXSTART) { gem_transmit(s); } if (!(val & GEM_NWCTRL_TXENA)) { /* Reset to start of Q when transmit disabled. */ - s->tx_desc_addr = s->regs[GEM_TXQBASE]; + for (i = 0; i < s->num_priority_queues; i++) { + s->tx_desc_addr[i] = s->regs[GEM_TXQBASE]; + } } if (gem_can_receive(qemu_get_queue(s->nic))) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); @@ -1150,10 +1370,16 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, gem_update_int_status(s); break; case GEM_RXQBASE: - s->rx_desc_addr = val; + s->rx_desc_addr[0] = val; + break; + case GEM_RECEIVE_Q1_PTR ... GEM_RECEIVE_Q15_PTR: + s->rx_desc_addr[offset - GEM_RECEIVE_Q1_PTR + 1] = val; break; case GEM_TXQBASE: - s->tx_desc_addr = val; + s->tx_desc_addr[0] = val; + break; + case GEM_TRANSMIT_Q1_PTR ... GEM_TRANSMIT_Q15_PTR: + s->tx_desc_addr[offset - GEM_TRANSMIT_Q1_PTR + 1] = val; break; case GEM_RXSTATUS: gem_update_int_status(s); @@ -1162,10 +1388,26 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, s->regs[GEM_IMR] &= ~val; gem_update_int_status(s); break; + case GEM_INT_Q1_ENABLE ... GEM_INT_Q7_ENABLE: + s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_ENABLE] &= ~val; + gem_update_int_status(s); + break; + case GEM_INT_Q8_ENABLE ... GEM_INT_Q15_ENABLE: + s->regs[GEM_INT_Q8_MASK + offset - GEM_INT_Q8_ENABLE] &= ~val; + gem_update_int_status(s); + break; case GEM_IDR: s->regs[GEM_IMR] |= val; gem_update_int_status(s); break; + case GEM_INT_Q1_DISABLE ... GEM_INT_Q7_DISABLE: + s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_DISABLE] |= val; + gem_update_int_status(s); + break; + case GEM_INT_Q8_DISABLE ... GEM_INT_Q15_DISABLE: + s->regs[GEM_INT_Q8_MASK + offset - GEM_INT_Q8_DISABLE] |= val; + gem_update_int_status(s); + break; case GEM_SPADDR1LO: case GEM_SPADDR2LO: case GEM_SPADDR3LO: @@ -1202,8 +1444,11 @@ static const MemoryRegionOps gem_ops = { static void gem_set_link(NetClientState *nc) { + CadenceGEMState *s = qemu_get_nic_opaque(nc); + DB_PRINT("\n"); - phy_update_link(qemu_get_nic_opaque(nc)); + phy_update_link(s); + gem_update_int_status(s); } static NetClientInfo net_gem_info = { @@ -1214,36 +1459,62 @@ static NetClientInfo net_gem_info = { .link_status_changed = gem_set_link, }; -static int gem_init(SysBusDevice *sbd) +static void gem_realize(DeviceState *dev, Error **errp) { - DeviceState *dev = DEVICE(sbd); CadenceGEMState *s = CADENCE_GEM(dev); + int i; + + if (s->num_priority_queues == 0 || + s->num_priority_queues > MAX_PRIORITY_QUEUES) { + error_setg(errp, "Invalid num-priority-queues value: %" PRIx8, + s->num_priority_queues); + return; + } else if (s->num_type1_screeners > MAX_TYPE1_SCREENERS) { + error_setg(errp, "Invalid num-type1-screeners value: %" PRIx8, + s->num_type1_screeners); + return; + } else if (s->num_type2_screeners > MAX_TYPE2_SCREENERS) { + error_setg(errp, "Invalid num-type2-screeners value: %" PRIx8, + s->num_type2_screeners); + return; + } + + for (i = 0; i < s->num_priority_queues; ++i) { + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]); + } + + qemu_macaddr_default_if_unset(&s->conf.macaddr); + + s->nic = qemu_new_nic(&net_gem_info, &s->conf, + object_get_typename(OBJECT(dev)), dev->id, s); +} + +static void gem_init(Object *obj) +{ + CadenceGEMState *s = CADENCE_GEM(obj); + DeviceState *dev = DEVICE(obj); DB_PRINT("\n"); gem_init_register_masks(s); memory_region_init_io(&s->iomem, OBJECT(s), &gem_ops, s, "enet", sizeof(s->regs)); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq); - qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->nic = qemu_new_nic(&net_gem_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->id, s); - - return 0; + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); } static const VMStateDescription vmstate_cadence_gem = { .name = "cadence_gem", - .version_id = 2, - .minimum_version_id = 2, + .version_id = 4, + .minimum_version_id = 4, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, CadenceGEMState, CADENCE_GEM_MAXREG), VMSTATE_UINT16_ARRAY(phy_regs, CadenceGEMState, 32), VMSTATE_UINT8(phy_loop, CadenceGEMState), - VMSTATE_UINT32(rx_desc_addr, CadenceGEMState), - VMSTATE_UINT32(tx_desc_addr, CadenceGEMState), + VMSTATE_UINT32_ARRAY(rx_desc_addr, CadenceGEMState, + MAX_PRIORITY_QUEUES), + VMSTATE_UINT32_ARRAY(tx_desc_addr, CadenceGEMState, + MAX_PRIORITY_QUEUES), VMSTATE_BOOL_ARRAY(sar_active, CadenceGEMState, 4), VMSTATE_END_OF_LIST(), } @@ -1251,15 +1522,20 @@ static const VMStateDescription vmstate_cadence_gem = { static Property gem_properties[] = { DEFINE_NIC_PROPERTIES(CadenceGEMState, conf), + DEFINE_PROP_UINT8("num-priority-queues", CadenceGEMState, + num_priority_queues, 1), + DEFINE_PROP_UINT8("num-type1-screeners", CadenceGEMState, + num_type1_screeners, 4), + DEFINE_PROP_UINT8("num-type2-screeners", CadenceGEMState, + num_type2_screeners, 4), DEFINE_PROP_END_OF_LIST(), }; static void gem_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - sdc->init = gem_init; + dc->realize = gem_realize; dc->props = gem_properties; dc->vmsd = &vmstate_cadence_gem; dc->reset = gem_reset; @@ -1269,6 +1545,7 @@ static const TypeInfo gem_info = { .name = TYPE_CADENCE_GEM, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(CadenceGEMState), + .instance_init = gem_init, .class_init = gem_class_init, }; diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index b5c777fbf6..951c5f0038 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -387,7 +387,7 @@ static void etsec_realize(DeviceState *dev, Error **errp) etsec->bh = qemu_bh_new(etsec_timer_hit, etsec); - etsec->ptimer = ptimer_init(etsec->bh); + etsec->ptimer = ptimer_init(etsec->bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(etsec->ptimer, 100); } diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index 4615d873b1..3db8937cac 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -1345,7 +1345,7 @@ static int lan9118_init1(SysBusDevice *sbd) s->txp = &s->tx_packet; bh = qemu_bh_new(lan9118_tick, s); - s->timer = ptimer_init(bh); + s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(s->timer, 10000); ptimer_set_limit(s->timer, 0xffff, 1); diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 3ff0886dd5..24001dc3e6 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -31,7 +31,7 @@ do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__);} while (0) #endif typedef enum { - SSI_SD_CMD, + SSI_SD_CMD = 0, SSI_SD_CMDARG, SSI_SD_RESPONSE, SSI_SD_DATA_START, @@ -40,13 +40,13 @@ typedef enum { typedef struct { SSISlave ssidev; - ssi_sd_mode mode; + uint32_t mode; int cmd; uint8_t cmdarg[4]; uint8_t response[5]; - int arglen; - int response_pos; - int stopping; + int32_t arglen; + int32_t response_pos; + int32_t stopping; SDState *sd; } ssi_sd_state; @@ -198,61 +198,46 @@ static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val) return 0xff; } -static void ssi_sd_save(QEMUFile *f, void *opaque) +static int ssi_sd_post_load(void *opaque, int version_id) { - SSISlave *ss = SSI_SLAVE(opaque); ssi_sd_state *s = (ssi_sd_state *)opaque; - int i; - qemu_put_be32(f, s->mode); - qemu_put_be32(f, s->cmd); - for (i = 0; i < 4; i++) - qemu_put_be32(f, s->cmdarg[i]); - for (i = 0; i < 5; i++) - qemu_put_be32(f, s->response[i]); - qemu_put_be32(f, s->arglen); - qemu_put_be32(f, s->response_pos); - qemu_put_be32(f, s->stopping); - - qemu_put_be32(f, ss->cs); -} - -static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) -{ - SSISlave *ss = SSI_SLAVE(opaque); - ssi_sd_state *s = (ssi_sd_state *)opaque; - int i; - - if (version_id != 1) + if (s->mode > SSI_SD_DATA_READ) { return -EINVAL; - - s->mode = qemu_get_be32(f); - s->cmd = qemu_get_be32(f); - for (i = 0; i < 4; i++) - s->cmdarg[i] = qemu_get_be32(f); - for (i = 0; i < 5; i++) - s->response[i] = qemu_get_be32(f); - s->arglen = qemu_get_be32(f); + } if (s->mode == SSI_SD_CMDARG && (s->arglen < 0 || s->arglen >= ARRAY_SIZE(s->cmdarg))) { return -EINVAL; } - s->response_pos = qemu_get_be32(f); - s->stopping = qemu_get_be32(f); if (s->mode == SSI_SD_RESPONSE && (s->response_pos < 0 || s->response_pos >= ARRAY_SIZE(s->response) || (!s->stopping && s->arglen > ARRAY_SIZE(s->response)))) { return -EINVAL; } - ss->cs = qemu_get_be32(f); - return 0; } +static const VMStateDescription vmstate_ssi_sd = { + .name = "ssi_sd", + .version_id = 2, + .minimum_version_id = 2, + .post_load = ssi_sd_post_load, + .fields = (VMStateField []) { + VMSTATE_UINT32(mode, ssi_sd_state), + VMSTATE_INT32(cmd, ssi_sd_state), + VMSTATE_UINT8_ARRAY(cmdarg, ssi_sd_state, 4), + VMSTATE_UINT8_ARRAY(response, ssi_sd_state, 5), + VMSTATE_INT32(arglen, ssi_sd_state), + VMSTATE_INT32(response_pos, ssi_sd_state), + VMSTATE_INT32(stopping, ssi_sd_state), + VMSTATE_SSI_SLAVE(ssidev, ssi_sd_state), + VMSTATE_END_OF_LIST() + } +}; + static void ssi_sd_realize(SSISlave *d, Error **errp) { - DeviceState *dev = DEVICE(d); ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d); DriveInfo *dinfo; @@ -264,16 +249,17 @@ static void ssi_sd_realize(SSISlave *d, Error **errp) error_setg(errp, "Device initialization failed."); return; } - register_savevm(dev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s); } static void ssi_sd_class_init(ObjectClass *klass, void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass); k->realize = ssi_sd_realize; k->transfer = ssi_sd_transfer; k->cs_polarity = SSI_CS_LOW; + dc->vmsd = &vmstate_ssi_sd; } static const TypeInfo ssi_sd_info = { diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c index 4226199811..e4e395fa67 100644 --- a/hw/ssi/imx_spi.c +++ b/hw/ssi/imx_spi.c @@ -25,7 +25,7 @@ } \ } while (0) -static char const *imx_spi_reg_name(uint32_t reg) +static const char *imx_spi_reg_name(uint32_t reg) { static char unknown[20]; diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c index 3385e5dc35..22ceabe1d4 100644 --- a/hw/timer/allwinner-a10-pit.c +++ b/hw/timer/allwinner-a10-pit.c @@ -267,7 +267,7 @@ static void a10_pit_init(Object *obj) tc->container = s; tc->index = i; bh[i] = qemu_bh_new(a10_pit_timer_cb, tc); - s->timer[i] = ptimer_init(bh[i]); + s->timer[i] = ptimer_init(bh[i], PTIMER_POLICY_DEFAULT); } } diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c index 111a16db37..98fddd7ac1 100644 --- a/hw/timer/arm_timer.c +++ b/hw/timer/arm_timer.c @@ -171,7 +171,7 @@ static arm_timer_state *arm_timer_init(uint32_t freq) s->control = TIMER_CTRL_IE; bh = qemu_bh_new(arm_timer_tick, s); - s->timer = ptimer_init(bh); + s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); vmstate_register(NULL, -1, &vmstate_arm_timer, s); return s; } diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c index 0f21faf876..e1fcf73c3e 100644 --- a/hw/timer/digic-timer.c +++ b/hw/timer/digic-timer.c @@ -127,7 +127,7 @@ static void digic_timer_init(Object *obj) { DigicTimerState *s = DIGIC_TIMER(obj); - s->ptimer = ptimer_init(NULL); + s->ptimer = ptimer_init(NULL, PTIMER_POLICY_DEFAULT); /* * FIXME: there is no documentation on Digic timer diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c index 36d8f462c4..8e18236c5a 100644 --- a/hw/timer/etraxfs_timer.c +++ b/hw/timer/etraxfs_timer.c @@ -322,9 +322,9 @@ static int etraxfs_timer_init(SysBusDevice *dev) t->bh_t0 = qemu_bh_new(timer0_hit, t); t->bh_t1 = qemu_bh_new(timer1_hit, t); t->bh_wd = qemu_bh_new(watchdog_hit, t); - t->ptimer_t0 = ptimer_init(t->bh_t0); - t->ptimer_t1 = ptimer_init(t->bh_t1); - t->ptimer_wd = ptimer_init(t->bh_wd); + t->ptimer_t0 = ptimer_init(t->bh_t0, PTIMER_POLICY_DEFAULT); + t->ptimer_t1 = ptimer_init(t->bh_t1, PTIMER_POLICY_DEFAULT); + t->ptimer_wd = ptimer_init(t->bh_wd, PTIMER_POLICY_DEFAULT); sysbus_init_irq(dev, &t->irq); sysbus_init_irq(dev, &t->nmi); diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index ae69345f0d..0c189348ae 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -1431,15 +1431,16 @@ static void exynos4210_mct_init(Object *obj) /* Global timer */ bh[0] = qemu_bh_new(exynos4210_gfrc_event, s); - s->g_timer.ptimer_frc = ptimer_init(bh[0]); + s->g_timer.ptimer_frc = ptimer_init(bh[0], PTIMER_POLICY_DEFAULT); memset(&s->g_timer.reg, 0, sizeof(struct gregs)); /* Local timers */ for (i = 0; i < 2; i++) { bh[0] = qemu_bh_new(exynos4210_ltick_event, &s->l_timer[i]); bh[1] = qemu_bh_new(exynos4210_lfrc_event, &s->l_timer[i]); - s->l_timer[i].tick_timer.ptimer_tick = ptimer_init(bh[0]); - s->l_timer[i].ptimer_frc = ptimer_init(bh[1]); + s->l_timer[i].tick_timer.ptimer_tick = + ptimer_init(bh[0], PTIMER_POLICY_DEFAULT); + s->l_timer[i].ptimer_frc = ptimer_init(bh[1], PTIMER_POLICY_DEFAULT); s->l_timer[i].id = i; } diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c index 0e9e2e9bf5..f5765075c7 100644 --- a/hw/timer/exynos4210_pwm.c +++ b/hw/timer/exynos4210_pwm.c @@ -390,7 +390,7 @@ static void exynos4210_pwm_init(Object *obj) for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) { bh = qemu_bh_new(exynos4210_pwm_tick, &s->timer[i]); sysbus_init_irq(dev, &s->timer[i].irq); - s->timer[i].ptimer = ptimer_init(bh); + s->timer[i].ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); s->timer[i].id = i; s->timer[i].parent = s; } diff --git a/hw/timer/exynos4210_rtc.c b/hw/timer/exynos4210_rtc.c index da4dd451b9..1a648c5d9e 100644 --- a/hw/timer/exynos4210_rtc.c +++ b/hw/timer/exynos4210_rtc.c @@ -555,12 +555,12 @@ static void exynos4210_rtc_init(Object *obj) QEMUBH *bh; bh = qemu_bh_new(exynos4210_rtc_tick, s); - s->ptimer = ptimer_init(bh); + s->ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(s->ptimer, RTC_BASE_FREQ); exynos4210_rtc_update_freq(s, 0); bh = qemu_bh_new(exynos4210_rtc_1Hz_tick, s); - s->ptimer_1Hz = ptimer_init(bh); + s->ptimer_1Hz = ptimer_init(bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(s->ptimer_1Hz, RTC_BASE_FREQ); sysbus_init_irq(dev, &s->alm_irq); diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c index dd000f5afa..712d1aece5 100644 --- a/hw/timer/grlib_gptimer.c +++ b/hw/timer/grlib_gptimer.c @@ -363,7 +363,7 @@ static int grlib_gptimer_init(SysBusDevice *dev) timer->unit = unit; timer->bh = qemu_bh_new(grlib_gptimer_hit, timer); - timer->ptimer = ptimer_init(timer->bh); + timer->ptimer = ptimer_init(timer->bh, PTIMER_POLICY_DEFAULT); timer->id = i; /* One IRQ line for each timer */ diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c index eddf3481e8..8677b753b1 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -30,7 +30,7 @@ } \ } while (0) -static char const *imx_epit_reg_name(uint32_t reg) +static const char *imx_epit_reg_name(uint32_t reg) { switch (reg) { case 0: @@ -314,10 +314,10 @@ static void imx_epit_realize(DeviceState *dev, Error **errp) 0x00001000); sysbus_init_mmio(sbd, &s->iomem); - s->timer_reload = ptimer_init(NULL); + s->timer_reload = ptimer_init(NULL, PTIMER_POLICY_DEFAULT); bh = qemu_bh_new(imx_epit_cmp, s); - s->timer_cmp = ptimer_init(bh); + s->timer_cmp = ptimer_init(bh, PTIMER_POLICY_DEFAULT); } static void imx_epit_class_init(ObjectClass *klass, void *data) diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index 82bc73cb86..010ccbf207 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -29,7 +29,7 @@ } \ } while (0) -static char const *imx_gpt_reg_name(uint32_t reg) +static const char *imx_gpt_reg_name(uint32_t reg) { switch (reg) { case 0: @@ -461,7 +461,7 @@ static void imx_gpt_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->iomem); bh = qemu_bh_new(imx_gpt_timeout, s); - s->timer = ptimer_init(bh); + s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); } static void imx_gpt_class_init(ObjectClass *klass, void *data) diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c index e45a65bb9d..2a07b59524 100644 --- a/hw/timer/lm32_timer.c +++ b/hw/timer/lm32_timer.c @@ -184,7 +184,7 @@ static void lm32_timer_init(Object *obj) sysbus_init_irq(dev, &s->irq); s->bh = qemu_bh_new(timer_hit, s); - s->ptimer = ptimer_init(s->bh); + s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT); memory_region_init_io(&s->iomem, obj, &timer_ops, s, "timer", R_MAX * 4); diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c index 21948328ce..44885907c9 100644 --- a/hw/timer/milkymist-sysctl.c +++ b/hw/timer/milkymist-sysctl.c @@ -281,8 +281,8 @@ static void milkymist_sysctl_init(Object *obj) s->bh0 = qemu_bh_new(timer0_hit, s); s->bh1 = qemu_bh_new(timer1_hit, s); - s->ptimer0 = ptimer_init(s->bh0); - s->ptimer1 = ptimer_init(s->bh1); + s->ptimer0 = ptimer_init(s->bh0, PTIMER_POLICY_DEFAULT); + s->ptimer1 = ptimer_init(s->bh1, PTIMER_POLICY_DEFAULT); memory_region_init_io(&s->regs_region, obj, &sysctl_mmio_ops, s, "milkymist-sysctl", R_MAX * 4); diff --git a/hw/timer/puv3_ost.c b/hw/timer/puv3_ost.c index 93650b7990..0b3d717e60 100644 --- a/hw/timer/puv3_ost.c +++ b/hw/timer/puv3_ost.c @@ -125,7 +125,7 @@ static int puv3_ost_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); s->bh = qemu_bh_new(puv3_ost_tick, s); - s->ptimer = ptimer_init(s->bh); + s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(s->ptimer, 50 * 1000 * 1000); memory_region_init_io(&s->iomem, OBJECT(s), &puv3_ost_ops, s, "puv3_ost", diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c index 255b2fc910..9afb2d048c 100644 --- a/hw/timer/sh_timer.c +++ b/hw/timer/sh_timer.c @@ -203,7 +203,7 @@ static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq) s->irq = irq; bh = qemu_bh_new(sh_timer_tick, s); - s->timer = ptimer_init(bh); + s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); sh_timer_write(s, OFFSET_TCOR >> 2, s->tcor); sh_timer_write(s, OFFSET_TCNT >> 2, s->tcnt); diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c index fb3e08bedc..bfee1f3027 100644 --- a/hw/timer/slavio_timer.c +++ b/hw/timer/slavio_timer.c @@ -389,7 +389,7 @@ static int slavio_timer_init1(SysBusDevice *dev) tc->timer_index = i; bh = qemu_bh_new(slavio_timer_irq, tc); - s->cputimer[i].timer = ptimer_init(bh); + s->cputimer[i].timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD); size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE; diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c index 2ea970dc9d..59439c05be 100644 --- a/hw/timer/xilinx_timer.c +++ b/hw/timer/xilinx_timer.c @@ -218,7 +218,7 @@ static void xilinx_timer_realize(DeviceState *dev, Error **errp) xt->parent = t; xt->nr = i; xt->bh = qemu_bh_new(timer_hit, xt); - xt->ptimer = ptimer_init(xt->bh); + xt->ptimer = ptimer_init(xt->bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(xt->ptimer, t->freq_hz); } diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h new file mode 100644 index 0000000000..932704c380 --- /dev/null +++ b/include/hw/arm/aspeed_soc.h @@ -0,0 +1,59 @@ +/* + * ASPEED SoC family + * + * Andrew Jeffery <andrew@aj.id.au> + * + * Copyright 2016 IBM Corp. + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + */ + +#ifndef ASPEED_SOC_H +#define ASPEED_SOC_H + +#include "hw/arm/arm.h" +#include "hw/intc/aspeed_vic.h" +#include "hw/misc/aspeed_scu.h" +#include "hw/misc/aspeed_sdmc.h" +#include "hw/timer/aspeed_timer.h" +#include "hw/i2c/aspeed_i2c.h" +#include "hw/ssi/aspeed_smc.h" + +typedef struct AspeedSoCState { + /*< private >*/ + DeviceState parent; + + /*< public >*/ + ARMCPU *cpu; + MemoryRegion iomem; + AspeedVICState vic; + AspeedTimerCtrlState timerctrl; + AspeedI2CState i2c; + AspeedSCUState scu; + AspeedSMCState smc; + AspeedSMCState spi; + AspeedSDMCState sdmc; +} AspeedSoCState; + +#define TYPE_ASPEED_SOC "aspeed-soc" +#define ASPEED_SOC(obj) OBJECT_CHECK(AspeedSoCState, (obj), TYPE_ASPEED_SOC) + +typedef struct AspeedSoCInfo { + const char *name; + const char *cpu_model; + uint32_t silicon_rev; + hwaddr sdram_base; +} AspeedSoCInfo; + +typedef struct AspeedSoCClass { + DeviceClass parent_class; + AspeedSoCInfo *info; +} AspeedSoCClass; + +#define ASPEED_SOC_CLASS(klass) \ + OBJECT_CLASS_CHECK(AspeedSoCClass, (klass), TYPE_ASPEED_SOC) +#define ASPEED_SOC_GET_CLASS(obj) \ + OBJECT_GET_CLASS(AspeedSoCClass, (obj), TYPE_ASPEED_SOC) + +#endif /* ASPEED_SOC_H */ diff --git a/include/hw/arm/ast2400.h b/include/hw/arm/ast2400.h deleted file mode 100644 index e68807d475..0000000000 --- a/include/hw/arm/ast2400.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * ASPEED AST2400 SoC - * - * Andrew Jeffery <andrew@aj.id.au> - * - * Copyright 2016 IBM Corp. - * - * This code is licensed under the GPL version 2 or later. See - * the COPYING file in the top-level directory. - */ - -#ifndef AST2400_H -#define AST2400_H - -#include "hw/arm/arm.h" -#include "hw/intc/aspeed_vic.h" -#include "hw/misc/aspeed_scu.h" -#include "hw/misc/aspeed_sdmc.h" -#include "hw/timer/aspeed_timer.h" -#include "hw/i2c/aspeed_i2c.h" -#include "hw/ssi/aspeed_smc.h" - -typedef struct AST2400State { - /*< private >*/ - DeviceState parent; - - /*< public >*/ - ARMCPU *cpu; - MemoryRegion iomem; - AspeedVICState vic; - AspeedTimerCtrlState timerctrl; - AspeedI2CState i2c; - AspeedSCUState scu; - AspeedSMCState smc; - AspeedSMCState spi; - AspeedSDMCState sdmc; -} AST2400State; - -#define TYPE_AST2400 "ast2400" -#define AST2400(obj) OBJECT_CHECK(AST2400State, (obj), TYPE_AST2400) - -#define AST2400_SDRAM_BASE 0x40000000 - -#endif /* AST2400_H */ diff --git a/include/hw/dma/xlnx-zynq-devcfg.h b/include/hw/dma/xlnx-zynq-devcfg.h index d40e5c8df6..9f5119a89a 100644 --- a/include/hw/dma/xlnx-zynq-devcfg.h +++ b/include/hw/dma/xlnx-zynq-devcfg.h @@ -34,7 +34,7 @@ #define XLNX_ZYNQ_DEVCFG(obj) \ OBJECT_CHECK(XlnxZynqDevcfg, (obj), TYPE_XLNX_ZYNQ_DEVCFG) -#define XLNX_ZYNQ_DEVCFG_R_MAX 0x118 +#define XLNX_ZYNQ_DEVCFG_R_MAX (0x100 / 4) #define XLNX_ZYNQ_DEVCFG_DMA_CMD_FIFO_LEN 10 diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h index f510e7ec2a..25659b93be 100644 --- a/include/hw/elf_ops.h +++ b/include/hw/elf_ops.h @@ -263,7 +263,8 @@ static int glue(load_elf, SZ)(const char *name, int fd, void *translate_opaque, int must_swab, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr, - int elf_machine, int clear_lsb, int data_swab) + int elf_machine, int clear_lsb, int data_swab, + AddressSpace *as) { struct elfhdr ehdr; struct elf_phdr *phdr = NULL, *ph; @@ -280,6 +281,11 @@ static int glue(load_elf, SZ)(const char *name, int fd, glue(bswap_ehdr, SZ)(&ehdr); } + if (elf_machine <= EM_NONE) { + /* The caller didn't specify an ARCH, we can figure it out */ + elf_machine = ehdr.e_machine; + } + switch (elf_machine) { case EM_PPC64: if (ehdr.e_machine != EM_PPC64) { @@ -400,7 +406,7 @@ static int glue(load_elf, SZ)(const char *name, int fd, snprintf(label, sizeof(label), "phdr #%d: %s", i, name); /* rom_add_elf_program() seize the ownership of 'data' */ - rom_add_elf_program(label, data, file_size, mem_size, addr); + rom_add_elf_program(label, data, file_size, mem_size, addr, as); total_size += mem_size; if (addr < low) diff --git a/include/hw/loader.h b/include/hw/loader.h index 4879b63a2f..038170624d 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -14,8 +14,28 @@ int get_image_size(const char *filename); int load_image(const char *filename, uint8_t *addr); /* deprecated */ ssize_t load_image_size(const char *filename, void *addr, size_t size); + +/**load_image_targphys_as: + * @filename: Path to the image file + * @addr: Address to load the image to + * @max_sz: The maximum size of the image to load + * @as: The AddressSpace to load the ELF to. The value of address_space_memory + * is used if nothing is supplied here. + * + * Load a fixed image into memory. + * + * Returns the size of the loaded image on success, -1 otherwise. + */ +int load_image_targphys_as(const char *filename, + hwaddr addr, uint64_t max_sz, AddressSpace *as); + +/** load_image_targphys: + * Same as load_image_targphys_as(), but doesn't allow the caller to specify + * an AddressSpace. + */ int load_image_targphys(const char *filename, hwaddr, uint64_t max_sz); + /** * load_image_mr: load an image into a memory region * @filename: Path to the image file @@ -45,7 +65,7 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz); #define ELF_LOAD_WRONG_ENDIAN -4 const char *load_elf_strerror(int error); -/** load_elf: +/** load_elf_as: * @filename: Path of ELF file * @translate_fn: optional function to translate load addresses * @translate_opaque: opaque data passed to @translate_fn @@ -59,6 +79,8 @@ const char *load_elf_strerror(int error); * @data_swab: Set to order of byte swapping for data. 0 for no swap, 1 * for swapping bytes within halfwords, 2 for bytes within * words and 3 for within doublewords. + * @as: The AddressSpace to load the ELF to. The value of address_space_memory + * is used if nothing is supplied here. * * Load an ELF file's contents to the emulated system's address space. * Clients may optionally specify a callback to perform address @@ -68,8 +90,19 @@ const char *load_elf_strerror(int error); * load will fail if the target ELF does not match. Some architectures * have some architecture-specific behaviours that come into effect when * their particular values for @elf_machine are set. + * If @elf_machine is EM_NONE then the machine type will be read from the + * ELF header and no checks will be carried out against the machine type. */ +int load_elf_as(const char *filename, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr, + uint64_t *highaddr, int big_endian, int elf_machine, + int clear_lsb, int data_swab, AddressSpace *as); +/** load_elf: + * Same as load_elf_as(), but doesn't allow the caller to specify an + * AddressSpace. + */ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr, int big_endian, int elf_machine, @@ -89,6 +122,30 @@ void load_elf_hdr(const char *filename, void *hdr, bool *is64, Error **errp); int load_aout(const char *filename, hwaddr addr, int max_sz, int bswap_needed, hwaddr target_page_size); + +/** load_uimage_as: + * @filename: Path of uimage file + * @ep: Populated with program entry point. Ignored if NULL. + * @loadaddr: Populated with the load address. Ignored if NULL. + * @is_linux: Is set to true if the image loaded is Linux. Ignored if NULL. + * @translate_fn: optional function to translate load addresses + * @translate_opaque: opaque data passed to @translate_fn + * @as: The AddressSpace to load the ELF to. The value of address_space_memory + * is used if nothing is supplied here. + * + * Loads a u-boot image into memory. + * + * Returns the size of the loaded image on success, -1 otherwise. + */ +int load_uimage_as(const char *filename, hwaddr *ep, + hwaddr *loadaddr, int *is_linux, + uint64_t (*translate_fn)(void *, uint64_t), + void *translate_opaque, AddressSpace *as); + +/** load_uimage: + * Same as load_uimage_as(), but doesn't allow the caller to specify an + * AddressSpace. + */ int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr, int *is_linux, uint64_t (*translate_fn)(void *, uint64_t), @@ -118,14 +175,14 @@ extern bool rom_file_has_mr; int rom_add_file(const char *file, const char *fw_dir, hwaddr addr, int32_t bootindex, - bool option_rom, MemoryRegion *mr); + bool option_rom, MemoryRegion *mr, AddressSpace *as); MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, size_t max_len, hwaddr addr, const char *fw_file_name, FWCfgReadCallback fw_callback, void *callback_opaque); int rom_add_elf_program(const char *name, void *data, size_t datasize, - size_t romsize, hwaddr addr); + size_t romsize, hwaddr addr, AddressSpace *as); int rom_check_and_register_reset(void); void rom_set_fw(FWCfgState *f); void rom_set_order_override(int order); @@ -135,11 +192,17 @@ void *rom_ptr(hwaddr addr); void hmp_info_roms(Monitor *mon, const QDict *qdict); #define rom_add_file_fixed(_f, _a, _i) \ - rom_add_file(_f, NULL, _a, _i, false, NULL) + rom_add_file(_f, NULL, _a, _i, false, NULL, NULL) #define rom_add_blob_fixed(_f, _b, _l, _a) \ rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL) #define rom_add_file_mr(_f, _mr, _i) \ - rom_add_file(_f, NULL, 0, _i, false, _mr) + rom_add_file(_f, NULL, 0, _i, false, _mr, NULL) +#define rom_add_file_as(_f, _as, _i) \ + rom_add_file(_f, NULL, 0, _i, false, NULL, _as) +#define rom_add_file_fixed_as(_f, _a, _i, _as) \ + rom_add_file(_f, NULL, _a, _i, false, NULL, _as) +#define rom_add_blob_fixed_as(_f, _b, _l, _a, _as) \ + rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, _as) #define PC_ROM_MIN_VGA 0xc0000 #define PC_ROM_MIN_OPTION 0xc8000 diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h index fdfd982288..14ffc43de8 100644 --- a/include/hw/misc/aspeed_scu.h +++ b/include/hw/misc/aspeed_scu.h @@ -33,7 +33,200 @@ typedef struct AspeedSCUState { #define AST2400_A0_SILICON_REV 0x02000303U #define AST2500_A0_SILICON_REV 0x04000303U +#define AST2500_A1_SILICON_REV 0x04010303U extern bool is_supported_silicon_rev(uint32_t silicon_rev); +/* + * Extracted from Aspeed SDK v00.03.21. Fixes and extra definitions + * were added. + * + * Original header file : + * arch/arm/mach-aspeed/include/mach/regs-scu.h + * + * Copyright (C) 2012-2020 ASPEED Technology Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * History : + * 1. 2012/12/29 Ryan Chen Create + */ + +/* Hardware Strapping Register definition (for Aspeed AST2400 SOC) + * + * 31:29 Software defined strapping registers + * 28:27 DRAM size setting (for VGA driver use) + * 26:24 DRAM configuration setting + * 23 Enable 25 MHz reference clock input + * 22 Enable GPIOE pass-through mode + * 21 Enable GPIOD pass-through mode + * 20 Disable LPC to decode SuperIO 0x2E/0x4E address + * 19 Disable ACPI function + * 23,18 Clock source selection + * 17 Enable BMC 2nd boot watchdog timer + * 16 SuperIO configuration address selection + * 15 VGA Class Code selection + * 14 Enable LPC dedicated reset pin function + * 13:12 SPI mode selection + * 11:10 CPU/AHB clock frequency ratio selection + * 9:8 H-PLL default clock frequency selection + * 7 Define MAC#2 interface + * 6 Define MAC#1 interface + * 5 Enable VGA BIOS ROM + * 4 Boot flash memory extended option + * 3:2 VGA memory size selection + * 1:0 BMC CPU boot code selection + */ +#define SCU_AST2400_HW_STRAP_SW_DEFINE(x) ((x) << 29) +#define SCU_AST2400_HW_STRAP_SW_DEFINE_MASK (0x7 << 29) + +#define SCU_AST2400_HW_STRAP_DRAM_SIZE(x) ((x) << 27) +#define SCU_AST2400_HW_STRAP_DRAM_SIZE_MASK (0x3 << 27) +#define DRAM_SIZE_64MB 0 +#define DRAM_SIZE_128MB 1 +#define DRAM_SIZE_256MB 2 +#define DRAM_SIZE_512MB 3 + +#define SCU_AST2400_HW_STRAP_DRAM_CONFIG(x) ((x) << 24) +#define SCU_AST2400_HW_STRAP_DRAM_CONFIG_MASK (0x7 << 24) + +#define SCU_HW_STRAP_GPIOE_PT_EN (0x1 << 22) +#define SCU_HW_STRAP_GPIOD_PT_EN (0x1 << 21) +#define SCU_HW_STRAP_LPC_DEC_SUPER_IO (0x1 << 20) +#define SCU_AST2400_HW_STRAP_ACPI_DIS (0x1 << 19) + +/* bit 23, 18 [1,0] */ +#define SCU_AST2400_HW_STRAP_SET_CLK_SOURCE(x) (((((x) & 0x3) >> 1) << 23) \ + | (((x) & 0x1) << 18)) +#define SCU_AST2400_HW_STRAP_GET_CLK_SOURCE(x) (((((x) >> 23) & 0x1) << 1) \ + | (((x) >> 18) & 0x1)) +#define SCU_AST2400_HW_STRAP_CLK_SOURCE_MASK ((0x1 << 23) | (0x1 << 18)) +#define AST2400_CLK_25M_IN (0x1 << 23) +#define AST2400_CLK_24M_IN 0 +#define AST2400_CLK_48M_IN 1 +#define AST2400_CLK_25M_IN_24M_USB_CKI 2 +#define AST2400_CLK_25M_IN_48M_USB_CKI 3 + +#define SCU_HW_STRAP_2ND_BOOT_WDT (0x1 << 17) +#define SCU_HW_STRAP_SUPER_IO_CONFIG (0x1 << 16) +#define SCU_HW_STRAP_VGA_CLASS_CODE (0x1 << 15) +#define SCU_HW_STRAP_LPC_RESET_PIN (0x1 << 14) + +#define SCU_HW_STRAP_SPI_MODE(x) ((x) << 12) +#define SCU_HW_STRAP_SPI_MODE_MASK (0x3 << 12) +#define SCU_HW_STRAP_SPI_DIS 0 +#define SCU_HW_STRAP_SPI_MASTER 1 +#define SCU_HW_STRAP_SPI_M_S_EN 2 +#define SCU_HW_STRAP_SPI_PASS_THROUGH 3 + +#define SCU_AST2400_HW_STRAP_SET_CPU_AHB_RATIO(x) ((x) << 10) +#define SCU_AST2400_HW_STRAP_GET_CPU_AHB_RATIO(x) (((x) >> 10) & 3) +#define SCU_AST2400_HW_STRAP_CPU_AHB_RATIO_MASK (0x3 << 10) +#define AST2400_CPU_AHB_RATIO_1_1 0 +#define AST2400_CPU_AHB_RATIO_2_1 1 +#define AST2400_CPU_AHB_RATIO_4_1 2 +#define AST2400_CPU_AHB_RATIO_3_1 3 + +#define SCU_AST2400_HW_STRAP_GET_H_PLL_CLK(x) (((x) >> 8) & 0x3) +#define SCU_AST2400_HW_STRAP_H_PLL_CLK_MASK (0x3 << 8) +#define AST2400_CPU_384MHZ 0 +#define AST2400_CPU_360MHZ 1 +#define AST2400_CPU_336MHZ 2 +#define AST2400_CPU_408MHZ 3 + +#define SCU_HW_STRAP_MAC1_RGMII (0x1 << 7) +#define SCU_HW_STRAP_MAC0_RGMII (0x1 << 6) +#define SCU_HW_STRAP_VGA_BIOS_ROM (0x1 << 5) +#define SCU_HW_STRAP_SPI_WIDTH (0x1 << 4) + +#define SCU_HW_STRAP_VGA_SIZE_GET(x) (((x) >> 2) & 0x3) +#define SCU_HW_STRAP_VGA_MASK (0x3 << 2) +#define SCU_HW_STRAP_VGA_SIZE_SET(x) ((x) << 2) +#define VGA_8M_DRAM 0 +#define VGA_16M_DRAM 1 +#define VGA_32M_DRAM 2 +#define VGA_64M_DRAM 3 + +#define SCU_AST2400_HW_STRAP_BOOT_MODE(x) (x) +#define AST2400_NOR_BOOT 0 +#define AST2400_NAND_BOOT 1 +#define AST2400_SPI_BOOT 2 +#define AST2400_DIS_BOOT 3 + +/* + * Hardware strapping register definition (for Aspeed AST2500 SoC and + * higher) + * + * 31 Enable SPI Flash Strap Auto Fetch Mode + * 30 Enable GPIO Strap Mode + * 29 Select UART Debug Port + * 28 Reserved (1) + * 27 Enable fast reset mode for ARM ICE debugger + * 26 Enable eSPI flash mode + * 25 Enable eSPI mode + * 24 Select DDR4 SDRAM + * 23 Select 25 MHz reference clock input mode + * 22 Enable GPIOE pass-through mode + * 21 Enable GPIOD pass-through mode + * 20 Disable LPC to decode SuperIO 0x2E/0x4E address + * 19 Enable ACPI function + * 18 Select USBCKI input frequency + * 17 Enable BMC 2nd boot watchdog timer + * 16 SuperIO configuration address selection + * 15 VGA Class Code selection + * 14 Select dedicated LPC reset input + * 13:12 SPI mode selection + * 11:9 AXI/AHB clock frequency ratio selection + * 8 Reserved (0) + * 7 Define MAC#2 interface + * 6 Define MAC#1 interface + * 5 Enable dedicated VGA BIOS ROM + * 4 Reserved (0) + * 3:2 VGA memory size selection + * 1 Reserved (1) + * 0 Disable CPU boot + */ +#define SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE (0x1 << 31) +#define SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE (0x1 << 30) +#define SCU_AST2500_HW_STRAP_UART_DEBUG (0x1 << 29) +#define UART_DEBUG_UART1 0 +#define UART_DEBUG_UART5 1 +#define SCU_AST2500_HW_STRAP_RESERVED28 (0x1 << 28) + +#define SCU_AST2500_HW_STRAP_FAST_RESET_DBG (0x1 << 27) +#define SCU_AST2500_HW_STRAP_ESPI_FLASH_ENABLE (0x1 << 26) +#define SCU_AST2500_HW_STRAP_ESPI_ENABLE (0x1 << 25) +#define SCU_AST2500_HW_STRAP_DDR4_ENABLE (0x1 << 24) + +#define SCU_AST2500_HW_STRAP_ACPI_ENABLE (0x1 << 19) +#define SCU_AST2500_HW_STRAP_USBCKI_FREQ (0x1 << 18) +#define USBCKI_FREQ_24MHZ 0 +#define USBCKI_FREQ_28MHZ 1 + +#define SCU_AST2500_HW_STRAP_SET_AXI_AHB_RATIO(x) ((x) << 9) +#define SCU_AST2500_HW_STRAP_GET_AXI_AHB_RATIO(x) (((x) >> 9) & 7) +#define SCU_AST2500_HW_STRAP_CPU_AXI_RATIO_MASK (0x7 << 9) +#define AXI_AHB_RATIO_UNDEFINED 0 +#define AXI_AHB_RATIO_2_1 1 +#define AXI_AHB_RATIO_3_1 2 +#define AXI_AHB_RATIO_4_1 3 +#define AXI_AHB_RATIO_5_1 4 +#define AXI_AHB_RATIO_6_1 5 +#define AXI_AHB_RATIO_7_1 6 +#define AXI_AHB_RATIO_8_1 7 + +#define SCU_AST2500_HW_STRAP_RESERVED1 (0x1 << 1) +#define SCU_AST2500_HW_STRAP_DIS_BOOT (0x1 << 0) + +#define AST2500_HW_STRAP1_DEFAULTS ( \ + SCU_AST2500_HW_STRAP_RESERVED28 | \ + SCU_HW_STRAP_2ND_BOOT_WDT | \ + SCU_HW_STRAP_VGA_CLASS_CODE | \ + SCU_HW_STRAP_LPC_RESET_PIN | \ + SCU_AST2500_HW_STRAP_SET_AXI_AHB_RATIO(AXI_AHB_RATIO_2_1) | \ + SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) | \ + SCU_AST2500_HW_STRAP_RESERVED1) + #endif /* ASPEED_SCU_H */ diff --git a/include/hw/misc/aspeed_sdmc.h b/include/hw/misc/aspeed_sdmc.h index 7e081f6d2b..551c8afdf4 100644 --- a/include/hw/misc/aspeed_sdmc.h +++ b/include/hw/misc/aspeed_sdmc.h @@ -25,6 +25,8 @@ typedef struct AspeedSDMCState { uint32_t regs[ASPEED_SDMC_NR_REGS]; uint32_t silicon_rev; + uint32_t ram_bits; + uint64_t ram_size; } AspeedSDMCState; diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h index f2e08e3575..c469ffe69b 100644 --- a/include/hw/net/cadence_gem.h +++ b/include/hw/net/cadence_gem.h @@ -30,7 +30,11 @@ #include "net/net.h" #include "hw/sysbus.h" -#define CADENCE_GEM_MAXREG (0x00000640/4) /* Last valid GEM address */ +#define CADENCE_GEM_MAXREG (0x00000800 / 4) /* Last valid GEM address */ + +#define MAX_PRIORITY_QUEUES 8 +#define MAX_TYPE1_SCREENERS 16 +#define MAX_TYPE2_SCREENERS 16 typedef struct CadenceGEMState { /*< private >*/ @@ -40,7 +44,12 @@ typedef struct CadenceGEMState { MemoryRegion iomem; NICState *nic; NICConf conf; - qemu_irq irq; + qemu_irq irq[MAX_PRIORITY_QUEUES]; + + /* Static properties */ + uint8_t num_priority_queues; + uint8_t num_type1_screeners; + uint8_t num_type2_screeners; /* GEM registers backing store */ uint32_t regs[CADENCE_GEM_MAXREG]; @@ -59,12 +68,12 @@ typedef struct CadenceGEMState { uint8_t phy_loop; /* Are we in phy loopback? */ /* The current DMA descriptor pointers */ - uint32_t rx_desc_addr; - uint32_t tx_desc_addr; + uint32_t rx_desc_addr[MAX_PRIORITY_QUEUES]; + uint32_t tx_desc_addr[MAX_PRIORITY_QUEUES]; uint8_t can_rx_state; /* Debug only */ - unsigned rx_desc[2]; + unsigned rx_desc[MAX_PRIORITY_QUEUES][2]; bool sar_active[4]; } CadenceGEMState; diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h index e397db5bdb..26c7fdcd75 100644 --- a/include/hw/ptimer.h +++ b/include/hw/ptimer.h @@ -12,11 +12,34 @@ #include "qemu/timer.h" #include "migration/vmstate.h" +/* The default ptimer policy retains backward compatibility with the legacy + * timers. Custom policies are adjusting the default one. Consider providing + * a correct policy for your timer. + * + * The rough edges of the default policy: + * - Starting to run with a period = 0 emits error message and stops the + * timer without a trigger. + * + * - Setting period to 0 of the running timer emits error message and + * stops the timer without a trigger. + * + * - Starting to run with counter = 0 or setting it to "0" while timer + * is running causes a trigger and reloads counter with a limit value. + * If limit = 0, ptimer emits error message and stops the timer. + * + * - Counter value of the running timer is one less than the actual value. + * + * - Changing period/frequency of the running timer loses time elapsed + * since the last period, effectively restarting the timer with a + * counter = counter value at the moment of change (.i.e. one less). + */ +#define PTIMER_POLICY_DEFAULT 0 + /* ptimer.c */ typedef struct ptimer_state ptimer_state; typedef void (*ptimer_cb)(void *opaque); -ptimer_state *ptimer_init(QEMUBH *bh); +ptimer_state *ptimer_init(QEMUBH *bh, uint8_t policy_mask); void ptimer_set_period(ptimer_state *s, int64_t period); void ptimer_set_freq(ptimer_state *s, uint32_t freq); uint64_t ptimer_get_limit(ptimer_state *s); diff --git a/include/qemu/module.h b/include/qemu/module.h index 2370708445..dc2c9d4c4e 100644 --- a/include/qemu/module.h +++ b/include/qemu/module.h @@ -52,9 +52,12 @@ typedef enum { #define qapi_init(function) module_init(function, MODULE_INIT_QAPI) #define type_init(function) module_init(function, MODULE_INIT_QOM) +#define block_module_load_one(lib) module_load_one("block-", lib) + void register_module_init(void (*fn)(void), module_init_type type); void register_dso_module_init(void (*fn)(void), module_init_type type); void module_call_init(module_init_type type); +void module_load_one(const char *prefix, const char *lib_name); #endif diff --git a/linux-user/arm/target_syscall.h b/linux-user/arm/target_syscall.h index cd021ff598..94e2a42cb2 100644 --- a/linux-user/arm/target_syscall.h +++ b/linux-user/arm/target_syscall.h @@ -32,5 +32,13 @@ struct target_pt_regs { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define TARGET_WANT_OLD_SYS_SELECT + +#define TARGET_FORCE_SHMLBA + +static inline abi_ulong target_shmlba(CPUARMState *env) +{ + return 4 * 4096; +} #endif /* ARM_TARGET_SYSCALL_H */ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 29455e4e47..3d751f8523 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2111,19 +2111,19 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias) found: /* Now know where the strtab and symtab are. Snarf them. */ - s = malloc(sizeof(*s)); + s = g_try_new(struct syminfo, 1); if (!s) { goto give_up; } i = shdr[str_idx].sh_size; - s->disas_strtab = strings = malloc(i); + s->disas_strtab = strings = g_try_malloc(i); if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) { goto give_up; } i = shdr[sym_idx].sh_size; - syms = malloc(i); + syms = g_try_malloc(i); if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) { goto give_up; } @@ -2157,7 +2157,7 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias) that we threw away. Whether or not this has any effect on the memory allocation depends on the malloc implementation and how many symbols we managed to discard. */ - new_syms = realloc(syms, nsyms * sizeof(*syms)); + new_syms = g_try_renew(struct elf_sym, syms, nsyms); if (new_syms == NULL) { goto give_up; } @@ -2178,9 +2178,9 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias) return; give_up: - free(s); - free(strings); - free(syms); + g_free(s); + g_free(strings); + g_free(syms); } int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) @@ -2233,7 +2233,7 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) we do not have the power to recompile these, we emulate the SVr4 behavior. Sigh. */ target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE, -1, 0); + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); } } @@ -3050,7 +3050,9 @@ static int elf_core_dump(int signr, const CPUArchState *env) phdr.p_align = ELF_EXEC_PAGESIZE; bswap_phdr(&phdr, 1); - dump_write(fd, &phdr, sizeof (phdr)); + if (dump_write(fd, &phdr, sizeof(phdr)) != 0) { + goto out; + } } /* diff --git a/linux-user/flatload.c b/linux-user/flatload.c index 42d1079a24..a35a560904 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -95,7 +95,13 @@ static int target_pread(int fd, abi_ulong ptr, abi_ulong len, int ret; buf = lock_user(VERIFY_WRITE, ptr, len, 0); + if (!buf) { + return -EFAULT; + } ret = pread(fd, buf, len, offset); + if (ret < 0) { + ret = -errno; + } unlock_user(buf, ptr, len); return ret; } diff --git a/linux-user/i386/target_syscall.h b/linux-user/i386/target_syscall.h index b4e895fd9c..2854758134 100644 --- a/linux-user/i386/target_syscall.h +++ b/linux-user/i386/target_syscall.h @@ -153,5 +153,6 @@ struct target_vm86plus_struct { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define TARGET_WANT_OLD_SYS_SELECT #endif /* I386_TARGET_SYSCALL_H */ diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 7e2c133ba1..1bad701481 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -120,6 +120,9 @@ MK_PTR(MK_STRUCT(STRUCT_fiemap))) #endif + IOCTL(FS_IOC_GETFLAGS, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(FS_IOC_SETFLAGS, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SIOCATMARK, IOC_R, MK_PTR(TYPE_INT)) IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT)) IOCTL(SIOCGIFFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) diff --git a/linux-user/m68k/target_syscall.h b/linux-user/m68k/target_syscall.h index db2be4f101..632ee4fcf8 100644 --- a/linux-user/m68k/target_syscall.h +++ b/linux-user/m68k/target_syscall.h @@ -24,6 +24,8 @@ struct target_pt_regs { #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define TARGET_WANT_OLD_SYS_SELECT + void do_m68k_simcall(CPUM68KState *, int); #endif /* M68K_TARGET_SYSCALL_H */ diff --git a/linux-user/main.c b/linux-user/main.c index 3ad70f8a6e..aba58c78bc 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -339,7 +339,7 @@ void cpu_loop(CPUX86State *env) info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP0D_GPF: /* XXX: potential problem if ABI32 */ @@ -353,7 +353,7 @@ void cpu_loop(CPUX86State *env) info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP0E_PAGE: @@ -364,7 +364,7 @@ void cpu_loop(CPUX86State *env) else info.si_code = TARGET_SEGV_ACCERR; info._sifields._sigfault._addr = env->cr[2]; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP00_DIVZ: #ifndef TARGET_X86_64 @@ -378,7 +378,7 @@ void cpu_loop(CPUX86State *env) info.si_errno = 0; info.si_code = TARGET_FPE_INTDIV; info._sifields._sigfault._addr = env->eip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP01_DB: @@ -398,7 +398,7 @@ void cpu_loop(CPUX86State *env) info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; } - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP04_INTO: @@ -413,7 +413,7 @@ void cpu_loop(CPUX86State *env) info.si_errno = 0; info.si_code = TARGET_SI_KERNEL; info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP06_ILLOP: @@ -421,7 +421,7 @@ void cpu_loop(CPUX86State *env) info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPN; info._sifields._sigfault._addr = env->eip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ @@ -436,7 +436,7 @@ void cpu_loop(CPUX86State *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -576,7 +576,7 @@ segv: /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->exception.vaddress; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } /* Handle a jump to the kernel code page. */ @@ -755,7 +755,7 @@ void cpu_loop(CPUARMState *env) info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPN; info._sifields._sigfault._addr = env->regs[15]; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } else if (rc < 0) { /* FP exception */ int arm_fpe=0; @@ -786,7 +786,7 @@ void cpu_loop(CPUARMState *env) if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV; info._sifields._sigfault._addr = env->regs[15]; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } else { env->regs[15] += 4; } @@ -907,7 +907,7 @@ void cpu_loop(CPUARMState *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = addr; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_DEBUG: @@ -921,7 +921,7 @@ void cpu_loop(CPUARMState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -1099,7 +1099,7 @@ void cpu_loop(CPUARMState *env) info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPN; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_STREX: if (!do_strex_a64(env)) { @@ -1113,7 +1113,7 @@ void cpu_loop(CPUARMState *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->exception.vaddress; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_DEBUG: case EXCP_BKPT: @@ -1122,7 +1122,7 @@ void cpu_loop(CPUARMState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_SEMIHOST: @@ -1202,7 +1202,7 @@ void cpu_loop(CPUUniCore32State *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->cp0.c4_faultaddr; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ @@ -1216,7 +1216,7 @@ void cpu_loop(CPUUniCore32State *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -1431,7 +1431,7 @@ void cpu_loop (CPUSPARCState *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->mmuregs[4]; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; #else @@ -1452,7 +1452,7 @@ void cpu_loop (CPUSPARCState *env) info._sifields._sigfault._addr = env->dmmuregs[4]; else info._sifields._sigfault._addr = cpu_tsptr(env)->tpc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; #ifndef TARGET_ABI32 @@ -1475,7 +1475,7 @@ void cpu_loop (CPUSPARCState *env) info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPC; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_DEBUG: @@ -1488,7 +1488,7 @@ void cpu_loop (CPUSPARCState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -1679,7 +1679,7 @@ void cpu_loop(CPUPPCState *env) break; } info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_ISI: /* Instruction storage exception */ /* XXX: check this */ @@ -1705,7 +1705,7 @@ void cpu_loop(CPUPPCState *env) break; } info._sifields._sigfault._addr = env->nip - 4; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_EXTERNAL: /* External input */ cpu_abort(cs, "External interrupt while in user mode. " @@ -1717,7 +1717,7 @@ void cpu_loop(CPUPPCState *env) info.si_errno = 0; info.si_code = TARGET_BUS_ADRALN; info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_PROGRAM: /* Program exception */ case POWERPC_EXCP_HV_EMU: /* HV emulation */ @@ -1808,14 +1808,14 @@ void cpu_loop(CPUPPCState *env) break; } info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_SYSCALL: /* System call exception */ cpu_abort(cs, "Syscall exception while in user mode. " @@ -1826,7 +1826,7 @@ void cpu_loop(CPUPPCState *env) info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_DECR: /* Decrementer exception */ cpu_abort(cs, "Decrementer interrupt while in user mode. " @@ -1853,7 +1853,7 @@ void cpu_loop(CPUPPCState *env) info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */ cpu_abort(cs, "Embedded floating-point data IRQ not handled\n"); @@ -1916,7 +1916,7 @@ void cpu_loop(CPUPPCState *env) info.si_errno = 0; info.si_code = TARGET_ILL_COPROC; info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */ cpu_abort(cs, "Programmable interval timer interrupt " @@ -2010,7 +2010,7 @@ void cpu_loop(CPUPPCState *env) info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->nip; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_DEBUG: @@ -2022,7 +2022,7 @@ void cpu_loop(CPUPPCState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -2456,13 +2456,13 @@ static int do_break(CPUMIPSState *env, target_siginfo_t *info, info->si_signo = TARGET_SIGFPE; info->si_errno = 0; info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV; - queue_signal(env, info->si_signo, &*info); + queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info); ret = 0; break; default: info->si_signo = TARGET_SIGTRAP; info->si_errno = 0; - queue_signal(env, info->si_signo, &*info); + queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info); ret = 0; break; } @@ -2560,14 +2560,14 @@ done_syscall: /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->CP0_BadVAddr; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_CpU: case EXCP_RI: info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = 0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ @@ -2582,7 +2582,7 @@ done_syscall: info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -2592,14 +2592,14 @@ done_syscall: info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->active_tc.PC; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_DSPDIS: info.si_signo = TARGET_SIGILL; info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPC; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; /* The code below was inspired by the MIPS Linux kernel trap * handling code in arch/mips/kernel/traps.c. @@ -2850,7 +2850,7 @@ void cpu_loop(CPUSH4State *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -2860,7 +2860,7 @@ void cpu_loop(CPUSH4State *env) info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->tea; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; default: @@ -2892,7 +2892,7 @@ void cpu_loop(CPUCRISState *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->pregs[PR_EDA]; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_INTERRUPT: @@ -2924,7 +2924,7 @@ void cpu_loop(CPUCRISState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -2957,7 +2957,7 @@ void cpu_loop(CPUMBState *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_INTERRUPT: @@ -3006,7 +3006,7 @@ void cpu_loop(CPUMBState *env) info.si_errno = 0; info.si_code = TARGET_FPE_FLTDIV; info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case ESR_EC_FPU: info.si_signo = TARGET_SIGFPE; @@ -3018,7 +3018,7 @@ void cpu_loop(CPUMBState *env) info.si_code = TARGET_FPE_FLTDIV; } info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; default: printf ("Unhandled hw-exception: 0x%x\n", @@ -3038,7 +3038,7 @@ void cpu_loop(CPUMBState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -3092,7 +3092,7 @@ void cpu_loop(CPUM68KState *env) info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPN; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_TRAP0: { @@ -3126,7 +3126,7 @@ void cpu_loop(CPUM68KState *env) /* XXX: check env->error_code */ info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->mmu.ar; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_DEBUG: @@ -3139,7 +3139,7 @@ void cpu_loop(CPUM68KState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } } break; @@ -3195,7 +3195,7 @@ static void do_store_exclusive(CPUAlphaState *env, int reg, int quad) info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = addr; - queue_signal(env, TARGET_SIGSEGV, &info); + queue_signal(env, TARGET_SIGSEGV, QEMU_SI_FAULT, &info); } void cpu_loop(CPUAlphaState *env) @@ -3237,7 +3237,7 @@ void cpu_loop(CPUAlphaState *env) info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR); info._sifields._sigfault._addr = env->trap_arg0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_UNALIGN: env->lock_addr = -1; @@ -3245,7 +3245,7 @@ void cpu_loop(CPUAlphaState *env) info.si_errno = 0; info.si_code = TARGET_BUS_ADRALN; info._sifields._sigfault._addr = env->trap_arg0; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_OPCDEC: do_sigill: @@ -3254,7 +3254,7 @@ void cpu_loop(CPUAlphaState *env) info.si_errno = 0; info.si_code = TARGET_ILL_ILLOPC; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_ARITH: env->lock_addr = -1; @@ -3262,7 +3262,7 @@ void cpu_loop(CPUAlphaState *env) info.si_errno = 0; info.si_code = TARGET_FPE_FLTINV; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_FEN: /* No-op. Linux simply re-enables the FPU. */ @@ -3276,7 +3276,7 @@ void cpu_loop(CPUAlphaState *env) info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case 0x81: /* BUGCHK */ @@ -3284,7 +3284,7 @@ void cpu_loop(CPUAlphaState *env) info.si_errno = 0; info.si_code = 0; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case 0x83: /* CALLSYS */ @@ -3356,7 +3356,7 @@ void cpu_loop(CPUAlphaState *env) } info.si_errno = 0; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; default: goto do_sigill; @@ -3368,7 +3368,7 @@ void cpu_loop(CPUAlphaState *env) env->lock_addr = -1; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_STL_C: @@ -3502,7 +3502,7 @@ void cpu_loop(CPUS390XState *env) info.si_errno = 0; info.si_code = n; info._sifields._sigfault._addr = addr; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; default: @@ -3526,7 +3526,7 @@ static void gen_sigill_reg(CPUTLGState *env) info.si_errno = 0; info.si_code = TARGET_ILL_PRVREG; info._sifields._sigfault._addr = env->pc; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } static void do_signal(CPUTLGState *env, int signo, int sigcode) @@ -3550,7 +3550,7 @@ static void do_signal(CPUTLGState *env, int signo, int sigcode) } info.si_code = sigcode; - queue_signal(env, info.si_signo, &info); + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } static void gen_sigsegv_maperr(CPUTLGState *env, target_ulong addr) @@ -4615,10 +4615,11 @@ int main(int argc, char **argv, char **envp) int i; #if defined(TARGET_PPC64) + int flag = (env->insns_flags2 & PPC2_BOOKE206) ? MSR_CM : MSR_SF; #if defined(TARGET_ABI32) - env->msr &= ~((target_ulong)1 << MSR_SF); + env->msr &= ~((target_ulong)1 << flag); #else - env->msr |= (target_ulong)1 << MSR_SF; + env->msr |= (target_ulong)1 << flag; #endif #endif env->nip = regs->nip; diff --git a/linux-user/microblaze/target_syscall.h b/linux-user/microblaze/target_syscall.h index 0b6980c899..4141cbaa5e 100644 --- a/linux-user/microblaze/target_syscall.h +++ b/linux-user/microblaze/target_syscall.h @@ -53,4 +53,6 @@ struct target_pt_regs { #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define TARGET_WANT_NI_OLD_SELECT + #endif diff --git a/linux-user/mips/target_syscall.h b/linux-user/mips/target_syscall.h index 2b4f390729..6c666dcb73 100644 --- a/linux-user/mips/target_syscall.h +++ b/linux-user/mips/target_syscall.h @@ -230,4 +230,11 @@ struct target_pt_regs { #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define TARGET_FORCE_SHMLBA + +static inline abi_ulong target_shmlba(CPUMIPSState *env) +{ + return 0x40000; +} + #endif /* MIPS_TARGET_SYSCALL_H */ diff --git a/linux-user/mips64/target_syscall.h b/linux-user/mips64/target_syscall.h index 8da9c1f9cc..a9c17f7edf 100644 --- a/linux-user/mips64/target_syscall.h +++ b/linux-user/mips64/target_syscall.h @@ -227,4 +227,11 @@ struct target_pt_regs { #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define TARGET_FORCE_SHMLBA + +static inline abi_ulong target_shmlba(CPUMIPSState *env) +{ + return 0x40000; +} + #endif /* MIPS64_TARGET_SYSCALL_H */ diff --git a/linux-user/openrisc/syscall_nr.h b/linux-user/openrisc/syscall_nr.h index 6b1c7d265e..04059d020c 100644 --- a/linux-user/openrisc/syscall_nr.h +++ b/linux-user/openrisc/syscall_nr.h @@ -459,8 +459,6 @@ #define TARGET_NR_getdents 1065 #define __ARCH_WANT_SYS_GETDENTS #define TARGET_NR_futimesat 1066 -#define TARGET_NR_select 1067 -#define __ARCH_WANT_SYS_SELECT #define TARGET_NR_poll 1068 #define TARGET_NR_epoll_wait 1069 #define TARGET_NR_ustat 1070 diff --git a/linux-user/ppc/target_syscall.h b/linux-user/ppc/target_syscall.h index a8662f4856..afc0570410 100644 --- a/linux-user/ppc/target_syscall.h +++ b/linux-user/ppc/target_syscall.h @@ -74,5 +74,6 @@ struct target_revectored_struct { #define TARGET_MINSIGSTKSZ 2048 #define TARGET_MLOCKALL_MCL_CURRENT 0x2000 #define TARGET_MLOCKALL_MCL_FUTURE 0x4000 +#define TARGET_WANT_NI_OLD_SELECT #endif /* PPC_TARGET_SYSCALL_H */ diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 815447f5fc..da73a01106 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -362,12 +362,23 @@ void print_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6); void print_syscall_ret(int num, abi_long arg1); +/** + * print_taken_signal: + * @target_signum: target signal being taken + * @tinfo: target_siginfo_t which will be passed to the guest for the signal + * + * Print strace output indicating that this signal is being taken by the guest, + * in a format similar to: + * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} --- + */ +void print_taken_signal(int target_signum, const target_siginfo_t *tinfo); extern int do_strace; /* signal.c */ void process_pending_signals(CPUArchState *cpu_env); void signal_init(void); -int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info); +int queue_signal(CPUArchState *env, int sig, int si_type, + target_siginfo_t *info); void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); int target_to_host_signal(int sig); diff --git a/linux-user/sh4/syscall_nr.h b/linux-user/sh4/syscall_nr.h index 50099846d2..e99f73589d 100644 --- a/linux-user/sh4/syscall_nr.h +++ b/linux-user/sh4/syscall_nr.h @@ -84,7 +84,7 @@ #define TARGET_NR_settimeofday 79 #define TARGET_NR_getgroups 80 #define TARGET_NR_setgroups 81 -#define TARGET_NR_select 82 + /* 82 was sys_oldselect */ #define TARGET_NR_symlink 83 #define TARGET_NR_oldlstat 84 #define TARGET_NR_readlink 85 diff --git a/linux-user/sh4/target_syscall.h b/linux-user/sh4/target_syscall.h index 78d5557124..2b5f75be13 100644 --- a/linux-user/sh4/target_syscall.h +++ b/linux-user/sh4/target_syscall.h @@ -19,4 +19,11 @@ struct target_pt_regs { #define TARGET_MLOCKALL_MCL_CURRENT 1 #define TARGET_MLOCKALL_MCL_FUTURE 2 +#define TARGET_FORCE_SHMLBA + +static inline abi_ulong target_shmlba(CPUSH4State *env) +{ + return 0x4000; +} + #endif /* SH4_TARGET_SYSCALL_H */ diff --git a/linux-user/signal.c b/linux-user/signal.c index d3ac0e2565..e4eea697b4 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -512,9 +512,43 @@ void signal_init(void) } } +#if !(defined(TARGET_X86_64) || defined(TARGET_UNICORE32)) +/* Force a synchronously taken signal. The kernel force_sig() function + * also forces the signal to "not blocked, not ignored", but for QEMU + * that work is done in process_pending_signals(). + */ +static void force_sig(int sig) +{ + CPUState *cpu = thread_cpu; + CPUArchState *env = cpu->env_ptr; + target_siginfo_t info; + + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_SI_KERNEL; + info._sifields._kill._pid = 0; + info._sifields._kill._uid = 0; + queue_signal(env, info.si_signo, QEMU_SI_KILL, &info); +} + +/* Force a SIGSEGV if we couldn't write to memory trying to set + * up the signal frame. oldsig is the signal we were trying to handle + * at the point of failure. + */ +static void force_sigsegv(int oldsig) +{ + if (oldsig == SIGSEGV) { + /* Make sure we don't try to deliver the signal again; this will + * end up with handle_pending_signal() calling dump_core_and_abort(). + */ + sigact_table[oldsig - 1]._sa_handler = TARGET_SIG_DFL; + } + force_sig(TARGET_SIGSEGV); +} +#endif /* abort execution with signal */ -static void QEMU_NORETURN force_sig(int target_sig) +static void QEMU_NORETURN dump_core_and_abort(int target_sig) { CPUState *cpu = thread_cpu; CPUArchState *env = cpu->env_ptr; @@ -569,19 +603,15 @@ static void QEMU_NORETURN force_sig(int target_sig) /* queue a signal so that it will be send to the virtual CPU as soon as possible */ -int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info) +int queue_signal(CPUArchState *env, int sig, int si_type, + target_siginfo_t *info) { CPUState *cpu = ENV_GET_CPU(env); TaskState *ts = cpu->opaque; trace_user_queue_signal(env, sig); - /* Currently all callers define siginfo structures which - * use the _sifields._sigfault union member, so we can - * set the type here. If that changes we should push this - * out so the si_type is passed in by callers. - */ - info->si_code = deposit32(info->si_code, 16, 16, QEMU_SI_FAULT); + info->si_code = deposit32(info->si_code, 16, 16, si_type); ts->sync_signal.info = *info; ts->sync_signal.pending = sig; @@ -1015,10 +1045,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - if (sig == TARGET_SIGSEGV) { - ka->_sa_handler = TARGET_SIG_DFL; - } - force_sig(TARGET_SIGSEGV /* , current */); + force_sigsegv(sig); } /* compare linux/arch/i386/kernel/signal.c:setup_rt_frame() */ @@ -1088,10 +1115,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - if (sig == TARGET_SIGSEGV) { - ka->_sa_handler = TARGET_SIG_DFL; - } - force_sig(TARGET_SIGSEGV /* , current */); + force_sigsegv(sig); } static int @@ -1165,7 +1189,7 @@ long do_sigreturn(CPUX86State *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUX86State *env) @@ -1196,7 +1220,7 @@ long do_rt_sigreturn(CPUX86State *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_AARCH64) @@ -1420,7 +1444,7 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sig(TARGET_SIGSEGV); + force_sigsegv(usig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -1466,7 +1490,7 @@ long do_rt_sigreturn(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } long do_sigreturn(CPUARMState *env) @@ -1772,7 +1796,7 @@ static void setup_frame_v1(int usig, struct target_sigaction *ka, trace_user_setup_frame(regs, frame_addr); if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { - return; + goto sigsegv; } setup_sigcontext(&frame->sc, regs, set->sig[0]); @@ -1785,6 +1809,9 @@ static void setup_frame_v1(int usig, struct target_sigaction *ka, frame_addr + offsetof(struct sigframe_v1, retcode)); unlock_user_struct(frame, frame_addr, 1); + return; +sigsegv: + force_sigsegv(usig); } static void setup_frame_v2(int usig, struct target_sigaction *ka, @@ -1795,7 +1822,7 @@ static void setup_frame_v2(int usig, struct target_sigaction *ka, trace_user_setup_frame(regs, frame_addr); if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { - return; + goto sigsegv; } setup_sigframe_v2(&frame->uc, set, regs); @@ -1804,6 +1831,9 @@ static void setup_frame_v2(int usig, struct target_sigaction *ka, frame_addr + offsetof(struct sigframe_v2, retcode)); unlock_user_struct(frame, frame_addr, 1); + return; +sigsegv: + force_sigsegv(usig); } static void setup_frame(int usig, struct target_sigaction *ka, @@ -1829,7 +1859,7 @@ static void setup_rt_frame_v1(int usig, struct target_sigaction *ka, trace_user_setup_rt_frame(env, frame_addr); if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { - return /* 1 */; + goto sigsegv; } info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info); @@ -1859,6 +1889,9 @@ static void setup_rt_frame_v1(int usig, struct target_sigaction *ka, env->regs[2] = uc_addr; unlock_user_struct(frame, frame_addr, 1); + return; +sigsegv: + force_sigsegv(usig); } static void setup_rt_frame_v2(int usig, struct target_sigaction *ka, @@ -1871,7 +1904,7 @@ static void setup_rt_frame_v2(int usig, struct target_sigaction *ka, trace_user_setup_rt_frame(env, frame_addr); if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { - return /* 1 */; + goto sigsegv; } info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info); @@ -1887,6 +1920,9 @@ static void setup_rt_frame_v2(int usig, struct target_sigaction *ka, env->regs[2] = uc_addr; unlock_user_struct(frame, frame_addr, 1); + return; +sigsegv: + force_sigsegv(usig); } static void setup_rt_frame(int usig, struct target_sigaction *ka, @@ -1976,8 +2012,8 @@ static long do_sigreturn_v1(CPUARMState *env) return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace) @@ -2035,7 +2071,8 @@ static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env, return (abi_ulong*)(iwmmxtframe + 1); } -static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr, +static int do_sigframe_return_v2(CPUARMState *env, + target_ulong context_addr, struct target_ucontext_v2 *uc) { sigset_t host_set; @@ -2062,8 +2099,11 @@ static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr, } } - if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) + if (do_sigaltstack(context_addr + + offsetof(struct target_ucontext_v2, tuc_stack), + 0, get_sp_from_cpustate(env)) == -EFAULT) { return 1; + } #if 0 /* Send SIGTRAP if we're single-stepping */ @@ -2094,7 +2134,10 @@ static long do_sigreturn_v2(CPUARMState *env) goto badframe; } - if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) { + if (do_sigframe_return_v2(env, + frame_addr + + offsetof(struct sigframe_v2, uc), + &frame->uc)) { goto badframe; } @@ -2103,8 +2146,8 @@ static long do_sigreturn_v2(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_sigreturn(CPUARMState *env) @@ -2157,8 +2200,8 @@ static long do_rt_sigreturn_v1(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } static long do_rt_sigreturn_v2(CPUARMState *env) @@ -2181,7 +2224,10 @@ static long do_rt_sigreturn_v2(CPUARMState *env) goto badframe; } - if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) { + if (do_sigframe_return_v2(env, + frame_addr + + offsetof(struct rt_sigframe_v2, uc), + &frame->uc)) { goto badframe; } @@ -2190,8 +2236,8 @@ static long do_rt_sigreturn_v2(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUARMState *env) @@ -2445,7 +2491,7 @@ sigill_and_return: #endif sigsegv: unlock_user(sf, sf_addr, sizeof(struct target_signal_frame)); - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -2525,6 +2571,7 @@ long do_sigreturn(CPUSPARCState *env) segv_and_exit: unlock_user_struct(sf, sf_addr, 0); force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUSPARCState *env) @@ -3037,7 +3084,7 @@ static void setup_frame(int sig, struct target_sigaction * ka, return; give_sigsegv: - force_sig(TARGET_SIGSEGV/*, current*/); + force_sigsegv(sig); } long do_sigreturn(CPUMIPSState *regs) @@ -3082,8 +3129,8 @@ long do_sigreturn(CPUMIPSState *regs) return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV/*, current*/); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } # endif /* O32 */ @@ -3146,7 +3193,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sig(TARGET_SIGSEGV/*, current*/); + force_sigsegv(sig); } long do_rt_sigreturn(CPUMIPSState *env) @@ -3179,8 +3226,8 @@ long do_rt_sigreturn(CPUMIPSState *env) return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV/*, current*/); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_SH4) @@ -3349,7 +3396,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -3409,7 +3456,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } long do_sigreturn(CPUSH4State *regs) @@ -3446,7 +3493,7 @@ long do_sigreturn(CPUSH4State *regs) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUSH4State *regs) @@ -3478,7 +3525,7 @@ long do_rt_sigreturn(CPUSH4State *regs) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_MICROBLAZE) @@ -3656,7 +3703,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); return; badframe: - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -3697,6 +3744,7 @@ long do_sigreturn(CPUMBState *env) return -TARGET_QEMU_ESIGRETURN; badframe: force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUMBState *env) @@ -3826,7 +3874,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, unlock_user_struct(frame, frame_addr, 1); return; badframe: - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -3864,6 +3912,7 @@ long do_sigreturn(CPUCRISState *env) return -TARGET_QEMU_ESIGRETURN; badframe: force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUCRISState *env) @@ -4065,10 +4114,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - if (sig == TARGET_SIGSEGV) { - ka->_sa_handler = TARGET_SIG_DFL; - } - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } long do_sigreturn(CPUOpenRISCState *env) @@ -4249,7 +4295,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -4304,7 +4350,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static int @@ -4358,7 +4404,7 @@ long do_sigreturn(CPUS390XState *env) badframe: force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUS390XState *env) @@ -4389,7 +4435,7 @@ long do_rt_sigreturn(CPUS390XState *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_PPC) @@ -4815,7 +4861,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -4910,7 +4956,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, sigsegv: unlock_user_struct(rt_sf, rt_sf_addr, 1); - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } @@ -4948,7 +4994,7 @@ sigsegv: unlock_user_struct(sr, sr_addr, 1); unlock_user_struct(sc, sc_addr, 1); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } /* See arch/powerpc/kernel/signal_32.c. */ @@ -5003,7 +5049,7 @@ long do_rt_sigreturn(CPUPPCState *env) sigsegv: unlock_user_struct(rt_sf, rt_sf_addr, 1); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_M68K) @@ -5159,7 +5205,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } static inline int target_rt_setup_ucontext(struct target_ucontext *uc, @@ -5298,7 +5344,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); } long do_sigreturn(CPUM68KState *env) @@ -5333,7 +5379,7 @@ long do_sigreturn(CPUM68KState *env) badframe: force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUM68KState *env) @@ -5366,7 +5412,7 @@ long do_rt_sigreturn(CPUM68KState *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_ALPHA) @@ -5505,10 +5551,8 @@ static void setup_frame(int sig, struct target_sigaction *ka, if (err) { give_sigsegv: - if (sig == TARGET_SIGSEGV) { - ka->_sa_handler = TARGET_SIG_DFL; - } - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); + return; } env->ir[IR_RA] = r26; @@ -5562,10 +5606,8 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, if (err) { give_sigsegv: - if (sig == TARGET_SIGSEGV) { - ka->_sa_handler = TARGET_SIG_DFL; - } - force_sig(TARGET_SIGSEGV); + force_sigsegv(sig); + return; } env->ir[IR_RA] = r26; @@ -5599,6 +5641,7 @@ long do_sigreturn(CPUAlphaState *env) badframe: force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUAlphaState *env) @@ -5628,6 +5671,7 @@ long do_rt_sigreturn(CPUAlphaState *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_TILEGX) @@ -5762,10 +5806,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, return; give_sigsegv: - if (sig == TARGET_SIGSEGV) { - ka->_sa_handler = TARGET_SIG_DFL; - } - force_sig(TARGET_SIGSEGV /* , current */); + force_sigsegv(sig); } long do_rt_sigreturn(CPUTLGState *env) @@ -5795,6 +5836,7 @@ long do_rt_sigreturn(CPUTLGState *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } #else @@ -5849,6 +5891,10 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig, handler = sa->_sa_handler; } + if (do_strace) { + print_taken_signal(sig, &k->info); + } + if (handler == TARGET_SIG_DFL) { /* default handler : ignore some signal. The other are job control or fatal */ if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) { @@ -5857,12 +5903,12 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig, sig != TARGET_SIGURG && sig != TARGET_SIGWINCH && sig != TARGET_SIGCONT) { - force_sig(sig); + dump_core_and_abort(sig); } } else if (handler == TARGET_SIG_IGN) { /* ignore sig */ } else if (handler == TARGET_SIG_ERR) { - force_sig(sig); + dump_core_and_abort(sig); } else { /* compute the blocked signals during the handler execution */ sigset_t *blocked_set; @@ -5921,6 +5967,7 @@ void process_pending_signals(CPUArchState *cpu_env) sigfillset(&set); sigprocmask(SIG_SETMASK, &set, 0); + restart_scan: sig = ts->sync_signal.pending; if (sig) { /* Synchronous signals are forced, @@ -5948,8 +5995,10 @@ void process_pending_signals(CPUArchState *cpu_env) (!sigismember(blocked_set, target_to_host_signal_table[sig]))) { handle_pending_signal(cpu_env, sig, &ts->sigtab[sig - 1]); - /* Restart scan from the beginning */ - sig = 1; + /* Restart scan from the beginning, as handle_pending_signal + * might have resulted in a new synchronous signal (eg SIGSEGV). + */ + goto restart_scan; } } diff --git a/linux-user/sparc/target_syscall.h b/linux-user/sparc/target_syscall.h index 326f674b4e..f97aa6b075 100644 --- a/linux-user/sparc/target_syscall.h +++ b/linux-user/sparc/target_syscall.h @@ -22,4 +22,20 @@ struct target_pt_regs { #define TARGET_MLOCKALL_MCL_CURRENT 0x2000 #define TARGET_MLOCKALL_MCL_FUTURE 0x4000 +/* For SPARC SHMLBA is determined at runtime in the kernel, and + * libc has to runtime-detect it using the hwcaps (see glibc + * sysdeps/unix/sysv/linux/sparc/getshmlba; we follow the same + * logic here, though we know we're not the sparc v9 64-bit case). + */ +#define TARGET_FORCE_SHMLBA + +static inline abi_ulong target_shmlba(CPUSPARCState *env) +{ + if (!(env->def->features & CPU_FEATURE_FLUSH)) { + return 64 * 1024; + } else { + return 256 * 1024; + } +} + #endif /* SPARC_TARGET_SYSCALL_H */ diff --git a/linux-user/strace.c b/linux-user/strace.c index cc10dc4703..1e5136098e 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -154,6 +154,100 @@ print_signal(abi_ulong arg, int last) gemu_log("%s%s", signal_name, get_comma(last)); } +static void print_si_code(int arg) +{ + const char *codename = NULL; + + switch (arg) { + case SI_USER: + codename = "SI_USER"; + break; + case SI_KERNEL: + codename = "SI_KERNEL"; + break; + case SI_QUEUE: + codename = "SI_QUEUE"; + break; + case SI_TIMER: + codename = "SI_TIMER"; + break; + case SI_MESGQ: + codename = "SI_MESGQ"; + break; + case SI_ASYNCIO: + codename = "SI_ASYNCIO"; + break; + case SI_SIGIO: + codename = "SI_SIGIO"; + break; + case SI_TKILL: + codename = "SI_TKILL"; + break; + default: + gemu_log("%d", arg); + return; + } + gemu_log("%s", codename); +} + +static void print_siginfo(const target_siginfo_t *tinfo) +{ + /* Print a target_siginfo_t in the format desired for printing + * signals being taken. We assume the target_siginfo_t is in the + * internal form where the top 16 bits of si_code indicate which + * part of the union is valid, rather than in the guest-visible + * form where the bottom 16 bits are sign-extended into the top 16. + */ + int si_type = extract32(tinfo->si_code, 16, 16); + int si_code = sextract32(tinfo->si_code, 0, 16); + + gemu_log("{si_signo="); + print_signal(tinfo->si_signo, 1); + gemu_log(", si_code="); + print_si_code(si_code); + + switch (si_type) { + case QEMU_SI_KILL: + gemu_log(", si_pid = %u, si_uid = %u", + (unsigned int)tinfo->_sifields._kill._pid, + (unsigned int)tinfo->_sifields._kill._uid); + break; + case QEMU_SI_TIMER: + gemu_log(", si_timer1 = %u, si_timer2 = %u", + tinfo->_sifields._timer._timer1, + tinfo->_sifields._timer._timer2); + break; + case QEMU_SI_POLL: + gemu_log(", si_band = %d, si_fd = %d", + tinfo->_sifields._sigpoll._band, + tinfo->_sifields._sigpoll._fd); + break; + case QEMU_SI_FAULT: + gemu_log(", si_addr = "); + print_pointer(tinfo->_sifields._sigfault._addr, 1); + break; + case QEMU_SI_CHLD: + gemu_log(", si_pid = %u, si_uid = %u, si_status = %d" + ", si_utime=" TARGET_ABI_FMT_ld + ", si_stime=" TARGET_ABI_FMT_ld, + (unsigned int)(tinfo->_sifields._sigchld._pid), + (unsigned int)(tinfo->_sifields._sigchld._uid), + tinfo->_sifields._sigchld._status, + tinfo->_sifields._sigchld._utime, + tinfo->_sifields._sigchld._stime); + break; + case QEMU_SI_RT: + gemu_log(", si_pid = %u, si_uid = %u, si_sigval = " TARGET_ABI_FMT_ld, + (unsigned int)tinfo->_sifields._rt._pid, + (unsigned int)tinfo->_sifields._rt._uid, + tinfo->_sifields._rt._sigval.sival_ptr); + break; + default: + g_assert_not_reached(); + } + gemu_log("}"); +} + static void print_sockaddr(abi_ulong addr, abi_long addrlen) { @@ -2190,3 +2284,15 @@ print_syscall_ret(int num, abi_long ret) break; } } + +void print_taken_signal(int target_signum, const target_siginfo_t *tinfo) +{ + /* Print the strace output for a signal being taken: + * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} --- + */ + gemu_log("--- "); + print_signal(target_signum, 1); + gemu_log(" "); + print_siginfo(tinfo); + gemu_log(" ---\n"); +} diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ca06943f3b..7aa2c1d720 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -112,8 +112,56 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include "qemu.h" -#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \ - CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID) +#ifndef CLONE_IO +#define CLONE_IO 0x80000000 /* Clone io context */ +#endif + +/* We can't directly call the host clone syscall, because this will + * badly confuse libc (breaking mutexes, for example). So we must + * divide clone flags into: + * * flag combinations that look like pthread_create() + * * flag combinations that look like fork() + * * flags we can implement within QEMU itself + * * flags we can't support and will return an error for + */ +/* For thread creation, all these flags must be present; for + * fork, none must be present. + */ +#define CLONE_THREAD_FLAGS \ + (CLONE_VM | CLONE_FS | CLONE_FILES | \ + CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM) + +/* These flags are ignored: + * CLONE_DETACHED is now ignored by the kernel; + * CLONE_IO is just an optimisation hint to the I/O scheduler + */ +#define CLONE_IGNORED_FLAGS \ + (CLONE_DETACHED | CLONE_IO) + +/* Flags for fork which we can implement within QEMU itself */ +#define CLONE_OPTIONAL_FORK_FLAGS \ + (CLONE_SETTLS | CLONE_PARENT_SETTID | \ + CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID) + +/* Flags for thread creation which we can implement within QEMU itself */ +#define CLONE_OPTIONAL_THREAD_FLAGS \ + (CLONE_SETTLS | CLONE_PARENT_SETTID | \ + CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT) + +#define CLONE_INVALID_FORK_FLAGS \ + (~(CSIGNAL | CLONE_OPTIONAL_FORK_FLAGS | CLONE_IGNORED_FLAGS)) + +#define CLONE_INVALID_THREAD_FLAGS \ + (~(CSIGNAL | CLONE_THREAD_FLAGS | CLONE_OPTIONAL_THREAD_FLAGS | \ + CLONE_IGNORED_FLAGS)) + +/* CLONE_VFORK is special cased early in do_fork(). The other flag bits + * have almost all been allocated. We cannot support any of + * CLONE_NEWNS, CLONE_NEWCGROUP, CLONE_NEWUTS, CLONE_NEWIPC, + * CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET, CLONE_PTRACE, CLONE_UNTRACED. + * The checks against the invalid thread masks above will catch these. + * (The one remaining unallocated bit is 0x1000 which used to be CLONE_PID.) + */ //#define DEBUG /* Define DEBUG_ERESTARTSYS to force every syscall to be restarted @@ -520,16 +568,7 @@ static int sys_getcwd1(char *buf, size_t size) } #ifdef TARGET_NR_utimensat -#ifdef CONFIG_UTIMENSAT -static int sys_utimensat(int dirfd, const char *pathname, - const struct timespec times[2], int flags) -{ - if (pathname == NULL) - return futimens(dirfd, times); - else - return utimensat(dirfd, pathname, times, flags); -} -#elif defined(__NR_utimensat) +#if defined(__NR_utimensat) #define __NR_sys_utimensat __NR_utimensat _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname, const struct timespec *,tsp,int,flags) @@ -1405,6 +1444,29 @@ static abi_long do_select(int n, return ret; } + +#if defined(TARGET_WANT_OLD_SYS_SELECT) +static abi_long do_old_select(abi_ulong arg1) +{ + struct target_sel_arg_struct *sel; + abi_ulong inp, outp, exp, tvp; + long nsel; + + if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) { + return -TARGET_EFAULT; + } + + nsel = tswapal(sel->n); + inp = tswapal(sel->inp); + outp = tswapal(sel->outp); + exp = tswapal(sel->exp); + tvp = tswapal(sel->tvp); + + unlock_user_struct(sel, arg1, 0); + + return do_select(nsel, inp, outp, exp, tvp); +} +#endif #endif static abi_long do_pipe2(int host_pipe[], int flags) @@ -3119,7 +3181,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, } static struct iovec *lock_iovec(int type, abi_ulong target_addr, - int count, int copy) + abi_ulong count, int copy) { struct target_iovec *target_vec; struct iovec *vec; @@ -3132,7 +3194,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr, errno = 0; return NULL; } - if (count < 0 || count > IOV_MAX) { + if (count > IOV_MAX) { errno = EINVAL; return NULL; } @@ -3207,7 +3269,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr, } static void unlock_iovec(struct iovec *vec, abi_ulong target_addr, - int count, int copy) + abi_ulong count, int copy) { struct target_iovec *target_vec; int i; @@ -3462,7 +3524,7 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, { abi_long ret, len; struct msghdr msg; - int count; + abi_ulong count; struct iovec *vec; abi_ulong target_vec; @@ -3472,7 +3534,14 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, ret = target_to_host_sockaddr(fd, msg.msg_name, tswapal(msgp->msg_name), msg.msg_namelen); - if (ret) { + if (ret == -TARGET_EFAULT) { + /* For connected sockets msg_name and msg_namelen must + * be ignored, so returning EFAULT immediately is wrong. + * Instead, pass a bad msg_name to the host kernel, and + * let it decide whether to return EFAULT or not. + */ + msg.msg_name = (void *)-1; + } else if (ret) { goto out2; } } else { @@ -3485,6 +3554,15 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, count = tswapal(msgp->msg_iovlen); target_vec = tswapal(msgp->msg_iov); + + if (count > IOV_MAX) { + /* sendrcvmsg returns a different errno for this condition than + * readv/writev, so we must catch it here before lock_iovec() does. + */ + ret = -TARGET_EMSGSIZE; + goto out2; + } + vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, target_vec, count, send); if (vec == NULL) { @@ -3525,7 +3603,7 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, } if (!is_error(ret)) { msgp->msg_namelen = tswap32(msg.msg_namelen); - if (msg.msg_name != NULL) { + if (msg.msg_name != NULL && msg.msg_name != (void *)-1) { ret = host_to_target_sockaddr(tswapal(msgp->msg_name), msg.msg_name, msg.msg_namelen); if (ret) { @@ -4568,12 +4646,34 @@ static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf) return ret; } -static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg) +#ifndef TARGET_FORCE_SHMLBA +/* For most architectures, SHMLBA is the same as the page size; + * some architectures have larger values, in which case they should + * define TARGET_FORCE_SHMLBA and provide a target_shmlba() function. + * This corresponds to the kernel arch code defining __ARCH_FORCE_SHMLBA + * and defining its own value for SHMLBA. + * + * The kernel also permits SHMLBA to be set by the architecture to a + * value larger than the page size without setting __ARCH_FORCE_SHMLBA; + * this means that addresses are rounded to the large size if + * SHM_RND is set but addresses not aligned to that size are not rejected + * as long as they are at least page-aligned. Since the only architecture + * which uses this is ia64 this code doesn't provide for that oddity. + */ +static inline abi_ulong target_shmlba(CPUArchState *cpu_env) +{ + return TARGET_PAGE_SIZE; +} +#endif + +static inline abi_ulong do_shmat(CPUArchState *cpu_env, + int shmid, abi_ulong shmaddr, int shmflg) { abi_long raddr; void *host_raddr; struct shmid_ds shm_info; int i,ret; + abi_ulong shmlba; /* find out the length of the shared memory segment */ ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info)); @@ -4582,6 +4682,16 @@ static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg) return ret; } + shmlba = target_shmlba(cpu_env); + + if (shmaddr & (shmlba - 1)) { + if (shmflg & SHM_RND) { + shmaddr &= ~(shmlba - 1); + } else { + return -TARGET_EINVAL; + } + } + mmap_lock(); if (shmaddr) @@ -4640,7 +4750,8 @@ static inline abi_long do_shmdt(abi_ulong shmaddr) #ifdef TARGET_NR_ipc /* ??? This only works with linear mappings. */ /* do_ipc() must return target values and target errnos. */ -static abi_long do_ipc(unsigned int call, abi_long first, +static abi_long do_ipc(CPUArchState *cpu_env, + unsigned int call, abi_long first, abi_long second, abi_long third, abi_long ptr, abi_long fifth) { @@ -4709,7 +4820,7 @@ static abi_long do_ipc(unsigned int call, abi_long first, default: { abi_ulong raddr; - raddr = do_shmat(first, ptr, second); + raddr = do_shmat(cpu_env, first, ptr, second); if (is_error(raddr)) return get_errno(raddr); if (put_user_ual(raddr, third)) @@ -4994,13 +5105,18 @@ static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, guest_data = arg + host_dm->data_start; if ((guest_data - arg) < 0) { - ret = -EINVAL; + ret = -TARGET_EINVAL; goto out; } guest_data_size = host_dm->data_size - host_dm->data_start; host_data = (char*)host_dm + host_dm->data_start; argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1); + if (!argptr) { + ret = -TARGET_EFAULT; + goto out; + } + switch (ie->host_cmd) { case DM_REMOVE_ALL: case DM_LIST_DEVICES: @@ -5966,9 +6082,10 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, TaskState *ts; CPUState *new_cpu; CPUArchState *new_env; - unsigned int nptl_flags; sigset_t sigmask; + flags &= ~CLONE_IGNORED_FLAGS; + /* Emulate vfork() with fork() */ if (flags & CLONE_VFORK) flags &= ~(CLONE_VFORK | CLONE_VM); @@ -5978,6 +6095,11 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, new_thread_info info; pthread_attr_t attr; + if (((flags & CLONE_THREAD_FLAGS) != CLONE_THREAD_FLAGS) || + (flags & CLONE_INVALID_THREAD_FLAGS)) { + return -TARGET_EINVAL; + } + ts = g_new0(TaskState, 1); init_task_state(ts); /* we create a new CPU instance. */ @@ -5989,15 +6111,14 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, ts->bprm = parent_ts->bprm; ts->info = parent_ts->info; ts->signal_mask = parent_ts->signal_mask; - nptl_flags = flags; - flags &= ~CLONE_NPTL_FLAGS2; - if (nptl_flags & CLONE_CHILD_CLEARTID) { + if (flags & CLONE_CHILD_CLEARTID) { ts->child_tidptr = child_tidptr; } - if (nptl_flags & CLONE_SETTLS) + if (flags & CLONE_SETTLS) { cpu_set_tls (new_env, newtls); + } /* Grab a mutex so that thread setup appears atomic. */ pthread_mutex_lock(&clone_lock); @@ -6007,10 +6128,12 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, pthread_mutex_lock(&info.mutex); pthread_cond_init(&info.cond, NULL); info.env = new_env; - if (nptl_flags & CLONE_CHILD_SETTID) + if (flags & CLONE_CHILD_SETTID) { info.child_tidptr = child_tidptr; - if (nptl_flags & CLONE_PARENT_SETTID) + } + if (flags & CLONE_PARENT_SETTID) { info.parent_tidptr = parent_tidptr; + } ret = pthread_attr_init(&attr); ret = pthread_attr_setstacksize(&attr, NEW_STACK_SIZE); @@ -6029,8 +6152,6 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, /* Wait for the child to initialize. */ pthread_cond_wait(&info.cond, &info.mutex); ret = info.tid; - if (flags & CLONE_PARENT_SETTID) - put_user_u32(ret, parent_tidptr); } else { ret = -1; } @@ -6040,7 +6161,12 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, pthread_mutex_unlock(&clone_lock); } else { /* if no CLONE_VM, we consider it is a fork */ - if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0) { + if (flags & CLONE_INVALID_FORK_FLAGS) { + return -TARGET_EINVAL; + } + + /* We can't support custom termination signals */ + if ((flags & CSIGNAL) != TARGET_SIGCHLD) { return -TARGET_EINVAL; } @@ -8565,24 +8691,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #if defined(TARGET_NR_select) case TARGET_NR_select: -#if defined(TARGET_S390X) || defined(TARGET_ALPHA) - ret = do_select(arg1, arg2, arg3, arg4, arg5); +#if defined(TARGET_WANT_NI_OLD_SELECT) + /* some architectures used to have old_select here + * but now ENOSYS it. + */ + ret = -TARGET_ENOSYS; +#elif defined(TARGET_WANT_OLD_SYS_SELECT) + ret = do_old_select(arg1); #else - { - struct target_sel_arg_struct *sel; - abi_ulong inp, outp, exp, tvp; - long nsel; - - if (!lock_user_struct(VERIFY_READ, sel, arg1, 1)) - goto efault; - nsel = tswapal(sel->n); - inp = tswapal(sel->inp); - outp = tswapal(sel->outp); - exp = tswapal(sel->exp); - tvp = tswapal(sel->tvp); - unlock_user_struct(sel, arg1, 0); - ret = do_select(nsel, inp, outp, exp, tvp); - } + ret = do_select(arg1, arg2, arg3, arg4, arg5); #endif break; #endif @@ -9292,8 +9409,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #ifdef TARGET_NR_ipc case TARGET_NR_ipc: - ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6); - break; + ret = do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); + break; #endif #ifdef TARGET_NR_semget case TARGET_NR_semget: @@ -9342,7 +9459,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_shmat case TARGET_NR_shmat: - ret = do_shmat(arg1, arg2, arg3); + ret = do_shmat(cpu_env, arg1, arg2, arg3); break; #endif #ifdef TARGET_NR_shmdt @@ -9654,6 +9771,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, pfd = NULL; target_pfd = NULL; if (nfds) { + if (nfds > (INT_MAX / sizeof(struct target_pollfd))) { + ret = -TARGET_EINVAL; + break; + } + target_pfd = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_pollfd) * nfds, 1); if (!target_pfd) { @@ -10527,7 +10649,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, info.si_code = si_code; info._sifields._sigfault._addr = ((CPUArchState *)cpu_env)->pc; - queue_signal((CPUArchState *)cpu_env, info.si_signo, &info); + queue_signal((CPUArchState *)cpu_env, info.si_signo, + QEMU_SI_FAULT, &info); } } break; @@ -11259,6 +11382,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_mq_unlink: p = lock_user_string(arg1 - 1); + if (!p) { + ret = -TARGET_EFAULT; + break; + } ret = get_errno(mq_unlink(p)); unlock_user (p, arg1, 0); break; @@ -11494,6 +11621,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, int maxevents = arg3; int timeout = arg4; + if (maxevents <= 0 || maxevents > TARGET_EP_MAX_EVENTS) { + ret = -TARGET_EINVAL; + break; + } + target_ep = lock_user(VERIFY_WRITE, arg2, maxevents * sizeof(struct target_epoll_event), 1); if (!target_ep) { @@ -11606,7 +11738,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, info.si_errno = 0; info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = arg6; - queue_signal((CPUArchState *)cpu_env, info.si_signo, &info); + queue_signal((CPUArchState *)cpu_env, info.si_signo, + QEMU_SI_FAULT, &info); ret = 0xdeadbeef; } diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index c0c9b5887c..5c19c5ca19 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -998,6 +998,12 @@ struct target_pollfd { #define TARGET_FIBMAP TARGET_IO(0x00,1) /* bmap access */ #define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */ +/* Note that the ioctl numbers claim type "long" but the actual type + * used by the kernel is "int". + */ +#define TARGET_FS_IOC_GETFLAGS TARGET_IOR('f', 1, long) +#define TARGET_FS_IOC_SETFLAGS TARGET_IOW('f', 2, long) + #define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap) /* cdrom commands */ @@ -2579,6 +2585,9 @@ struct target_epoll_event { abi_uint events; target_epoll_data_t data; } TARGET_EPOLL_PACKED; + +#define TARGET_EP_MAX_EVENTS (INT_MAX / sizeof(struct target_epoll_event)) + #endif struct target_rlimit64 { uint64_t rlim_cur; diff --git a/linux-user/tilegx/syscall_nr.h b/linux-user/tilegx/syscall_nr.h index 8e30cd1ae9..c104b94230 100644 --- a/linux-user/tilegx/syscall_nr.h +++ b/linux-user/tilegx/syscall_nr.h @@ -311,7 +311,6 @@ #define TARGET_NR_creat 1064 #define TARGET_NR_getdents 1065 #define TARGET_NR_futimesat 1066 -#define TARGET_NR_select 1067 #define TARGET_NR_poll 1068 #define TARGET_NR_epoll_wait 1069 #define TARGET_NR_ustat 1070 diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 7e95b2da79..f054599a91 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -45,6 +45,12 @@ STEXI @item convert [--object @var{objectdef}] [--image-opts] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} ETEXI +DEF("dd", img_dd, + "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] if=input of=output") +STEXI +@item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] if=@var{input} of=@var{output} +ETEXI + DEF("info", img_info, "info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] filename") STEXI diff --git a/qemu-img.c b/qemu-img.c index ea52486e81..ceffefeacb 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -166,7 +166,15 @@ static void QEMU_NORETURN help(void) "Parameters to compare subcommand:\n" " '-f' first image format\n" " '-F' second image format\n" - " '-s' run in Strict mode - fail on different image size or sector allocation\n"; + " '-s' run in Strict mode - fail on different image size or sector allocation\n" + "\n" + "Parameters to dd subcommand:\n" + " 'bs=BYTES' read and write up to BYTES bytes at a time " + "(default: 512)\n" + " 'count=N' copy only N input blocks\n" + " 'if=FILE' read from FILE\n" + " 'of=FILE' write to FILE\n" + " 'skip=N' skip N bs-sized blocks at the start of input\n"; printf("%s\nSupported formats:", help_msg); bdrv_iterate_format(format_print, NULL); @@ -3796,6 +3804,339 @@ out: return 0; } +#define C_BS 01 +#define C_COUNT 02 +#define C_IF 04 +#define C_OF 010 +#define C_SKIP 020 + +struct DdInfo { + unsigned int flags; + int64_t count; +}; + +struct DdIo { + int bsz; /* Block size */ + char *filename; + uint8_t *buf; + int64_t offset; +}; + +struct DdOpts { + const char *name; + int (*f)(const char *, struct DdIo *, struct DdIo *, struct DdInfo *); + unsigned int flag; +}; + +static int img_dd_bs(const char *arg, + struct DdIo *in, struct DdIo *out, + struct DdInfo *dd) +{ + char *end; + int64_t res; + + res = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B); + + if (res <= 0 || res > INT_MAX || *end) { + error_report("invalid number: '%s'", arg); + return 1; + } + in->bsz = out->bsz = res; + + return 0; +} + +static int img_dd_count(const char *arg, + struct DdIo *in, struct DdIo *out, + struct DdInfo *dd) +{ + char *end; + + dd->count = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B); + + if (dd->count < 0 || *end) { + error_report("invalid number: '%s'", arg); + return 1; + } + + return 0; +} + +static int img_dd_if(const char *arg, + struct DdIo *in, struct DdIo *out, + struct DdInfo *dd) +{ + in->filename = g_strdup(arg); + + return 0; +} + +static int img_dd_of(const char *arg, + struct DdIo *in, struct DdIo *out, + struct DdInfo *dd) +{ + out->filename = g_strdup(arg); + + return 0; +} + +static int img_dd_skip(const char *arg, + struct DdIo *in, struct DdIo *out, + struct DdInfo *dd) +{ + char *end; + + in->offset = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B); + + if (in->offset < 0 || *end) { + error_report("invalid number: '%s'", arg); + return 1; + } + + return 0; +} + +static int img_dd(int argc, char **argv) +{ + int ret = 0; + char *arg = NULL; + char *tmp; + BlockDriver *drv = NULL, *proto_drv = NULL; + BlockBackend *blk1 = NULL, *blk2 = NULL; + QemuOpts *opts = NULL; + QemuOptsList *create_opts = NULL; + Error *local_err = NULL; + bool image_opts = false; + int c, i; + const char *out_fmt = "raw"; + const char *fmt = NULL; + int64_t size = 0; + int64_t block_count = 0, out_pos, in_pos; + struct DdInfo dd = { + .flags = 0, + .count = 0, + }; + struct DdIo in = { + .bsz = 512, /* Block size is by default 512 bytes */ + .filename = NULL, + .buf = NULL, + .offset = 0 + }; + struct DdIo out = { + .bsz = 512, + .filename = NULL, + .buf = NULL, + .offset = 0 + }; + + const struct DdOpts options[] = { + { "bs", img_dd_bs, C_BS }, + { "count", img_dd_count, C_COUNT }, + { "if", img_dd_if, C_IF }, + { "of", img_dd_of, C_OF }, + { "skip", img_dd_skip, C_SKIP }, + { NULL, NULL, 0 } + }; + const struct option long_options[] = { + { "help", no_argument, 0, 'h'}, + { "image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, + { 0, 0, 0, 0 } + }; + + while ((c = getopt_long(argc, argv, "hf:O:", long_options, NULL))) { + if (c == EOF) { + break; + } + switch (c) { + case 'O': + out_fmt = optarg; + break; + case 'f': + fmt = optarg; + break; + case '?': + error_report("Try 'qemu-img --help' for more information."); + ret = -1; + goto out; + case 'h': + help(); + break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; + } + } + + for (i = optind; i < argc; i++) { + int j; + arg = g_strdup(argv[i]); + + tmp = strchr(arg, '='); + if (tmp == NULL) { + error_report("unrecognized operand %s", arg); + ret = -1; + goto out; + } + + *tmp++ = '\0'; + + for (j = 0; options[j].name != NULL; j++) { + if (!strcmp(arg, options[j].name)) { + break; + } + } + if (options[j].name == NULL) { + error_report("unrecognized operand %s", arg); + ret = -1; + goto out; + } + + if (options[j].f(tmp, &in, &out, &dd) != 0) { + ret = -1; + goto out; + } + dd.flags |= options[j].flag; + g_free(arg); + arg = NULL; + } + + if (!(dd.flags & C_IF && dd.flags & C_OF)) { + error_report("Must specify both input and output files"); + ret = -1; + goto out; + } + blk1 = img_open(image_opts, in.filename, fmt, 0, false, false); + + if (!blk1) { + ret = -1; + goto out; + } + + drv = bdrv_find_format(out_fmt); + if (!drv) { + error_report("Unknown file format"); + ret = -1; + goto out; + } + proto_drv = bdrv_find_protocol(out.filename, true, &local_err); + + if (!proto_drv) { + error_report_err(local_err); + ret = -1; + goto out; + } + if (!drv->create_opts) { + error_report("Format driver '%s' does not support image creation", + drv->format_name); + ret = -1; + goto out; + } + if (!proto_drv->create_opts) { + error_report("Protocol driver '%s' does not support image creation", + proto_drv->format_name); + ret = -1; + goto out; + } + create_opts = qemu_opts_append(create_opts, drv->create_opts); + create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); + + opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); + + size = blk_getlength(blk1); + if (size < 0) { + error_report("Failed to get size for '%s'", in.filename); + ret = -1; + goto out; + } + + if (dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz && + dd.count * in.bsz < size) { + size = dd.count * in.bsz; + } + + /* Overflow means the specified offset is beyond input image's size */ + if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz || + size < in.bsz * in.offset)) { + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort); + } else { + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, + size - in.bsz * in.offset, &error_abort); + } + + ret = bdrv_create(drv, out.filename, opts, &local_err); + if (ret < 0) { + error_reportf_err(local_err, + "%s: error while creating output image: ", + out.filename); + ret = -1; + goto out; + } + + blk2 = img_open(image_opts, out.filename, out_fmt, BDRV_O_RDWR, + false, false); + + if (!blk2) { + ret = -1; + goto out; + } + + if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz || + size < in.offset * in.bsz)) { + /* We give a warning if the skip option is bigger than the input + * size and create an empty output disk image (i.e. like dd(1)). + */ + error_report("%s: cannot skip to specified offset", in.filename); + in_pos = size; + } else { + in_pos = in.offset * in.bsz; + } + + in.buf = g_new(uint8_t, in.bsz); + + for (out_pos = 0; in_pos < size; block_count++) { + int in_ret, out_ret; + + if (in_pos + in.bsz > size) { + in_ret = blk_pread(blk1, in_pos, in.buf, size - in_pos); + } else { + in_ret = blk_pread(blk1, in_pos, in.buf, in.bsz); + } + if (in_ret < 0) { + error_report("error while reading from input image file: %s", + strerror(-in_ret)); + ret = -1; + goto out; + } + in_pos += in_ret; + + out_ret = blk_pwrite(blk2, out_pos, in.buf, in_ret, 0); + + if (out_ret < 0) { + error_report("error while writing to output image file: %s", + strerror(-out_ret)); + ret = -1; + goto out; + } + out_pos += out_ret; + } + +out: + g_free(arg); + qemu_opts_del(opts); + qemu_opts_free(create_opts); + blk_unref(blk1); + blk_unref(blk2); + g_free(in.filename); + g_free(out.filename); + g_free(in.buf); + g_free(out.buf); + + if (ret) { + return 1; + } + return 0; +} + static const img_cmd_t img_cmds[] = { #define DEF(option, callback, arg_string) \ diff --git a/qemu-img.texi b/qemu-img.texi index 449a19c710..174aae38b7 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -139,6 +139,22 @@ Parameters to convert subcommand: Skip the creation of the target volume @end table +Parameters to dd subcommand: + +@table @option + +@item bs=@var{block_size} +defines the block size +@item count=@var{blocks} +sets the number of input blocks to copy +@item if=@var{input} +sets the input file +@item of=@var{output} +sets the output file +@item skip=@var{blocks} +sets the number of input blocks to skip +@end table + Command description: @table @option @@ -310,6 +326,17 @@ skipped. This is useful for formats such as @code{rbd} if the target volume has already been created with site specific options that cannot be supplied through qemu-img. +@item dd [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] if=@var{input} of=@var{output} + +Dd copies from @var{input} file to @var{output} file converting it from +@var{fmt} format to @var{output_fmt} format. + +The data is by default read and written using blocks of 512 bytes but can be +modified by specifying @var{block_size}. If count=@var{blocks} is specified +dd will stop reading input after reading @var{blocks} input blocks. + +The size syntax is similar to dd(1)'s size syntax. + @item info [-f @var{fmt}] [--output=@var{ofmt}] [--backing-chain] @var{filename} Give information about the disk image @var{filename}. Use it in diff --git a/qemu-seccomp.c b/qemu-seccomp.c index cb569dc058..df75d9c471 100644 --- a/qemu-seccomp.c +++ b/qemu-seccomp.c @@ -65,6 +65,7 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { { SCMP_SYS(prctl), 245 }, { SCMP_SYS(signalfd), 245 }, { SCMP_SYS(getrlimit), 245 }, + { SCMP_SYS(getrusage), 245 }, { SCMP_SYS(set_tid_address), 245 }, { SCMP_SYS(statfs), 245 }, { SCMP_SYS(unlink), 245 }, diff --git a/scripts/modules/module_block.py b/scripts/modules/module_block.py new file mode 100644 index 0000000000..db4fb540cd --- /dev/null +++ b/scripts/modules/module_block.py @@ -0,0 +1,108 @@ +#!/usr/bin/python +# +# Module information generator +# +# Copyright Red Hat, Inc. 2015 - 2016 +# +# Authors: +# Marc Mari <markmb@redhat.com> +# +# This work is licensed under the terms of the GNU GPL, version 2. +# See the COPYING file in the top-level directory. + +from __future__ import print_function +import sys +import os + +def get_string_struct(line): + data = line.split() + + # data[0] -> struct element name + # data[1] -> = + # data[2] -> value + + return data[2].replace('"', '')[:-1] + +def add_module(fheader, library, format_name, protocol_name): + lines = [] + lines.append('.library_name = "' + library + '",') + if format_name != "": + lines.append('.format_name = "' + format_name + '",') + if protocol_name != "": + lines.append('.protocol_name = "' + protocol_name + '",') + + text = '\n '.join(lines) + fheader.write('\n {\n ' + text + '\n },') + +def process_file(fheader, filename): + # This parser assumes the coding style rules are being followed + with open(filename, "r") as cfile: + found_something = False + found_start = False + library, _ = os.path.splitext(os.path.basename(filename)) + for line in cfile: + if found_start: + line = line.replace('\n', '') + if line.find(".format_name") != -1: + format_name = get_string_struct(line) + elif line.find(".protocol_name") != -1: + protocol_name = get_string_struct(line) + elif line == "};": + add_module(fheader, library, format_name, protocol_name) + found_start = False + elif line.find("static BlockDriver") != -1: + found_something = True + found_start = True + format_name = "" + protocol_name = "" + + if not found_something: + print("No BlockDriver struct found in " + filename + ". \ + Is this really a module?", file=sys.stderr) + sys.exit(1) + +def print_top(fheader): + fheader.write('''/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ +/* + * QEMU Block Module Infrastructure + * + * Authors: + * Marc Mari <markmb@redhat.com> + */ + +''') + + fheader.write('''#ifndef QEMU_MODULE_BLOCK_H +#define QEMU_MODULE_BLOCK_H + +#include "qemu-common.h" + +static const struct { + const char *format_name; + const char *protocol_name; + const char *library_name; +} block_driver_modules[] = {''') + +def print_bottom(fheader): + fheader.write(''' +}; + +#endif +''') + +# First argument: output file +# All other arguments: modules source files (.c) +output_file = sys.argv[1] +with open(output_file, 'w') as fheader: + print_top(fheader) + + for filename in sys.argv[2:]: + if os.path.isfile(filename): + process_file(fheader, filename) + else: + print("File " + filename + " does not exist.", file=sys.stderr) + sys.exit(1) + + print_bottom(fheader) + +sys.exit(0) diff --git a/stubs/vmstate.c b/stubs/vmstate.c index 65906271d2..94b831e219 100644 --- a/stubs/vmstate.c +++ b/stubs/vmstate.c @@ -3,6 +3,11 @@ #include "migration/vmstate.h" const VMStateDescription vmstate_dummy = {}; +const VMStateInfo vmstate_info_uint8; +const VMStateInfo vmstate_info_uint32; +const VMStateInfo vmstate_info_uint64; +const VMStateInfo vmstate_info_int64; +const VMStateInfo vmstate_info_timer; int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, diff --git a/target-arm/cpu.c b/target-arm/cpu.c index ce8b8f4a5b..1b9540e085 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -1129,6 +1129,51 @@ static const ARMCPRegInfo cortexa15_cp_reginfo[] = { REGINFO_SENTINEL }; +static void cortex_a7_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a7"; + set_feature(&cpu->env, ARM_FEATURE_V7); + set_feature(&cpu->env, ARM_FEATURE_VFP4); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); + set_feature(&cpu->env, ARM_FEATURE_ARM_DIV); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_LPAE); + set_feature(&cpu->env, ARM_FEATURE_EL3); + cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7; + cpu->midr = 0x410fc075; + cpu->reset_fpsid = 0x41023075; + cpu->mvfr0 = 0x10110222; + cpu->mvfr1 = 0x11111111; + cpu->ctr = 0x84448003; + cpu->reset_sctlr = 0x00c50078; + cpu->id_pfr0 = 0x00001131; + cpu->id_pfr1 = 0x00011011; + cpu->id_dfr0 = 0x02010555; + cpu->pmceid0 = 0x00000000; + cpu->pmceid1 = 0x00000000; + cpu->id_afr0 = 0x00000000; + cpu->id_mmfr0 = 0x10101105; + cpu->id_mmfr1 = 0x40000000; + cpu->id_mmfr2 = 0x01240000; + cpu->id_mmfr3 = 0x02102211; + cpu->id_isar0 = 0x01101110; + cpu->id_isar1 = 0x13112111; + cpu->id_isar2 = 0x21232041; + cpu->id_isar3 = 0x11112131; + cpu->id_isar4 = 0x10011142; + cpu->dbgdidr = 0x3515f005; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */ + cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */ + define_arm_cp_regs(cpu, cortexa15_cp_reginfo); /* Same as A15 */ +} + static void cortex_a15_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -1385,6 +1430,7 @@ static const ARMCPUInfo arm_cpus[] = { { .name = "cortex-m4", .initfn = cortex_m4_initfn, .class_init = arm_v7m_class_init }, { .name = "cortex-r5", .initfn = cortex_r5_initfn }, + { .name = "cortex-a7", .initfn = cortex_a7_initfn }, { .name = "cortex-a8", .initfn = cortex_a8_initfn }, { .name = "cortex-a9", .initfn = cortex_a9_initfn }, { .name = "cortex-a15", .initfn = cortex_a15_initfn }, diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c index cf7536bd52..eeb1777bbb 100644 --- a/tcg/i386/tcg-target.inc.c +++ b/tcg/i386/tcg-target.inc.c @@ -1243,7 +1243,7 @@ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi, } else { tcg_out_modrm_offset(s, OPC_LEA + trexw, r1, addrlo, s_mask - a_mask); } - tlb_mask = TARGET_PAGE_MASK | a_mask; + tlb_mask = (target_ulong)TARGET_PAGE_MASK | a_mask; tcg_out_shifti(s, SHIFT_SHR + tlbrexw, r0, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); diff --git a/tests/Makefile.include b/tests/Makefile.include index 6052a3828f..1fb3866a99 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -296,6 +296,7 @@ check-qtest-xtensaeb-y = $(check-qtest-xtensa-y) check-qtest-s390x-y = tests/boot-serial-test$(EXESUF) check-qtest-generic-y += tests/qom-test$(EXESUF) +check-qtest-generic-y += tests/ptimer-test$(EXESUF) qapi-schema += alternate-any.json qapi-schema += alternate-array.json @@ -658,6 +659,7 @@ tests/test-filter-mirror$(EXESUF): tests/test-filter-mirror.o $(qtest-obj-y) tests/test-filter-redirector$(EXESUF): tests/test-filter-redirector.o $(qtest-obj-y) tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y) tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o +tests/ptimer-test$(EXESUF): tests/ptimer-test.o tests/ptimer-test-stubs.o hw/core/ptimer.o tests/migration/stress$(EXESUF): tests/migration/stress.o $(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ," LINK $(TARGET_DIR)$@") diff --git a/tests/ptimer-test-stubs.c b/tests/ptimer-test-stubs.c new file mode 100644 index 0000000000..92a22fbb09 --- /dev/null +++ b/tests/ptimer-test-stubs.c @@ -0,0 +1,107 @@ +/* + * Stubs for the ptimer-test + * + * Author: Dmitry Osipenko <digetx@gmail.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "sysemu/replay.h" + +#include "ptimer-test.h" + +struct QEMUBH { + QEMUBHFunc *cb; + void *opaque; +}; + +QEMUTimerListGroup main_loop_tlg; + +int64_t ptimer_test_time_ns; + +void timer_init_tl(QEMUTimer *ts, + QEMUTimerList *timer_list, int scale, + QEMUTimerCB *cb, void *opaque) +{ + ts->timer_list = timer_list; + ts->cb = cb; + ts->opaque = opaque; + ts->scale = scale; + ts->expire_time = -1; +} + +void timer_mod(QEMUTimer *ts, int64_t expire_time) +{ + QEMUTimerList *timer_list = ts->timer_list; + QEMUTimer *t = &timer_list->active_timers; + + while (t->next != NULL) { + if (t->next == ts) { + break; + } + + t = t->next; + } + + ts->expire_time = MAX(expire_time * ts->scale, 0); + ts->next = NULL; + t->next = ts; +} + +void timer_del(QEMUTimer *ts) +{ + QEMUTimerList *timer_list = ts->timer_list; + QEMUTimer *t = &timer_list->active_timers; + + while (t->next != NULL) { + if (t->next == ts) { + t->next = ts->next; + return; + } + + t = t->next; + } +} + +int64_t qemu_clock_get_ns(QEMUClockType type) +{ + return ptimer_test_time_ns; +} + +int64_t qemu_clock_deadline_ns_all(QEMUClockType type) +{ + QEMUTimerList *timer_list = main_loop_tlg.tl[type]; + QEMUTimer *t = timer_list->active_timers.next; + int64_t deadline = -1; + + while (t != NULL) { + if (deadline == -1) { + deadline = t->expire_time; + } else { + deadline = MIN(deadline, t->expire_time); + } + + t = t->next; + } + + return deadline; +} + +QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque) +{ + QEMUBH *bh = g_new(QEMUBH, 1); + + bh->cb = cb; + bh->opaque = opaque; + + return bh; +} + +void replay_bh_schedule_event(QEMUBH *bh) +{ + bh->cb(bh->opaque); +} diff --git a/tests/ptimer-test.c b/tests/ptimer-test.c new file mode 100644 index 0000000000..f207eeb0eb --- /dev/null +++ b/tests/ptimer-test.c @@ -0,0 +1,568 @@ +/* + * QTest testcase for the ptimer + * + * Author: Dmitry Osipenko <digetx@gmail.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include <glib/gprintf.h> + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "hw/ptimer.h" + +#include "libqtest.h" +#include "ptimer-test.h" + +static bool triggered; + +static void ptimer_trigger(void *opaque) +{ + triggered = true; +} + +static void ptimer_test_expire_qemu_timers(int64_t expire_time, + QEMUClockType type) +{ + QEMUTimerList *timer_list = main_loop_tlg.tl[type]; + QEMUTimer *t = timer_list->active_timers.next; + + while (t != NULL) { + if (t->expire_time == expire_time) { + timer_del(t); + + if (t->cb != NULL) { + t->cb(t->opaque); + } + } + + t = t->next; + } +} + +static void ptimer_test_set_qemu_time_ns(int64_t ns) +{ + ptimer_test_time_ns = ns; +} + +static void qemu_clock_step(uint64_t ns) +{ + int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + int64_t advanced_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns; + + while (deadline != -1 && deadline <= advanced_time) { + ptimer_test_set_qemu_time_ns(deadline); + ptimer_test_expire_qemu_timers(deadline, QEMU_CLOCK_VIRTUAL); + deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + } + + ptimer_test_set_qemu_time_ns(advanced_time); +} + +static void check_set_count(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_count(ptimer, 1000); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 1000); + g_assert_false(triggered); +} + +static void check_set_limit(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_limit(ptimer, 1000, 0); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_cmpuint(ptimer_get_limit(ptimer), ==, 1000); + g_assert_false(triggered); + + ptimer_set_limit(ptimer, 2000, 1); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 2000); + g_assert_cmpuint(ptimer_get_limit(ptimer), ==, 2000); + g_assert_false(triggered); +} + +static void check_oneshot(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_period(ptimer, 2000000); + ptimer_set_count(ptimer, 10); + ptimer_run(ptimer, 1); + + qemu_clock_step(2000000 * 2 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7); + g_assert_false(triggered); + + ptimer_stop(ptimer); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7); + g_assert_false(triggered); + + qemu_clock_step(2000000 * 11); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7); + g_assert_false(triggered); + + ptimer_run(ptimer, 1); + + qemu_clock_step(2000000 * 7 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + qemu_clock_step(4000000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + ptimer_set_count(ptimer, 10); + + qemu_clock_step(20000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 10); + g_assert_false(triggered); + + ptimer_set_limit(ptimer, 9, 1); + + qemu_clock_step(20000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9); + g_assert_false(triggered); + + ptimer_run(ptimer, 1); + + qemu_clock_step(2000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7); + g_assert_false(triggered); + + ptimer_set_count(ptimer, 20); + + qemu_clock_step(2000000 * 19 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + qemu_clock_step(2000000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); + + ptimer_stop(ptimer); + + triggered = false; + + qemu_clock_step(2000000 * 12 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); +} + +static void check_periodic(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_period(ptimer, 2000000); + ptimer_set_limit(ptimer, 10, 1); + ptimer_run(ptimer, 0); + + qemu_clock_step(2000000 * 10 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8); + g_assert_false(triggered); + + ptimer_set_count(ptimer, 20); + + qemu_clock_step(2000000 * 11 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8); + g_assert_false(triggered); + + qemu_clock_step(2000000 * 10); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8); + g_assert_true(triggered); + + ptimer_stop(ptimer); + triggered = false; + + qemu_clock_step(2000000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8); + g_assert_false(triggered); + + ptimer_set_count(ptimer, 3); + ptimer_run(ptimer, 0); + + qemu_clock_step(2000000 * 3 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8); + g_assert_false(triggered); + + ptimer_set_count(ptimer, 0); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 10); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000 * 12 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7); + g_assert_true(triggered); + + ptimer_stop(ptimer); + + triggered = false; + + qemu_clock_step(2000000 * 12 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7); + g_assert_false(triggered); + + ptimer_run(ptimer, 0); + ptimer_set_period(ptimer, 0); + + qemu_clock_step(2000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7); + g_assert_false(triggered); +} + +static void check_on_the_fly_mode_change(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_period(ptimer, 2000000); + ptimer_set_limit(ptimer, 10, 1); + ptimer_run(ptimer, 1); + + qemu_clock_step(2000000 * 9 + 100000); + + ptimer_run(ptimer, 0); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + qemu_clock_step(2000000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000 * 9); + + ptimer_run(ptimer, 1); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + qemu_clock_step(2000000 * 3); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); +} + +static void check_on_the_fly_period_change(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_period(ptimer, 2000000); + ptimer_set_limit(ptimer, 8, 1); + ptimer_run(ptimer, 1); + + qemu_clock_step(2000000 * 4 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3); + g_assert_false(triggered); + + ptimer_set_period(ptimer, 4000000); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3); + + qemu_clock_step(4000000 * 2 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + qemu_clock_step(4000000 * 2); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); +} + +static void check_on_the_fly_freq_change(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_freq(ptimer, 500); + ptimer_set_limit(ptimer, 8, 1); + ptimer_run(ptimer, 1); + + qemu_clock_step(2000000 * 4 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3); + g_assert_false(triggered); + + ptimer_set_freq(ptimer, 250); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3); + + qemu_clock_step(2000000 * 4 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + qemu_clock_step(2000000 * 4); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); +} + +static void check_run_with_period_0(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_count(ptimer, 99); + ptimer_run(ptimer, 1); + + qemu_clock_step(10 * NANOSECONDS_PER_SECOND); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 99); + g_assert_false(triggered); +} + +static void check_run_with_delta_0(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_period(ptimer, 2000000); + ptimer_set_limit(ptimer, 99, 0); + ptimer_run(ptimer, 1); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 99); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 97); + g_assert_false(triggered); + + qemu_clock_step(2000000 * 97); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + qemu_clock_step(2000000 * 2); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); + + triggered = false; + + ptimer_set_count(ptimer, 0); + ptimer_run(ptimer, 0); + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 99); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 97); + g_assert_false(triggered); + + qemu_clock_step(2000000 * 98); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 98); + g_assert_true(triggered); + + ptimer_stop(ptimer); +} + +static void check_periodic_with_load_0(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_period(ptimer, 2000000); + ptimer_run(ptimer, 0); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + ptimer_stop(ptimer); +} + +static void check_oneshot_with_load_0(gconstpointer arg) +{ + const uint8_t *policy = arg; + QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL); + ptimer_state *ptimer = ptimer_init(bh, *policy); + + triggered = false; + + ptimer_set_period(ptimer, 2000000); + ptimer_run(ptimer, 1); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_true(triggered); + + triggered = false; + + qemu_clock_step(2000000 + 100000); + + g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0); + g_assert_false(triggered); + + triggered = false; + + qemu_clock_step(2000000 + 100000); + + g_assert_false(triggered); +} + +static void add_ptimer_tests(uint8_t policy) +{ + uint8_t *ppolicy = g_malloc(1); + char *policy_name = g_malloc(64); + + *ppolicy = policy; + + if (policy == PTIMER_POLICY_DEFAULT) { + g_sprintf(policy_name, "default"); + } + + qtest_add_data_func( + g_strdup_printf("/ptimer/set_count policy=%s", policy_name), + ppolicy, check_set_count); + + qtest_add_data_func( + g_strdup_printf("/ptimer/set_limit policy=%s", policy_name), + ppolicy, check_set_limit); + + qtest_add_data_func( + g_strdup_printf("/ptimer/oneshot policy=%s", policy_name), + ppolicy, check_oneshot); + + qtest_add_data_func( + g_strdup_printf("/ptimer/periodic policy=%s", policy_name), + ppolicy, check_periodic); + + qtest_add_data_func( + g_strdup_printf("/ptimer/on_the_fly_mode_change policy=%s", policy_name), + ppolicy, check_on_the_fly_mode_change); + + qtest_add_data_func( + g_strdup_printf("/ptimer/on_the_fly_period_change policy=%s", policy_name), + ppolicy, check_on_the_fly_period_change); + + qtest_add_data_func( + g_strdup_printf("/ptimer/on_the_fly_freq_change policy=%s", policy_name), + ppolicy, check_on_the_fly_freq_change); + + qtest_add_data_func( + g_strdup_printf("/ptimer/run_with_period_0 policy=%s", policy_name), + ppolicy, check_run_with_period_0); + + qtest_add_data_func( + g_strdup_printf("/ptimer/run_with_delta_0 policy=%s", policy_name), + ppolicy, check_run_with_delta_0); + + qtest_add_data_func( + g_strdup_printf("/ptimer/periodic_with_load_0 policy=%s", policy_name), + ppolicy, check_periodic_with_load_0); + + qtest_add_data_func( + g_strdup_printf("/ptimer/oneshot_with_load_0 policy=%s", policy_name), + ppolicy, check_oneshot_with_load_0); +} + +int main(int argc, char **argv) +{ + int i; + + g_test_init(&argc, &argv, NULL); + + for (i = 0; i < QEMU_CLOCK_MAX; i++) { + main_loop_tlg.tl[i] = g_new0(QEMUTimerList, 1); + } + + add_ptimer_tests(PTIMER_POLICY_DEFAULT); + + qtest_allowed = true; + + return g_test_run(); +} diff --git a/tests/ptimer-test.h b/tests/ptimer-test.h new file mode 100644 index 0000000000..98d9b8f347 --- /dev/null +++ b/tests/ptimer-test.h @@ -0,0 +1,22 @@ +/* + * QTest testcase for the ptimer + * + * Author: Dmitry Osipenko <digetx@gmail.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef PTIMER_TEST_H +#define PTIMER_TEST_H + +extern bool qtest_allowed; + +extern int64_t ptimer_test_time_ns; + +struct QEMUTimerList { + QEMUTimer active_timers; +}; + +#endif diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055 index ff4535e3ea..1d3fd04b65 100755 --- a/tests/qemu-iotests/055 +++ b/tests/qemu-iotests/055 @@ -29,17 +29,24 @@ test_img = os.path.join(iotests.test_dir, 'test.img') target_img = os.path.join(iotests.test_dir, 'target.img') blockdev_target_img = os.path.join(iotests.test_dir, 'blockdev-target.img') -class TestSingleDrive(iotests.QMPTestCase): - image_len = 64 * 1024 * 1024 # MB +image_len = 64 * 1024 * 1024 # MB + +def setUpModule(): + qemu_img('create', '-f', iotests.imgfmt, test_img, str(image_len)) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x11 0 64k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x00 64k 128k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x22 162k 32k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xd5 1M 32k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 32M 124k', test_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x33 67043328 64k', test_img) +def tearDownModule(): + os.remove(test_img) + + +class TestSingleDrive(iotests.QMPTestCase): def setUp(self): - # Write data to the image so we can compare later - qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleDrive.image_len)) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x5d 0 64k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xd5 1M 32k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 32M 124k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 67043328 64k', test_img) - qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(TestSingleDrive.image_len)) + qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len)) self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img) if iotests.qemu_default_machine == 'pc': @@ -48,7 +55,6 @@ class TestSingleDrive(iotests.QMPTestCase): def tearDown(self): self.vm.shutdown() - os.remove(test_img) os.remove(blockdev_target_img) try: os.remove(target_img) @@ -155,19 +161,14 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_qmp(result, 'error/class', 'GenericError') class TestSetSpeed(iotests.QMPTestCase): - image_len = 80 * 1024 * 1024 # MB - def setUp(self): - qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSetSpeed.image_len)) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P1 0 512', test_img) - qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(TestSingleDrive.image_len)) + qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len)) self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img) self.vm.launch() def tearDown(self): self.vm.shutdown() - os.remove(test_img) os.remove(blockdev_target_img) try: os.remove(target_img) @@ -243,15 +244,8 @@ class TestSetSpeed(iotests.QMPTestCase): self.do_test_set_speed_invalid('blockdev-backup', 'drive1') class TestSingleTransaction(iotests.QMPTestCase): - image_len = 64 * 1024 * 1024 # MB - def setUp(self): - qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleTransaction.image_len)) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x5d 0 64k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xd5 1M 32k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 32M 124k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 67043328 64k', test_img) - qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(TestSingleDrive.image_len)) + qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len)) self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img) if iotests.qemu_default_machine == 'pc': @@ -260,7 +254,6 @@ class TestSingleTransaction(iotests.QMPTestCase): def tearDown(self): self.vm.shutdown() - os.remove(test_img) os.remove(blockdev_target_img) try: os.remove(target_img) @@ -454,17 +447,8 @@ class TestDriveCompression(iotests.QMPTestCase): fmt_supports_compression = [{'type': 'qcow2', 'args': ()}, {'type': 'vmdk', 'args': ('-o', 'subformat=streamOptimized')}] - def setUp(self): - # Write data to the image so we can compare later - qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestDriveCompression.image_len)) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x11 0 64k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x00 64k 128k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x22 162k 32k', test_img) - qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x33 67043328 64k', test_img) - def tearDown(self): self.vm.shutdown() - os.remove(test_img) os.remove(blockdev_target_img) try: os.remove(target_img) diff --git a/tests/qemu-iotests/159 b/tests/qemu-iotests/159 new file mode 100755 index 0000000000..825f05fab8 --- /dev/null +++ b/tests/qemu-iotests/159 @@ -0,0 +1,70 @@ +#! /bin/bash +# +# qemu-img dd test with different block sizes +# +# Copyright (C) 2016 Reda Sallahi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +owner=fullmanet@gmail.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +status=1 + +_cleanup() +{ + _cleanup_test_img + rm -f "$TEST_IMG.out" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +. ./common.rc +. ./common.filter +. ./common.pattern + +_supported_fmt generic +_supported_proto file +_supported_os Linux + +TEST_SIZES="5 512 1024 1999 1K 64K 1M" + +for bs in $TEST_SIZES; do + echo + echo "== Creating image ==" + + size=1M + _make_test_img $size + _check_test_img + $QEMU_IO -c "write -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io + + echo + echo "== Converting the image with dd with a block size of $bs ==" + + $QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" bs=$bs -O "$IMGFMT" + TEST_IMG="$TEST_IMG.out" _check_test_img + + echo + echo "== Compare the images with qemu-img compare ==" + + $QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.out" +done + +echo +echo "*** done" +rm -f "$seq.full" +status=0 diff --git a/tests/qemu-iotests/159.out b/tests/qemu-iotests/159.out new file mode 100644 index 0000000000..b86b63abe6 --- /dev/null +++ b/tests/qemu-iotests/159.out @@ -0,0 +1,87 @@ +QA output created by 159 + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with a block size of 5 == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with a block size of 512 == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with a block size of 1024 == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with a block size of 1999 == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with a block size of 1K == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with a block size of 64K == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with a block size of 1M == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +*** done diff --git a/tests/qemu-iotests/160 b/tests/qemu-iotests/160 new file mode 100755 index 0000000000..5c910e5bfc --- /dev/null +++ b/tests/qemu-iotests/160 @@ -0,0 +1,72 @@ +#! /bin/bash +# +# qemu-img dd test for the skip option +# +# Copyright (C) 2016 Reda Sallahi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +owner=fullmanet@gmail.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +status=1 + +_cleanup() +{ + _cleanup_test_img + rm -f "$TEST_IMG.out" "$TEST_IMG.out.dd" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +. ./common.rc +. ./common.filter +. ./common.pattern + +_supported_fmt raw +_supported_proto file +_supported_os Linux + +TEST_SKIP_BLOCKS="1 2 30 30K" + +for skip in $TEST_SKIP_BLOCKS; do + echo + echo "== Creating image ==" + + size=1M + _make_test_img $size + _check_test_img + $QEMU_IO -c "write -P 0xa 24 512k" "$TEST_IMG" | _filter_qemu_io + + echo + echo "== Converting the image with dd with skip=$skip ==" + + $QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" skip="$skip" -O "$IMGFMT" \ + 2> /dev/null + TEST_IMG="$TEST_IMG.out" _check_test_img + dd if="$TEST_IMG" of="$TEST_IMG.out.dd" skip="$skip" status=none + + echo + echo "== Compare the images with qemu-img compare ==" + + $QEMU_IMG compare "$TEST_IMG.out.dd" "$TEST_IMG.out" +done + +echo +echo "*** done" +rm -f "$seq.full" +status=0 diff --git a/tests/qemu-iotests/160.out b/tests/qemu-iotests/160.out new file mode 100644 index 0000000000..9cedc80356 --- /dev/null +++ b/tests/qemu-iotests/160.out @@ -0,0 +1,51 @@ +QA output created by 160 + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 524288/524288 bytes at offset 24 +512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with skip=1 == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 524288/524288 bytes at offset 24 +512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with skip=2 == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 524288/524288 bytes at offset 24 +512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with skip=30 == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 524288/524288 bytes at offset 24 +512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd with skip=30K == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +*** done diff --git a/tests/qemu-iotests/170 b/tests/qemu-iotests/170 new file mode 100755 index 0000000000..5b335dbc3e --- /dev/null +++ b/tests/qemu-iotests/170 @@ -0,0 +1,67 @@ +#! /bin/bash +# +# qemu-img dd test +# +# Copyright (C) 2016 Reda Sallahi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +owner=fullmanet@gmail.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +status=1 + +_cleanup() +{ + _cleanup_test_img + rm -f "$TEST_IMG.out" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +. ./common.rc +. ./common.filter +. ./common.pattern + +_supported_fmt generic +_supported_proto file +_supported_os Linux + +echo +echo "== Creating image ==" + +size=1M +_make_test_img $size +_check_test_img + +$QEMU_IO -c "write -P 0xa 0 $size" "$TEST_IMG" | _filter_qemu_io + +echo +echo "== Converting the image with dd ==" + +$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" -O "$IMGFMT" +TEST_IMG="$TEST_IMG.out" _check_test_img + +echo +echo "== Compare the images with qemu-img compare ==" + +$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.out" + +echo +echo "*** done" +rm -f "$seq.full" +status=0 diff --git a/tests/qemu-iotests/170.out b/tests/qemu-iotests/170.out new file mode 100644 index 0000000000..a83fb82fa7 --- /dev/null +++ b/tests/qemu-iotests/170.out @@ -0,0 +1,15 @@ +QA output created by 170 + +== Creating image == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +No errors were found on the image. +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Converting the image with dd == +No errors were found on the image. + +== Compare the images with qemu-img compare == +Images are identical. + +*** done diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 3ab6e4d764..240ed0697a 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -44,6 +44,15 @@ _filter_imgfmt() sed -e "s#$IMGFMT#IMGFMT#g" } +# Replace error message when the format is not supported and delete +# the output lines after the first one +_filter_qemu_img_check() +{ + sed -e '/allocated.*fragmented.*compressed clusters/d' \ + -e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \ + -e '/Image end offset: [0-9]\+/d' +} + # Removes \r from messages _filter_win32() { diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 306b00c210..126bd67043 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -234,10 +234,7 @@ _check_test_img() else $QEMU_IMG check "$@" -f $IMGFMT "$TEST_IMG" 2>&1 fi - ) | _filter_testdir | \ - sed -e '/allocated.*fragmented.*compressed clusters/d' \ - -e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \ - -e '/Image end offset: [0-9]\+/d' + ) | _filter_testdir | _filter_qemu_img_check } _img_info() diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 50ddeed80a..a57fc9218f 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -157,4 +157,7 @@ 155 rw auto 156 rw auto quick 157 auto +159 rw auto quick +160 rw auto quick 162 auto quick +170 rw auto quick diff --git a/util/module.c b/util/module.c index 86e3f7aba0..a5f7fbd941 100644 --- a/util/module.c +++ b/util/module.c @@ -87,14 +87,11 @@ void register_dso_module_init(void (*fn)(void), module_init_type type) QTAILQ_INSERT_TAIL(&dso_init_list, e, node); } -static void module_load(module_init_type type); - void module_call_init(module_init_type type) { ModuleTypeList *l; ModuleEntry *e; - module_load(type); l = find_type(type); QTAILQ_FOREACH(e, l, node) { @@ -145,6 +142,7 @@ static int module_load_file(const char *fname) ret = -EINVAL; } else { QTAILQ_FOREACH(e, &dso_init_list, node) { + e->init(); register_module_init(e->init, e->type); } ret = 0; @@ -159,14 +157,10 @@ out: } #endif -static void module_load(module_init_type type) +void module_load_one(const char *prefix, const char *lib_name) { #ifdef CONFIG_MODULES char *fname = NULL; - const char **mp; - static const char *block_modules[] = { - CONFIG_BLOCK_MODULES - }; char *exec_dir; char *dirs[3]; int i = 0; @@ -177,15 +171,6 @@ static void module_load(module_init_type type) return; } - switch (type) { - case MODULE_INIT_BLOCK: - mp = block_modules; - break; - default: - /* no other types have dynamic modules for now*/ - return; - } - exec_dir = qemu_get_exec_dir(); dirs[i++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR); dirs[i++] = g_strdup_printf("%s/..", exec_dir ? : ""); @@ -194,16 +179,15 @@ static void module_load(module_init_type type) g_free(exec_dir); exec_dir = NULL; - for ( ; *mp; mp++) { - for (i = 0; i < ARRAY_SIZE(dirs); i++) { - fname = g_strdup_printf("%s/%s%s", dirs[i], *mp, HOST_DSOSUF); - ret = module_load_file(fname); - g_free(fname); - fname = NULL; - /* Try loading until loaded a module file */ - if (!ret) { - break; - } + for (i = 0; i < ARRAY_SIZE(dirs); i++) { + fname = g_strdup_printf("%s/%s%s%s", + dirs[i], prefix, lib_name, HOST_DSOSUF); + ret = module_load_file(fname); + g_free(fname); + fname = NULL; + /* Try loading until loaded a module file */ + if (!ret) { + break; } } @@ -507,6 +507,43 @@ static QemuOptsList qemu_fw_cfg_opts = { }, }; +#ifdef CONFIG_LIBISCSI +static QemuOptsList qemu_iscsi_opts = { + .name = "iscsi", + .head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head), + .desc = { + { + .name = "user", + .type = QEMU_OPT_STRING, + .help = "username for CHAP authentication to target", + },{ + .name = "password", + .type = QEMU_OPT_STRING, + .help = "password for CHAP authentication to target", + },{ + .name = "password-secret", + .type = QEMU_OPT_STRING, + .help = "ID of the secret providing password for CHAP " + "authentication to target", + },{ + .name = "header-digest", + .type = QEMU_OPT_STRING, + .help = "HeaderDigest setting. " + "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}", + },{ + .name = "initiator-name", + .type = QEMU_OPT_STRING, + .help = "Initiator iqn name to use when connecting", + },{ + .name = "timeout", + .type = QEMU_OPT_NUMBER, + .help = "Request timeout in seconds (default 0 = no timeout)", + }, + { /* end of list */ } + }, +}; +#endif + /** * Get machine options * @@ -3017,6 +3054,9 @@ int main(int argc, char **argv, char **envp) qemu_add_opts(&qemu_icount_opts); qemu_add_opts(&qemu_semihosting_config_opts); qemu_add_opts(&qemu_fw_cfg_opts); +#ifdef CONFIG_LIBISCSI + qemu_add_opts(&qemu_iscsi_opts); +#endif module_call_init(MODULE_INIT_OPTS); runstate_init(); |