diff options
146 files changed, 4326 insertions, 1459 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 09d13bf..a3a2ad7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -172,6 +172,7 @@ L: qemu-ppc@nongnu.org S: Maintained F: target-ppc/ F: hw/ppc/ +F: include/hw/ppc/ F: disas/ppc.c S390 @@ -574,6 +575,9 @@ L: qemu-ppc@nongnu.org S: Supported F: hw/ppc/e500.[hc] F: hw/ppc/e500plat.c +F: include/hw/ppc/ppc_e500.h +F: include/hw/pci-host/ppce500.h +F: pc-bios/u-boot.e500 mpc8544ds M: Alexander Graf <agraf@suse.de> @@ -591,6 +595,8 @@ F: hw/ppc/mac_newworld.c F: hw/pci-host/uninorth.c F: hw/pci-bridge/dec.[hc] F: hw/misc/macio/ +F: include/hw/ppc/mac_dbdma.h +F: hw/nvram/mac_nvram.c Old World M: Alexander Graf <agraf@suse.de> @@ -618,6 +624,14 @@ F: include/hw/*/spapr* F: hw/*/xics* F: include/hw/*/xics* F: pc-bios/spapr-rtas/* +F: pc-bios/spapr-rtas.bin +F: pc-bios/slof.bin +F: docs/specs/ppc-spapr-hcalls.txt +F: docs/specs/ppc-spapr-hotplug.txt +F: tests/spapr* +F: tests/libqos/*spapr* +F: tests/rtas* +F: tests/libqos/rtas* virtex_ml507 M: Edgar E. Iglesias <edgar.iglesias@gmail.com> @@ -815,6 +829,7 @@ M: Alexander Graf <agraf@suse.de> L: qemu-ppc@nongnu.org S: Odd Fixes F: hw/ppc/ppc4*.c +F: include/hw/ppc/ppc4xx.h ppce500 M: Alexander Graf <agraf@suse.de> @@ -1342,6 +1357,13 @@ F: include/qemu/throttle.h F: util/throttle.c L: qemu-block@nongnu.org +UUID +M: Fam Zheng <famz@redhat.com> +S: Supported +F: util/uuid.c +F: include/qemu/uuid.h +F: tests/test-uuid.c + Usermode Emulation ------------------ Overall diff --git a/arch_init.c b/arch_init.c index fa05973..5cc58b2 100644 --- a/arch_init.c +++ b/arch_init.c @@ -235,25 +235,6 @@ void audio_init(void) } } -int qemu_uuid_parse(const char *str, uint8_t *uuid) -{ - int ret; - - if (strlen(str) != 36) { - return -1; - } - - ret = sscanf(str, UUID_FMT, &uuid[0], &uuid[1], &uuid[2], &uuid[3], - &uuid[4], &uuid[5], &uuid[6], &uuid[7], &uuid[8], &uuid[9], - &uuid[10], &uuid[11], &uuid[12], &uuid[13], &uuid[14], - &uuid[15]); - - if (ret != 16) { - return -1; - } - return 0; -} - void do_acpitable_option(const QemuOpts *opts) { #ifdef TARGET_I386 diff --git a/backends/msmouse.c b/backends/msmouse.c index aceb6dc..85d08f7 100644 --- a/backends/msmouse.c +++ b/backends/msmouse.c @@ -139,7 +139,6 @@ static void msmouse_chr_close (struct CharDriverState *chr) qemu_input_handler_unregister(mouse->hs); g_free(mouse); - g_free(chr); } static QemuInputHandler msmouse_handler = { diff --git a/block/Makefile.objs b/block/Makefile.objs index cb158e9..7d4031d 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -2,7 +2,7 @@ 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 -block-obj-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o +block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o block-obj-y += quorum.o block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o block-obj-y += block-backend.o snapshot.o qapi.o diff --git a/block/iscsi.c b/block/iscsi.c index c4a0937..dff548a 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -36,7 +36,7 @@ #include "block/block_int.h" #include "block/scsi.h" #include "qemu/iov.h" -#include "sysemu/sysemu.h" +#include "qemu/uuid.h" #include "qmp-commands.h" #include "qapi/qmp/qstring.h" #include "crypto/secret.h" @@ -1813,19 +1813,22 @@ static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp) IscsiLun *iscsilun = bs->opaque; uint64_t max_xfer_len = iscsilun->use_16_for_rw ? 0xffffffff : 0xffff; + unsigned int block_size = MAX(BDRV_SECTOR_SIZE, iscsilun->block_size); - bs->bl.request_alignment = iscsilun->block_size; + assert(iscsilun->block_size >= BDRV_SECTOR_SIZE || bs->sg); + + bs->bl.request_alignment = block_size; if (iscsilun->bl.max_xfer_len) { max_xfer_len = MIN(max_xfer_len, iscsilun->bl.max_xfer_len); } - if (max_xfer_len * iscsilun->block_size < INT_MAX) { + if (max_xfer_len * block_size < INT_MAX) { bs->bl.max_transfer = max_xfer_len * iscsilun->block_size; } if (iscsilun->lbp.lbpu) { - if (iscsilun->bl.max_unmap < 0xffffffff / iscsilun->block_size) { + if (iscsilun->bl.max_unmap < 0xffffffff / block_size) { bs->bl.max_pdiscard = iscsilun->bl.max_unmap * iscsilun->block_size; } @@ -1835,7 +1838,7 @@ static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp) bs->bl.pdiscard_alignment = iscsilun->block_size; } - if (iscsilun->bl.max_ws_len < 0xffffffff / iscsilun->block_size) { + if (iscsilun->bl.max_ws_len < 0xffffffff / block_size) { bs->bl.max_pwrite_zeroes = iscsilun->bl.max_ws_len * iscsilun->block_size; } @@ -1846,7 +1849,7 @@ static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp) bs->bl.pwrite_zeroes_alignment = iscsilun->block_size; } if (iscsilun->bl.opt_xfer_len && - iscsilun->bl.opt_xfer_len < INT_MAX / iscsilun->block_size) { + iscsilun->bl.opt_xfer_len < INT_MAX / block_size) { bs->bl.opt_transfer = pow2floor(iscsilun->bl.opt_xfer_len * iscsilun->block_size); } diff --git a/block/vdi.c b/block/vdi.c index 8a1cf97..96b78d5 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -58,14 +58,7 @@ #include "migration/migration.h" #include "qemu/coroutine.h" #include "qemu/cutils.h" - -#if defined(CONFIG_UUID) -#include <uuid/uuid.h> -#else -/* TODO: move uuid emulation to some central place in QEMU. */ -#include "sysemu/sysemu.h" /* UUID_FMT */ -typedef unsigned char uuid_t[16]; -#endif +#include "qemu/uuid.h" /* Code configuration options. */ @@ -140,28 +133,6 @@ typedef unsigned char uuid_t[16]; #define VDI_DISK_SIZE_MAX ((uint64_t)VDI_BLOCKS_IN_IMAGE_MAX * \ (uint64_t)DEFAULT_CLUSTER_SIZE) -#if !defined(CONFIG_UUID) -static inline void uuid_generate(uuid_t out) -{ - memset(out, 0, sizeof(uuid_t)); -} - -static inline int uuid_is_null(const uuid_t uu) -{ - uuid_t null_uuid = { 0 }; - return memcmp(uu, null_uuid, sizeof(uuid_t)) == 0; -} - -# if defined(CONFIG_VDI_DEBUG) -static inline void uuid_unparse(const uuid_t uu, char *out) -{ - snprintf(out, 37, UUID_FMT, - uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7], - uu[8], uu[9], uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]); -} -# endif -#endif - typedef struct { char text[0x40]; uint32_t signature; @@ -182,10 +153,10 @@ typedef struct { uint32_t block_extra; /* unused here */ uint32_t blocks_in_image; uint32_t blocks_allocated; - uuid_t uuid_image; - uuid_t uuid_last_snap; - uuid_t uuid_link; - uuid_t uuid_parent; + QemuUUID uuid_image; + QemuUUID uuid_last_snap; + QemuUUID uuid_link; + QemuUUID uuid_parent; uint64_t unused2[7]; } QEMU_PACKED VdiHeader; @@ -206,16 +177,6 @@ typedef struct { Error *migration_blocker; } BDRVVdiState; -/* Change UUID from little endian (IPRT = VirtualBox format) to big endian - * format (network byte order, standard, see RFC 4122) and vice versa. - */ -static void uuid_convert(uuid_t uuid) -{ - bswap32s((uint32_t *)&uuid[0]); - bswap16s((uint16_t *)&uuid[4]); - bswap16s((uint16_t *)&uuid[6]); -} - static void vdi_header_to_cpu(VdiHeader *header) { le32_to_cpus(&header->signature); @@ -234,10 +195,10 @@ static void vdi_header_to_cpu(VdiHeader *header) le32_to_cpus(&header->block_extra); le32_to_cpus(&header->blocks_in_image); le32_to_cpus(&header->blocks_allocated); - uuid_convert(header->uuid_image); - uuid_convert(header->uuid_last_snap); - uuid_convert(header->uuid_link); - uuid_convert(header->uuid_parent); + qemu_uuid_bswap(&header->uuid_image); + qemu_uuid_bswap(&header->uuid_last_snap); + qemu_uuid_bswap(&header->uuid_link); + qemu_uuid_bswap(&header->uuid_parent); } static void vdi_header_to_le(VdiHeader *header) @@ -258,10 +219,10 @@ static void vdi_header_to_le(VdiHeader *header) cpu_to_le32s(&header->block_extra); cpu_to_le32s(&header->blocks_in_image); cpu_to_le32s(&header->blocks_allocated); - uuid_convert(header->uuid_image); - uuid_convert(header->uuid_last_snap); - uuid_convert(header->uuid_link); - uuid_convert(header->uuid_parent); + qemu_uuid_bswap(&header->uuid_image); + qemu_uuid_bswap(&header->uuid_last_snap); + qemu_uuid_bswap(&header->uuid_link); + qemu_uuid_bswap(&header->uuid_parent); } #if defined(CONFIG_VDI_DEBUG) @@ -469,11 +430,11 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, (uint64_t)header.blocks_in_image * header.block_size); ret = -ENOTSUP; goto fail; - } else if (!uuid_is_null(header.uuid_link)) { + } else if (!qemu_uuid_is_null(&header.uuid_link)) { error_setg(errp, "unsupported VDI image (non-NULL link UUID)"); ret = -ENOTSUP; goto fail; - } else if (!uuid_is_null(header.uuid_parent)) { + } else if (!qemu_uuid_is_null(&header.uuid_parent)) { error_setg(errp, "unsupported VDI image (non-NULL parent UUID)"); ret = -ENOTSUP; goto fail; @@ -821,8 +782,8 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp) if (image_type == VDI_TYPE_STATIC) { header.blocks_allocated = blocks; } - uuid_generate(header.uuid_image); - uuid_generate(header.uuid_last_snap); + qemu_uuid_generate(&header.uuid_image); + qemu_uuid_generate(&header.uuid_last_snap); /* There is no need to set header.uuid_link or header.uuid_parent here. */ #if defined(CONFIG_VDI_DEBUG) vdi_header_print(&header); diff --git a/block/vhdx-endian.c b/block/vhdx-endian.c index c306b90..429d755 100644 --- a/block/vhdx-endian.c +++ b/block/vhdx-endian.c @@ -21,9 +21,6 @@ #include "qemu/bswap.h" #include "block/vhdx.h" -#include <uuid/uuid.h> - - /* * All the VHDX formats on disk are little endian - the following * are helper import/export functions to correctly convert diff --git a/block/vhdx.c b/block/vhdx.c index 75ef2b1..0ba2f0a 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -25,8 +25,7 @@ #include "qemu/bswap.h" #include "block/vhdx.h" #include "migration/migration.h" - -#include <uuid/uuid.h> +#include "qemu/uuid.h" /* Options for VHDX creation */ @@ -213,11 +212,11 @@ bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset) */ void vhdx_guid_generate(MSGUID *guid) { - uuid_t uuid; + QemuUUID uuid; assert(guid != NULL); - uuid_generate(uuid); - memcpy(guid, uuid, sizeof(MSGUID)); + qemu_uuid_generate(&uuid); + memcpy(guid, &uuid, sizeof(MSGUID)); } /* Check for region overlaps inside the VHDX image */ diff --git a/block/vpc.c b/block/vpc.c index 43707ed..8d5886f 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -30,9 +30,7 @@ #include "qemu/module.h" #include "migration/migration.h" #include "qemu/bswap.h" -#if defined(CONFIG_UUID) -#include <uuid/uuid.h> -#endif +#include "qemu/uuid.h" /**************************************************************/ @@ -89,7 +87,7 @@ typedef struct vhd_footer { uint32_t checksum; /* UUID used to identify a parent hard disk (backing file) */ - uint8_t uuid[16]; + QemuUUID uuid; uint8_t in_saved_state; } QEMU_PACKED VHDFooter; @@ -980,9 +978,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp) footer->type = cpu_to_be32(disk_type); -#if defined(CONFIG_UUID) - uuid_generate(footer->uuid); -#endif + qemu_uuid_generate(&footer->uuid); footer->checksum = cpu_to_be32(vpc_checksum(buf, HEADER_SIZE)); @@ -212,7 +212,6 @@ sdlabi="" virtfs="" vnc="yes" sparse="no" -uuid="" vde="" vnc_sasl="" vnc_jpeg="" @@ -317,7 +316,6 @@ vte="" virglrenderer="" tpm="yes" libssh2="" -vhdx="" numa="" tcmalloc="no" jemalloc="no" @@ -887,10 +885,6 @@ for opt do ;; --disable-slirp) slirp="no" ;; - --disable-uuid) uuid="no" - ;; - --enable-uuid) uuid="yes" - ;; --disable-vde) vde="no" ;; --enable-vde) vde="yes" @@ -1103,6 +1097,12 @@ for opt do --disable-virtio-blk-data-plane|--enable-virtio-blk-data-plane) echo "$0: $opt is obsolete, virtio-blk data-plane is always on" >&2 ;; + --enable-vhdx|--disable-vhdx) + echo "$0: $opt is obsolete, VHDX driver is always built" >&2 + ;; + --enable-uuid|--disable-uuid) + echo "$0: $opt is obsolete, UUID support is always built" >&2 + ;; --disable-gtk) gtk="no" ;; --enable-gtk) gtk="yes" @@ -1143,10 +1143,6 @@ for opt do ;; --enable-libssh2) libssh2="yes" ;; - --enable-vhdx) vhdx="yes" - ;; - --disable-vhdx) vhdx="no" - ;; --disable-numa) numa="no" ;; --enable-numa) numa="yes" @@ -1365,7 +1361,6 @@ disabled with --disable-FEATURE, default is enabled if available: bluez bluez stack connectivity kvm KVM acceleration support rdma RDMA-based migration support - uuid uuid support vde support for vde network netmap support for netmap network linux-aio Linux AIO support @@ -1389,7 +1384,6 @@ disabled with --disable-FEATURE, default is enabled if available: archipelago Archipelago backend tpm TPM support libssh2 ssh block device support - vhdx support for the Microsoft VHDX image format numa libnuma support tcmalloc tcmalloc support jemalloc jemalloc support @@ -2662,47 +2656,6 @@ if compile_prog "" "" ; then fi ########################################## -# uuid_generate() probe, used for vdi block driver -# Note that on some systems (notably MacOSX) no extra library -# need be linked to get the uuid functions. -if test "$uuid" != "no" ; then - uuid_libs="-luuid" - cat > $TMPC << EOF -#include <uuid/uuid.h> -int main(void) -{ - uuid_t my_uuid; - uuid_generate(my_uuid); - return 0; -} -EOF - if compile_prog "" "" ; then - uuid="yes" - elif compile_prog "" "$uuid_libs" ; then - uuid="yes" - libs_softmmu="$uuid_libs $libs_softmmu" - libs_tools="$uuid_libs $libs_tools" - else - if test "$uuid" = "yes" ; then - feature_not_found "uuid" "Install libuuid devel" - fi - uuid=no - fi -fi - -if test "$vhdx" = "yes" ; then - if test "$uuid" = "no" ; then - error_exit "uuid required for VHDX support" - fi -elif test "$vhdx" != "no" ; then - if test "$uuid" = "yes" ; then - vhdx=yes - else - vhdx=no - fi -fi - -########################################## # xfsctl() probe, used for raw-posix if test "$xfs" != "no" ; then cat > $TMPC << EOF @@ -4075,7 +4028,7 @@ EOF if compile_prog "$vss_win32_include" "" ; then guest_agent_with_vss="yes" QEMU_CFLAGS="$QEMU_CFLAGS $vss_win32_include" - libs_qga="-lole32 -loleaut32 -lshlwapi -luuid -lstdc++ -Wl,--enable-stdcall-fixup $libs_qga" + libs_qga="-lole32 -loleaut32 -lshlwapi -lstdc++ -Wl,--enable-stdcall-fixup $libs_qga" qga_vss_provider="qga/vss-win32/qga-vss.dll qga/vss-win32/qga-vss.tlb" else if test "$vss_win32_sdk" != "" ; then @@ -4883,7 +4836,6 @@ echo "preadv support $preadv" echo "fdatasync $fdatasync" echo "madvise $madvise" echo "posix_madvise $posix_madvise" -echo "uuid support $uuid" echo "libcap-ng support $cap_ng" echo "vhost-net support $vhost_net" echo "vhost-scsi support $vhost_scsi" @@ -4917,7 +4869,6 @@ echo "TPM support $tpm" echo "libssh2 support $libssh2" echo "TPM passthrough $tpm_passthrough" echo "QOM debugging $qom_cast_debug" -echo "vhdx $vhdx" echo "lzo support $lzo" echo "snappy support $snappy" echo "bzip2 support $bzip2" @@ -5074,9 +5025,6 @@ fi if test "$fnmatch" = "yes" ; then echo "CONFIG_FNMATCH=y" >> $config_host_mak fi -if test "$uuid" = "yes" ; then - echo "CONFIG_UUID=y" >> $config_host_mak -fi if test "$xfs" = "yes" ; then echo "CONFIG_XFS=y" >> $config_host_mak fi @@ -5443,10 +5391,6 @@ if test "$libssh2" = "yes" ; then echo "LIBSSH2_LIBS=$libssh2_libs" >> $config_host_mak fi -if test "$vhdx" = "yes" ; then - echo "CONFIG_VHDX=y" >> $config_host_mak -fi - # USB host support if test "$libusb" = "yes"; then echo "HOST_USB=libusb legacy" >> $config_host_mak diff --git a/crypto/block-luks.c b/crypto/block-luks.c index a848232..4530f82 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -29,10 +29,7 @@ #include "crypto/pbkdf.h" #include "crypto/secret.h" #include "crypto/random.h" - -#ifdef CONFIG_UUID -#include <uuid/uuid.h> -#endif +#include "qemu/uuid.h" #include "qemu/coroutine.h" @@ -877,18 +874,12 @@ qcrypto_block_luks_open(QCryptoBlock *block, } -static int -qcrypto_block_luks_uuid_gen(uint8_t *uuidstr, Error **errp) +static void +qcrypto_block_luks_uuid_gen(uint8_t *uuidstr) { -#ifdef CONFIG_UUID - uuid_t uuid; - uuid_generate(uuid); - uuid_unparse(uuid, (char *)uuidstr); - return 0; -#else - error_setg(errp, "Unable to generate uuids on this platform"); - return -1; -#endif + QemuUUID uuid; + qemu_uuid_generate(&uuid); + qemu_uuid_unparse(&uuid, (char *)uuidstr); } static int @@ -965,10 +956,7 @@ qcrypto_block_luks_create(QCryptoBlock *block, * it out to disk */ luks->header.version = QCRYPTO_BLOCK_LUKS_VERSION; - if (qcrypto_block_luks_uuid_gen(luks->header.uuid, - errp) < 0) { - goto error; - } + qcrypto_block_luks_uuid_gen(luks->header.uuid); cipher_alg = qcrypto_block_luks_cipher_alg_lookup(luks_opts.cipher_alg, errp); diff --git a/disas/arm.c b/disas/arm.c index 426270f..93c6503 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 12764ef..4c5c4ee 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 0000000..6b18c7f --- /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 136bf64..c0a3102 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 cc50ace..7527037 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 54e29a8..0000000 --- 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 23c7199..0d86ba3 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 53e0e41..6e022b5 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 30829ee..c45c835 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 6d1faf4..e182893 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 a4753e5..b135a5f 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/i386/kvm/apic.c b/hw/i386/kvm/apic.c index feb0002..f57fed1 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -15,6 +15,7 @@ #include "hw/i386/apic_internal.h" #include "hw/pci/msi.h" #include "sysemu/kvm.h" +#include "target-i386/kvm_i386.h" static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic, int reg_id, uint32_t val) @@ -130,6 +131,7 @@ static void kvm_apic_put(void *data) struct kvm_lapic_state kapic; int ret; + kvm_put_apicbase(s->cpu, s->apicbase); kvm_put_apic_state(s, &kapic); ret = kvm_vcpu_ioctl(CPU(s->cpu), KVM_SET_LAPIC, &kapic); diff --git a/hw/input/adb.c b/hw/input/adb.c index f0ad0d4..3d39368 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -25,6 +25,9 @@ #include "hw/hw.h" #include "hw/input/adb.h" #include "ui/console.h" +#include "include/hw/input/adb-keys.h" +#include "ui/input.h" +#include "sysemu/sysemu.h" /* debug ADB */ //#define DEBUG_ADB @@ -59,6 +62,9 @@ do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0) /* error codes */ #define ADB_RET_NOTPRESENT (-2) +/* The adb keyboard doesn't have every key imaginable */ +#define NO_KEY 0xff + static void adb_device_reset(ADBDevice *d) { qdev_reset_all(DEVICE(d)); @@ -187,23 +193,125 @@ typedef struct ADBKeyboardClass { DeviceRealize parent_realize; } ADBKeyboardClass; -static const uint8_t pc_to_adb_keycode[256] = { - 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, - 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1, - 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, - 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96, - 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, - 84, 85, 82, 65, 0, 0, 10,103,111, 0, 0,110, 81, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76,125, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 75, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,115, 62,116, 0, 59, 0, 60, 0,119, - 61,121,114,117, 0, 0, 0, 0, 0, 0, 0, 55,126, 0,127, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +int qcode_to_adb_keycode[] = { + /* Make sure future additions are automatically set to NO_KEY */ + [0 ... 0xff] = NO_KEY, + + [Q_KEY_CODE_SHIFT] = ADB_KEY_LEFT_SHIFT, + [Q_KEY_CODE_SHIFT_R] = ADB_KEY_RIGHT_SHIFT, + [Q_KEY_CODE_ALT] = ADB_KEY_LEFT_OPTION, + [Q_KEY_CODE_ALT_R] = ADB_KEY_RIGHT_OPTION, + [Q_KEY_CODE_ALTGR] = ADB_KEY_RIGHT_OPTION, + [Q_KEY_CODE_CTRL] = ADB_KEY_LEFT_CONTROL, + [Q_KEY_CODE_CTRL_R] = ADB_KEY_RIGHT_CONTROL, + [Q_KEY_CODE_META_L] = ADB_KEY_COMMAND, + [Q_KEY_CODE_META_R] = ADB_KEY_COMMAND, + [Q_KEY_CODE_SPC] = ADB_KEY_SPACEBAR, + + [Q_KEY_CODE_ESC] = ADB_KEY_ESC, + [Q_KEY_CODE_1] = ADB_KEY_1, + [Q_KEY_CODE_2] = ADB_KEY_2, + [Q_KEY_CODE_3] = ADB_KEY_3, + [Q_KEY_CODE_4] = ADB_KEY_4, + [Q_KEY_CODE_5] = ADB_KEY_5, + [Q_KEY_CODE_6] = ADB_KEY_6, + [Q_KEY_CODE_7] = ADB_KEY_7, + [Q_KEY_CODE_8] = ADB_KEY_8, + [Q_KEY_CODE_9] = ADB_KEY_9, + [Q_KEY_CODE_0] = ADB_KEY_0, + [Q_KEY_CODE_MINUS] = ADB_KEY_MINUS, + [Q_KEY_CODE_EQUAL] = ADB_KEY_EQUAL, + [Q_KEY_CODE_BACKSPACE] = ADB_KEY_DELETE, + [Q_KEY_CODE_TAB] = ADB_KEY_TAB, + [Q_KEY_CODE_Q] = ADB_KEY_Q, + [Q_KEY_CODE_W] = ADB_KEY_W, + [Q_KEY_CODE_E] = ADB_KEY_E, + [Q_KEY_CODE_R] = ADB_KEY_R, + [Q_KEY_CODE_T] = ADB_KEY_T, + [Q_KEY_CODE_Y] = ADB_KEY_Y, + [Q_KEY_CODE_U] = ADB_KEY_U, + [Q_KEY_CODE_I] = ADB_KEY_I, + [Q_KEY_CODE_O] = ADB_KEY_O, + [Q_KEY_CODE_P] = ADB_KEY_P, + [Q_KEY_CODE_BRACKET_LEFT] = ADB_KEY_LEFT_BRACKET, + [Q_KEY_CODE_BRACKET_RIGHT] = ADB_KEY_RIGHT_BRACKET, + [Q_KEY_CODE_RET] = ADB_KEY_RETURN, + [Q_KEY_CODE_A] = ADB_KEY_A, + [Q_KEY_CODE_S] = ADB_KEY_S, + [Q_KEY_CODE_D] = ADB_KEY_D, + [Q_KEY_CODE_F] = ADB_KEY_F, + [Q_KEY_CODE_G] = ADB_KEY_G, + [Q_KEY_CODE_H] = ADB_KEY_H, + [Q_KEY_CODE_J] = ADB_KEY_J, + [Q_KEY_CODE_K] = ADB_KEY_K, + [Q_KEY_CODE_L] = ADB_KEY_L, + [Q_KEY_CODE_SEMICOLON] = ADB_KEY_SEMICOLON, + [Q_KEY_CODE_APOSTROPHE] = ADB_KEY_APOSTROPHE, + [Q_KEY_CODE_GRAVE_ACCENT] = ADB_KEY_GRAVE_ACCENT, + [Q_KEY_CODE_BACKSLASH] = ADB_KEY_BACKSLASH, + [Q_KEY_CODE_Z] = ADB_KEY_Z, + [Q_KEY_CODE_X] = ADB_KEY_X, + [Q_KEY_CODE_C] = ADB_KEY_C, + [Q_KEY_CODE_V] = ADB_KEY_V, + [Q_KEY_CODE_B] = ADB_KEY_B, + [Q_KEY_CODE_N] = ADB_KEY_N, + [Q_KEY_CODE_M] = ADB_KEY_M, + [Q_KEY_CODE_COMMA] = ADB_KEY_COMMA, + [Q_KEY_CODE_DOT] = ADB_KEY_PERIOD, + [Q_KEY_CODE_SLASH] = ADB_KEY_FORWARD_SLASH, + [Q_KEY_CODE_ASTERISK] = ADB_KEY_KP_MULTIPLY, + [Q_KEY_CODE_CAPS_LOCK] = ADB_KEY_CAPS_LOCK, + + [Q_KEY_CODE_F1] = ADB_KEY_F1, + [Q_KEY_CODE_F2] = ADB_KEY_F2, + [Q_KEY_CODE_F3] = ADB_KEY_F3, + [Q_KEY_CODE_F4] = ADB_KEY_F4, + [Q_KEY_CODE_F5] = ADB_KEY_F5, + [Q_KEY_CODE_F6] = ADB_KEY_F6, + [Q_KEY_CODE_F7] = ADB_KEY_F7, + [Q_KEY_CODE_F8] = ADB_KEY_F8, + [Q_KEY_CODE_F9] = ADB_KEY_F9, + [Q_KEY_CODE_F10] = ADB_KEY_F10, + [Q_KEY_CODE_F11] = ADB_KEY_F11, + [Q_KEY_CODE_F12] = ADB_KEY_F12, + [Q_KEY_CODE_PRINT] = ADB_KEY_F13, + [Q_KEY_CODE_SYSRQ] = ADB_KEY_F13, + [Q_KEY_CODE_SCROLL_LOCK] = ADB_KEY_F14, + [Q_KEY_CODE_PAUSE] = ADB_KEY_F15, + + [Q_KEY_CODE_NUM_LOCK] = ADB_KEY_KP_CLEAR, + [Q_KEY_CODE_KP_EQUALS] = ADB_KEY_KP_EQUAL, + [Q_KEY_CODE_KP_DIVIDE] = ADB_KEY_KP_DIVIDE, + [Q_KEY_CODE_KP_MULTIPLY] = ADB_KEY_KP_MULTIPLY, + [Q_KEY_CODE_KP_SUBTRACT] = ADB_KEY_KP_SUBTRACT, + [Q_KEY_CODE_KP_ADD] = ADB_KEY_KP_PLUS, + [Q_KEY_CODE_KP_ENTER] = ADB_KEY_KP_ENTER, + [Q_KEY_CODE_KP_DECIMAL] = ADB_KEY_KP_PERIOD, + [Q_KEY_CODE_KP_0] = ADB_KEY_KP_0, + [Q_KEY_CODE_KP_1] = ADB_KEY_KP_1, + [Q_KEY_CODE_KP_2] = ADB_KEY_KP_2, + [Q_KEY_CODE_KP_3] = ADB_KEY_KP_3, + [Q_KEY_CODE_KP_4] = ADB_KEY_KP_4, + [Q_KEY_CODE_KP_5] = ADB_KEY_KP_5, + [Q_KEY_CODE_KP_6] = ADB_KEY_KP_6, + [Q_KEY_CODE_KP_7] = ADB_KEY_KP_7, + [Q_KEY_CODE_KP_8] = ADB_KEY_KP_8, + [Q_KEY_CODE_KP_9] = ADB_KEY_KP_9, + + [Q_KEY_CODE_UP] = ADB_KEY_UP, + [Q_KEY_CODE_DOWN] = ADB_KEY_DOWN, + [Q_KEY_CODE_LEFT] = ADB_KEY_LEFT, + [Q_KEY_CODE_RIGHT] = ADB_KEY_RIGHT, + + [Q_KEY_CODE_HELP] = ADB_KEY_HELP, + [Q_KEY_CODE_INSERT] = ADB_KEY_HELP, + [Q_KEY_CODE_DELETE] = ADB_KEY_FORWARD_DELETE, + [Q_KEY_CODE_HOME] = ADB_KEY_HOME, + [Q_KEY_CODE_END] = ADB_KEY_END, + [Q_KEY_CODE_PGUP] = ADB_KEY_PAGE_UP, + [Q_KEY_CODE_PGDN] = ADB_KEY_PAGE_DOWN, + + [Q_KEY_CODE_POWER] = ADB_KEY_POWER }; static void adb_kbd_put_keycode(void *opaque, int keycode) @@ -220,35 +328,40 @@ static void adb_kbd_put_keycode(void *opaque, int keycode) static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) { - static int ext_keycode; KBDState *s = ADB_KEYBOARD(d); - int adb_keycode, keycode; + int keycode; int olen; olen = 0; - for(;;) { - if (s->count == 0) - break; - keycode = s->data[s->rptr]; - if (++s->rptr == sizeof(s->data)) - s->rptr = 0; - s->count--; - - if (keycode == 0xe0) { - ext_keycode = 1; - } else { - if (ext_keycode) - adb_keycode = pc_to_adb_keycode[keycode | 0x80]; - else - adb_keycode = pc_to_adb_keycode[keycode & 0x7f]; - obuf[0] = adb_keycode | (keycode & 0x80); - /* NOTE: could put a second keycode if needed */ - obuf[1] = 0xff; - olen = 2; - ext_keycode = 0; - break; - } + if (s->count == 0) { + return 0; } + keycode = s->data[s->rptr]; + s->rptr++; + if (s->rptr == sizeof(s->data)) { + s->rptr = 0; + } + s->count--; + /* + * The power key is the only two byte value key, so it is a special case. + * Since 0x7f is not a used keycode for ADB we overload it to indicate the + * power button when we're storing keycodes in our internal buffer, and + * expand it out to two bytes when we send to the guest. + */ + if (keycode == 0x7f) { + obuf[0] = 0x7f; + obuf[1] = 0x7f; + olen = 2; + } else { + obuf[0] = keycode; + /* NOTE: the power key key-up is the two byte sequence 0xff 0xff; + * otherwise we could in theory send a second keycode in the second + * byte, but choose not to bother. + */ + obuf[1] = 0xff; + olen = 2; + } + return olen; } @@ -313,6 +426,29 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, return olen; } +/* This is where keyboard events enter this file */ +static void adb_keyboard_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) +{ + KBDState *s = (KBDState *)dev; + int qcode, keycode; + + qcode = qemu_input_key_value_to_qcode(evt->u.key.data->key); + if (qcode >= ARRAY_SIZE(qcode_to_adb_keycode)) { + return; + } + keycode = qcode_to_adb_keycode[qcode]; + if (keycode == NO_KEY) { /* We don't want to send this to the guest */ + ADB_DPRINTF("Ignoring NO_KEY\n"); + return; + } + if (evt->u.key.data->down == false) { /* if key release event */ + keycode = keycode | 0x80; /* create keyboard break code */ + } + + adb_kbd_put_keycode(s, keycode); +} + static const VMStateDescription vmstate_adb_kbd = { .name = "adb_kbd", .version_id = 2, @@ -340,14 +476,17 @@ static void adb_kbd_reset(DeviceState *dev) s->count = 0; } +static QemuInputHandler adb_keyboard_handler = { + .name = "QEMU ADB Keyboard", + .mask = INPUT_EVENT_MASK_KEY, + .event = adb_keyboard_event, +}; + static void adb_kbd_realizefn(DeviceState *dev, Error **errp) { - ADBDevice *d = ADB_DEVICE(dev); ADBKeyboardClass *akc = ADB_KEYBOARD_GET_CLASS(dev); - akc->parent_realize(dev, errp); - - qemu_add_kbd_event_handler(adb_kbd_put_keycode, d); + qemu_input_handler_register(dev, &adb_keyboard_handler); } static void adb_kbd_initfn(Object *obj) diff --git a/hw/intc/xics.c b/hw/intc/xics.c index cd48f42..69162f0 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -505,8 +505,11 @@ static void ics_reject(ICSState *ics, int nr) ICSIRQState *irq = ics->irqs + nr - ics->offset; trace_xics_ics_reject(nr, nr - ics->offset); - irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */ - irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */ + if (irq->flags & XICS_FLAGS_IRQ_MSI) { + irq->status |= XICS_STATUS_REJECTED; + } else if (irq->flags & XICS_FLAGS_IRQ_LSI) { + irq->status &= ~XICS_STATUS_SENT; + } } static void ics_resend(ICSState *ics) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index dc9c14c..17c7c0e 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -1773,7 +1773,7 @@ static void ipmi_sim_realize(DeviceState *dev, Error **errp) ibs->acpi_power_state[1] = 0; if (qemu_uuid_set) { - memcpy(&ibs->uuid, qemu_uuid, 16); + memcpy(&ibs->uuid, &qemu_uuid, 16); } else { memset(&ibs->uuid, 0, 16); } diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c index e14896e..b81901f 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 2415557..9240ebf 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 c7e2c82..b1f3e6f 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 fc4217b..8830dc0 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 5cd8c0a..19e948a 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 1c03e52..b890c38 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 17e15d4..1b42101 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 8bb6829..55b817b 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 db1b301..8618e7a 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 b5c777f..951c5f0 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 4615d87..3db8937 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/net/spapr_llan.c b/hw/net/spapr_llan.c index 4bb95a5..01ecb02 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -34,20 +34,13 @@ #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" #include "sysemu/sysemu.h" +#include "trace.h" #include <libfdt.h> #define ETH_ALEN 6 #define MAX_PACKET_SIZE 65536 -/*#define DEBUG*/ - -#ifdef DEBUG -#define DPRINTF(fmt...) do { fprintf(stderr, fmt); } while (0) -#else -#define DPRINTF(fmt...) -#endif - /* Compatibility flags for migration */ #define SPAPRVLAN_FLAG_RX_BUF_POOLS_BIT 0 #define SPAPRVLAN_FLAG_RX_BUF_POOLS (1 << SPAPRVLAN_FLAG_RX_BUF_POOLS_BIT) @@ -158,8 +151,10 @@ static vlan_bd_t spapr_vlan_get_rx_bd_from_pool(VIOsPAPRVLANDevice *dev, return 0; } - DPRINTF("Found buffer: pool=%d count=%d rxbufs=%d\n", pool, - dev->rx_pool[pool]->count, dev->rx_bufs); + + trace_spapr_vlan_get_rx_bd_from_pool_found(pool, + dev->rx_pool[pool]->count, + dev->rx_bufs); /* Remove the buffer from the pool */ dev->rx_pool[pool]->count--; @@ -186,8 +181,8 @@ static vlan_bd_t spapr_vlan_get_rx_bd_from_page(VIOsPAPRVLANDevice *dev, } bd = vio_ldq(&dev->sdev, dev->buf_list + buf_ptr); - DPRINTF("use_buf_ptr=%d bd=0x%016llx\n", - buf_ptr, (unsigned long long)bd); + + trace_spapr_vlan_get_rx_bd_from_page(buf_ptr, (uint64_t)bd); } while ((!(bd & VLAN_BD_VALID) || VLAN_BD_LEN(bd) < size + 8) && buf_ptr != dev->use_buf_ptr); @@ -200,7 +195,7 @@ static vlan_bd_t spapr_vlan_get_rx_bd_from_page(VIOsPAPRVLANDevice *dev, dev->use_buf_ptr = buf_ptr; vio_stq(&dev->sdev, dev->buf_list + dev->use_buf_ptr, 0); - DPRINTF("Found buffer: ptr=%d rxbufs=%d\n", dev->use_buf_ptr, dev->rx_bufs); + trace_spapr_vlan_get_rx_bd_from_page_found(dev->use_buf_ptr, dev->rx_bufs); return bd; } @@ -215,8 +210,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, uint64_t handle; uint8_t control; - DPRINTF("spapr_vlan_receive() [%s] rx_bufs=%d\n", sdev->qdev.id, - dev->rx_bufs); + trace_spapr_vlan_receive(sdev->qdev.id, dev->rx_bufs); if (!dev->isopen) { return -1; @@ -244,7 +238,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, return -1; } - DPRINTF("spapr_vlan_receive: DMA write completed\n"); + trace_spapr_vlan_receive_dma_completed(); /* Update the receive queue */ control = VLAN_RXQC_TOGGLE | VLAN_RXQC_VALID; @@ -258,12 +252,11 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, vio_sth(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 2, 8); vio_stb(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr, control); - DPRINTF("wrote rxq entry (ptr=0x%llx): 0x%016llx 0x%016llx\n", - (unsigned long long)dev->rxq_ptr, - (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) + - dev->rxq_ptr), - (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) + - dev->rxq_ptr + 8)); + trace_spapr_vlan_receive_wrote(dev->rxq_ptr, + vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) + + dev->rxq_ptr), + vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) + + dev->rxq_ptr + 8)); dev->rxq_ptr += 16; if (dev->rxq_ptr >= VLAN_BD_LEN(rxq_bd)) { @@ -580,8 +573,8 @@ static target_long spapr_vlan_add_rxbuf_to_pool(VIOsPAPRVLANDevice *dev, qsort(dev->rx_pool, RX_MAX_POOLS, sizeof(dev->rx_pool[0]), rx_pool_size_compare); pool = spapr_vlan_get_rx_pool_id(dev, size); - DPRINTF("created RX pool %d for size %lld\n", pool, - VLAN_BD_LEN(buf)); + trace_spapr_vlan_add_rxbuf_to_pool_create(pool, + VLAN_BD_LEN(buf)); break; } } @@ -591,8 +584,8 @@ static target_long spapr_vlan_add_rxbuf_to_pool(VIOsPAPRVLANDevice *dev, return H_RESOURCE; } - DPRINTF("h_add_llan_buf(): Add buf using pool %i (size %lli, count=%i)\n", - pool, VLAN_BD_LEN(buf), dev->rx_pool[pool]->count); + trace_spapr_vlan_add_rxbuf_to_pool(pool, VLAN_BD_LEN(buf), + dev->rx_pool[pool]->count); dev->rx_pool[pool]->bds[dev->rx_pool[pool]->count++] = buf; @@ -623,8 +616,7 @@ static target_long spapr_vlan_add_rxbuf_to_page(VIOsPAPRVLANDevice *dev, vio_stq(&dev->sdev, dev->buf_list + dev->add_buf_ptr, buf); - DPRINTF("h_add_llan_buf(): Added buf ptr=%d rx_bufs=%d bd=0x%016llx\n", - dev->add_buf_ptr, dev->rx_bufs, (unsigned long long)buf); + trace_spapr_vlan_add_rxbuf_to_page(dev->add_buf_ptr, dev->rx_bufs, buf); return 0; } @@ -640,8 +632,7 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu, VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev); target_long ret; - DPRINTF("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx - ", 0x" TARGET_FMT_lx ")\n", reg, buf); + trace_spapr_vlan_h_add_logical_lan_buffer(reg, buf); if (!sdev) { hcall_dprintf("Bad device\n"); @@ -694,14 +685,13 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu, int i, nbufs; int ret; - DPRINTF("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", <bufs>, 0x" - TARGET_FMT_lx ")\n", reg, continue_token); + trace_spapr_vlan_h_send_logical_lan(reg, continue_token); if (!sdev) { return H_PARAMETER; } - DPRINTF("rxbufs = %d\n", dev->rx_bufs); + trace_spapr_vlan_h_send_logical_lan_rxbufs(dev->rx_bufs); if (!dev->isopen) { return H_DROPPED; @@ -713,7 +703,7 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu, total_len = 0; for (i = 0; i < 6; i++) { - DPRINTF(" buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]); + trace_spapr_vlan_h_send_logical_lan_buf_desc(bufs[i]); if (!(bufs[i] & VLAN_BD_VALID)) { break; } @@ -721,8 +711,7 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu, } nbufs = i; - DPRINTF("h_send_logical_lan() %d buffers, total length 0x%x\n", - nbufs, total_len); + trace_spapr_vlan_h_send_logical_lan_total(nbufs, total_len); if (total_len == 0) { return H_SUCCESS; diff --git a/hw/net/trace-events b/hw/net/trace-events index 8d38d77..47ab14a 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -270,3 +270,19 @@ e1000e_cfg_support_virtio(bool support) "Virtio header supported: %d" e1000e_vm_state_running(void) "VM state is running" e1000e_vm_state_stopped(void) "VM state is stopped" + +# hw/net/spapr_llan.c +spapr_vlan_get_rx_bd_from_pool_found(int pool, int32_t count, uint32_t rx_bufs) "pool=%d count=%"PRId32" rxbufs=%"PRIu32 +spapr_vlan_get_rx_bd_from_page(int buf_ptr, uint64_t bd) "use_buf_ptr=%d bd=0x%016"PRIx64 +spapr_vlan_get_rx_bd_from_page_found(uint32_t use_buf_ptr, uint32_t rx_bufs) "ptr=%"PRIu32" rxbufs=%"PRIu32 +spapr_vlan_receive(const char *id, uint32_t rx_bufs) "[%s] rx_bufs=%"PRIu32 +spapr_vlan_receive_dma_completed(void) "DMA write completed" +spapr_vlan_receive_wrote(uint64_t ptr, uint64_t hi, uint64_t lo) "rxq entry (ptr=0x%"PRIx64"): 0x%016"PRIx64" 0x%016"PRIx64 +spapr_vlan_add_rxbuf_to_pool_create(int pool, uint64_t len) "created RX pool %d for size %"PRIu64 +spapr_vlan_add_rxbuf_to_pool(int pool, uint64_t len, int32_t count) "add buf using pool %d (size %"PRIu64", count=%"PRId32")" +spapr_vlan_add_rxbuf_to_page(uint32_t ptr, uint32_t rx_bufs, uint64_t bd) "added buf ptr=%"PRIu32" rx_bufs=%"PRIu32" bd=0x%016"PRIx64 +spapr_vlan_h_add_logical_lan_buffer(uint64_t reg, uint64_t buf) "H_ADD_LOGICAL_LAN_BUFFER(0x%"PRIx64", 0x%"PRIx64")" +spapr_vlan_h_send_logical_lan(uint64_t reg, uint64_t continue_token) "H_SEND_LOGICAL_LAN(0x%"PRIx64", <bufs>, 0x%"PRIx64")" +spapr_vlan_h_send_logical_lan_rxbufs(uint32_t rx_bufs) "rxbufs = %"PRIu32 +spapr_vlan_h_send_logical_lan_buf_desc(uint64_t buf) " buf desc: 0x%"PRIx64 +spapr_vlan_h_send_logical_lan_total(int nbufs, unsigned total_len) "%d buffers, total length 0x%x" diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 1776b1b..92aa563 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -883,7 +883,7 @@ static void fw_cfg_init1(DeviceState *dev) qdev_init_nofail(dev); fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4); - fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16); + fw_cfg_add_bytes(s, FW_CFG_UUID, &qemu_uuid, 16); fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)!machine->enable_graphics); fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index ca77bb0..9b506d5 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -332,12 +332,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base, g_free(buf); } - buf = g_strdup_printf(UUID_FMT, qemu_uuid[0], qemu_uuid[1], - qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], - qemu_uuid[5], qemu_uuid[6], qemu_uuid[7], - qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], - qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], - qemu_uuid[14], qemu_uuid[15]); + buf = qemu_uuid_unparse_strdup(&qemu_uuid); _FDT((fdt_property_string(fdt, "vm,uuid", buf))); if (qemu_uuid_set) { @@ -1814,6 +1809,9 @@ static void ppc_spapr_init(MachineState *machine) /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */ kvmppc_enable_logical_ci_hcalls(); kvmppc_enable_set_mode_hcall(); + + /* H_CLEAR_MOD/_REF are mandatory in PAPR, but off by default */ + kvmppc_enable_clear_ref_mod_hcalls(); } /* allocate RAM */ @@ -2312,8 +2310,8 @@ static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev, } } -static HotplugHandler *spapr_get_hotpug_handler(MachineState *machine, - DeviceState *dev) +static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine, + DeviceState *dev) { if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { @@ -2385,7 +2383,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->kvm_type = spapr_kvm_type; mc->has_dynamic_sysbus = true; mc->pci_allow_0_address = true; - mc->get_hotplug_handler = spapr_get_hotpug_handler; + mc->get_hotplug_handler = spapr_get_hotplug_handler; hc->pre_plug = spapr_machine_device_pre_plug; hc->plug = spapr_machine_device_plug; hc->unplug = spapr_machine_device_unplug; diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index bcb483d..6f0533c 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -112,7 +112,8 @@ char *spapr_get_cpu_core_type(const char *model) static void spapr_core_release(DeviceState *dev, void *opaque) { sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); - const char *typename = object_class_get_name(sc->cpu_class); + sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); + const char *typename = object_class_get_name(scc->cpu_class); size_t size = object_type_get_instance_size(typename); sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); CPUCore *cc = CPU_CORE(dev); @@ -287,8 +288,9 @@ static void spapr_cpu_core_realize_child(Object *child, Error **errp) static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) { sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); + sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); CPUCore *cc = CPU_CORE(OBJECT(dev)); - const char *typename = object_class_get_name(sc->cpu_class); + const char *typename = object_class_get_name(scc->cpu_class); size_t size = object_type_get_instance_size(typename); Error *local_err = NULL; void *obj; @@ -331,83 +333,43 @@ err: error_propagate(errp, local_err); } -static void spapr_cpu_core_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - dc->realize = spapr_cpu_core_realize; -} - -/* - * instance_init routines from different flavours of sPAPR CPU cores. - */ -#define SPAPR_CPU_CORE_INITFN(_type, _fname) \ -static void glue(glue(spapr_cpu_core_, _fname), _initfn(Object *obj)) \ -{ \ - sPAPRCPUCore *core = SPAPR_CPU_CORE(obj); \ - char *name = g_strdup_printf("%s-" TYPE_POWERPC_CPU, stringify(_type)); \ - ObjectClass *oc = object_class_by_name(name); \ - g_assert(oc); \ - g_free((void *)name); \ - core->cpu_class = oc; \ -} - -SPAPR_CPU_CORE_INITFN(970mp_v1.0, 970MP_v10); -SPAPR_CPU_CORE_INITFN(970mp_v1.1, 970MP_v11); -SPAPR_CPU_CORE_INITFN(970_v2.2, 970); -SPAPR_CPU_CORE_INITFN(POWER5+_v2.1, POWER5plus); -SPAPR_CPU_CORE_INITFN(POWER7_v2.3, POWER7); -SPAPR_CPU_CORE_INITFN(POWER7+_v2.1, POWER7plus); -SPAPR_CPU_CORE_INITFN(POWER8_v2.0, POWER8); -SPAPR_CPU_CORE_INITFN(POWER8E_v2.1, POWER8E); -SPAPR_CPU_CORE_INITFN(POWER8NVL_v1.0, POWER8NVL); - -typedef struct SPAPRCoreInfo { - const char *name; - void (*initfn)(Object *obj); -} SPAPRCoreInfo; - -static const SPAPRCoreInfo spapr_cores[] = { +static const char *spapr_core_models[] = { /* 970 */ - { .name = "970_v2.2", .initfn = spapr_cpu_core_970_initfn }, + "970_v2.2", /* 970MP variants */ - { .name = "970MP_v1.0", .initfn = spapr_cpu_core_970MP_v10_initfn }, - { .name = "970mp_v1.0", .initfn = spapr_cpu_core_970MP_v10_initfn }, - { .name = "970MP_v1.1", .initfn = spapr_cpu_core_970MP_v11_initfn }, - { .name = "970mp_v1.1", .initfn = spapr_cpu_core_970MP_v11_initfn }, + "970MP_v1.0", + "970mp_v1.0", + "970MP_v1.1", + "970mp_v1.1", /* POWER5+ */ - { .name = "POWER5+_v2.1", .initfn = spapr_cpu_core_POWER5plus_initfn }, + "POWER5+_v2.1", /* POWER7 */ - { .name = "POWER7_v2.3", .initfn = spapr_cpu_core_POWER7_initfn }, + "POWER7_v2.3", /* POWER7+ */ - { .name = "POWER7+_v2.1", .initfn = spapr_cpu_core_POWER7plus_initfn }, + "POWER7+_v2.1", /* POWER8 */ - { .name = "POWER8_v2.0", .initfn = spapr_cpu_core_POWER8_initfn }, + "POWER8_v2.0", /* POWER8E */ - { .name = "POWER8E_v2.1", .initfn = spapr_cpu_core_POWER8E_initfn }, + "POWER8E_v2.1", /* POWER8NVL */ - { .name = "POWER8NVL_v1.0", .initfn = spapr_cpu_core_POWER8NVL_initfn }, - - { .name = NULL } + "POWER8NVL_v1.0", }; -static void spapr_cpu_core_register(const SPAPRCoreInfo *info) +void spapr_cpu_core_class_init(ObjectClass *oc, void *data) { - TypeInfo type_info = { - .parent = TYPE_SPAPR_CPU_CORE, - .instance_size = sizeof(sPAPRCPUCore), - .instance_init = info->initfn, - }; - - type_info.name = g_strdup_printf("%s-" TYPE_SPAPR_CPU_CORE, info->name); - type_register(&type_info); - g_free((void *)type_info.name); + DeviceClass *dc = DEVICE_CLASS(oc); + sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc); + + dc->realize = spapr_cpu_core_realize; + scc->cpu_class = cpu_class_by_name(TYPE_POWERPC_CPU, data); + g_assert(scc->cpu_class); } static const TypeInfo spapr_cpu_core_type_info = { @@ -415,17 +377,27 @@ static const TypeInfo spapr_cpu_core_type_info = { .parent = TYPE_CPU_CORE, .abstract = true, .instance_size = sizeof(sPAPRCPUCore), - .class_init = spapr_cpu_core_class_init, + .class_size = sizeof(sPAPRCPUCoreClass), }; static void spapr_cpu_core_register_types(void) { - const SPAPRCoreInfo *info = spapr_cores; + int i; type_register_static(&spapr_cpu_core_type_info); - while (info->name) { - spapr_cpu_core_register(info); - info++; + + for (i = 0; i < ARRAY_SIZE(spapr_core_models); i++) { + TypeInfo type_info = { + .parent = TYPE_SPAPR_CPU_CORE, + .instance_size = sizeof(sPAPRCPUCore), + .class_init = spapr_cpu_core_class_init, + .class_data = (void *) spapr_core_models[i], + }; + + type_info.name = g_strdup_printf("%s-" TYPE_SPAPR_CPU_CORE, + spapr_core_models[i]); + type_register(&type_info); + g_free((void *)type_info.name); } } diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 4b1a943..6e54fd4 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -20,20 +20,7 @@ #include "qapi/visitor.h" #include "qemu/error-report.h" #include "hw/ppc/spapr.h" /* for RTAS return codes */ - -/* #define DEBUG_SPAPR_DRC */ - -#ifdef DEBUG_SPAPR_DRC -#define DPRINTF(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -#define DPRINTFN(fmt, ...) \ - do { DPRINTF(fmt, ## __VA_ARGS__); fprintf(stderr, "\n"); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#define DPRINTFN(fmt, ...) \ - do { } while (0) -#endif +#include "trace.h" #define DRC_CONTAINER_PATH "/dr-connector" #define DRC_INDEX_TYPE_SHIFT 28 @@ -69,7 +56,7 @@ static uint32_t set_isolation_state(sPAPRDRConnector *drc, { sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - DPRINTFN("drc: %x, set_isolation_state: %x", get_index(drc), state); + trace_spapr_drc_set_isolation_state(get_index(drc), state); if (state == SPAPR_DR_ISOLATION_STATE_UNISOLATED) { /* cannot unisolate a non-existant resource, and, or resources @@ -94,11 +81,11 @@ static uint32_t set_isolation_state(sPAPRDRConnector *drc, */ if (drc->awaiting_release) { if (drc->configured) { - DPRINTFN("finalizing device removal"); + trace_spapr_drc_set_isolation_state_finalizing(get_index(drc)); drck->detach(drc, DEVICE(drc->dev), drc->detach_cb, drc->detach_cb_opaque, NULL); } else { - DPRINTFN("deferring device removal on unconfigured device\n"); + trace_spapr_drc_set_isolation_state_deferring(get_index(drc)); } } drc->configured = false; @@ -110,7 +97,7 @@ static uint32_t set_isolation_state(sPAPRDRConnector *drc, static uint32_t set_indicator_state(sPAPRDRConnector *drc, sPAPRDRIndicatorState state) { - DPRINTFN("drc: %x, set_indicator_state: %x", get_index(drc), state); + trace_spapr_drc_set_indicator_state(get_index(drc), state); drc->indicator_state = state; return RTAS_OUT_SUCCESS; } @@ -120,7 +107,7 @@ static uint32_t set_allocation_state(sPAPRDRConnector *drc, { sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - DPRINTFN("drc: %x, set_allocation_state: %x", get_index(drc), state); + trace_spapr_drc_set_allocation_state(get_index(drc), state); if (state == SPAPR_DR_ALLOCATION_STATE_USABLE) { /* if there's no resource/device associated with the DRC, there's @@ -137,7 +124,7 @@ static uint32_t set_allocation_state(sPAPRDRConnector *drc, drc->allocation_state = state; if (drc->awaiting_release && drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) { - DPRINTFN("finalizing device removal"); + trace_spapr_drc_set_allocation_state_finalizing(get_index(drc)); drck->detach(drc, DEVICE(drc->dev), drc->detach_cb, drc->detach_cb_opaque, NULL); } else if (drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_USABLE) { @@ -167,12 +154,11 @@ static const void *get_fdt(sPAPRDRConnector *drc, int *fdt_start_offset) static void set_configured(sPAPRDRConnector *drc) { - DPRINTFN("drc: %x, set_configured", get_index(drc)); + trace_spapr_drc_set_configured(get_index(drc)); if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_UNISOLATED) { /* guest should be not configuring an isolated device */ - DPRINTFN("drc: %x, set_configured: skipping isolated device", - get_index(drc)); + trace_spapr_drc_set_configured_skipping(get_index(drc)); return; } drc->configured = true; @@ -222,7 +208,7 @@ static uint32_t entity_sense(sPAPRDRConnector *drc, sPAPRDREntitySense *state) } } - DPRINTFN("drc: %x, entity_sense: %x", get_index(drc), state); + trace_spapr_drc_entity_sense(get_index(drc), *state); return RTAS_OUT_SUCCESS; } @@ -336,7 +322,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt, int fdt_start_offset, bool coldplug, Error **errp) { - DPRINTFN("drc: %x, attach", get_index(drc)); + trace_spapr_drc_attach(get_index(drc)); if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) { error_setg(errp, "an attached device is still awaiting release"); @@ -389,7 +375,7 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d, spapr_drc_detach_cb *detach_cb, void *detach_cb_opaque, Error **errp) { - DPRINTFN("drc: %x, detach", get_index(drc)); + trace_spapr_drc_detach(get_index(drc)); drc->detach_cb = detach_cb; drc->detach_cb_opaque = detach_cb_opaque; @@ -415,21 +401,21 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d, } if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) { - DPRINTFN("awaiting transition to isolated state before removal"); + trace_spapr_drc_awaiting_isolated(get_index(drc)); drc->awaiting_release = true; return; } if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI && drc->allocation_state != SPAPR_DR_ALLOCATION_STATE_UNUSABLE) { - DPRINTFN("awaiting transition to unusable state before removal"); + trace_spapr_drc_awaiting_unusable(get_index(drc)); drc->awaiting_release = true; return; } if (drc->awaiting_allocation) { drc->awaiting_release = true; - DPRINTFN("awaiting allocation to complete before removal"); + trace_spapr_drc_awaiting_allocation(get_index(drc)); return; } @@ -460,7 +446,7 @@ static void reset(DeviceState *d) sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); sPAPRDREntitySense state; - DPRINTFN("drc reset: %x", drck->get_index(drc)); + trace_spapr_drc_reset(drck->get_index(drc)); /* immediately upon reset we can safely assume DRCs whose devices * are pending removal can be safely removed, and that they will * subsequently be left in an ISOLATED state. move the DRC to this @@ -502,7 +488,7 @@ static void realize(DeviceState *d, Error **errp) gchar *child_name; Error *err = NULL; - DPRINTFN("drc realize: %x", drck->get_index(drc)); + trace_spapr_drc_realize(drck->get_index(drc)); /* NOTE: we do this as part of realize/unrealize due to the fact * that the guest will communicate with the DRC via RTAS calls * referencing the global DRC index. By unlinking the DRC @@ -513,7 +499,7 @@ static void realize(DeviceState *d, Error **errp) root_container = container_get(object_get_root(), DRC_CONTAINER_PATH); snprintf(link_name, sizeof(link_name), "%x", drck->get_index(drc)); child_name = object_get_canonical_path_component(OBJECT(drc)); - DPRINTFN("drc child name: %s", child_name); + trace_spapr_drc_realize_child(drck->get_index(drc), child_name); object_property_add_alias(root_container, link_name, drc->owner, child_name, &err); if (err) { @@ -521,7 +507,7 @@ static void realize(DeviceState *d, Error **errp) object_unref(OBJECT(drc)); } g_free(child_name); - DPRINTFN("drc realize complete"); + trace_spapr_drc_realize_complete(drck->get_index(drc)); } static void unrealize(DeviceState *d, Error **errp) @@ -532,7 +518,7 @@ static void unrealize(DeviceState *d, Error **errp) char name[256]; Error *err = NULL; - DPRINTFN("drc unrealize: %x", drck->get_index(drc)); + trace_spapr_drc_unrealize(drck->get_index(drc)); root_container = container_get(object_get_root(), DRC_CONTAINER_PATH); snprintf(name, sizeof(name), "%x", drck->get_index(drc)); object_property_del(root_container, name, &err); diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 73af112..290a712 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -201,7 +201,7 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr, switch (ret) { case REMOVE_SUCCESS: - check_tlb_flush(env); + check_tlb_flush(env, true); return H_SUCCESS; case REMOVE_NOT_FOUND: @@ -282,7 +282,7 @@ static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr, } } exit: - check_tlb_flush(env); + check_tlb_flush(env, true); return rc; } @@ -319,6 +319,8 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr, ppc_hash64_store_hpte(cpu, pte_index, (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0); ppc_hash64_tlb_flush_hpte(cpu, pte_index, v, r); + /* Flush the tlb */ + check_tlb_flush(env, true); /* Don't need a memory barrier, due to qemu's global lock */ ppc_hash64_store_hpte(cpu, pte_index, v | HPTE64_V_HPTE_DIRTY, r); return H_SUCCESS; diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 949c44f..4f00865 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -47,6 +47,7 @@ #include "sysemu/device_tree.h" #include "sysemu/kvm.h" #include "sysemu/hostmem.h" +#include "sysemu/numa.h" #include "hw/vfio/vfio.h" @@ -1544,6 +1545,7 @@ static Property spapr_phb_properties[] = { DEFINE_PROP_BOOL("ddw", sPAPRPHBState, ddw_enabled, true), DEFINE_PROP_UINT64("pgsz", sPAPRPHBState, page_size_mask, (1ULL << 12) | (1ULL << 16)), + DEFINE_PROP_UINT32("numa_node", sPAPRPHBState, numa_node, -1), DEFINE_PROP_END_OF_LIST(), }; @@ -1805,6 +1807,11 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, cpu_to_be32(1), cpu_to_be32(RTAS_IBM_RESET_PE_DMA_WINDOW) }; + uint32_t associativity[] = {cpu_to_be32(0x4), + cpu_to_be32(0x0), + cpu_to_be32(0x0), + cpu_to_be32(0x0), + cpu_to_be32(phb->numa_node)}; sPAPRTCETable *tcet; PCIBus *bus = PCI_HOST_BRIDGE(phb)->bus; sPAPRFDT s_fdt; @@ -1837,6 +1844,12 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, &ddw_extensions, sizeof(ddw_extensions))); } + /* Advertise NUMA via ibm,associativity */ + if (nb_numa_nodes > 1) { + _FDT(fdt_setprop(fdt, bus_off, "ibm,associativity", associativity, + sizeof(associativity))); + } + /* Build the interrupt-map, this must matches what is done * in pci_spapr_map_irq */ diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 27b5ad4..0db84c8 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -37,6 +37,7 @@ #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" +#include "hw/ppc/spapr_rtas.h" #include "hw/ppc/ppc.h" #include "qapi-event.h" #include "hw/boards.h" @@ -44,16 +45,7 @@ #include <libfdt.h> #include "hw/ppc/spapr_drc.h" #include "qemu/cutils.h" - -/* #define DEBUG_SPAPR */ - -#ifdef DEBUG_SPAPR -#define DPRINTF(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif +#include "trace.h" static sPAPRConfigureConnectorState *spapr_ccs_find(sPAPRMachineState *spapr, uint32_t drc_index) @@ -303,7 +295,8 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu, break; } case RTAS_SYSPARM_UUID: - ret = sysparm_st(buffer, length, qemu_uuid, (qemu_uuid_set ? 16 : 0)); + ret = sysparm_st(buffer, length, (unsigned char *)&qemu_uuid, + (qemu_uuid_set ? 16 : 0)); break; default: ret = RTAS_OUT_NOT_SUPPORTED; @@ -435,8 +428,7 @@ static void rtas_set_indicator(PowerPCCPU *cpu, sPAPRMachineState *spapr, /* if this is a DR sensor we can assume sensor_index == drc_index */ drc = spapr_dr_connector_by_index(sensor_index); if (!drc) { - DPRINTF("rtas_set_indicator: invalid sensor/DRC index: %xh\n", - sensor_index); + trace_spapr_rtas_set_indicator_invalid(sensor_index); ret = RTAS_OUT_PARAM_ERROR; goto out; } @@ -475,8 +467,7 @@ out: out_unimplemented: /* currently only DR-related sensors are implemented */ - DPRINTF("rtas_set_indicator: sensor/indicator not implemented: %d\n", - sensor_type); + trace_spapr_rtas_set_indicator_not_supported(sensor_index, sensor_type); rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED); } @@ -502,16 +493,15 @@ static void rtas_get_sensor_state(PowerPCCPU *cpu, sPAPRMachineState *spapr, if (sensor_type != RTAS_SENSOR_TYPE_ENTITY_SENSE) { /* currently only DR-related sensors are implemented */ - DPRINTF("rtas_get_sensor_state: sensor/indicator not implemented: %d\n", - sensor_type); + trace_spapr_rtas_get_sensor_state_not_supported(sensor_index, + sensor_type); ret = RTAS_OUT_NOT_SUPPORTED; goto out; } drc = spapr_dr_connector_by_index(sensor_index); if (!drc) { - DPRINTF("rtas_get_sensor_state: invalid sensor/DRC index: %xh\n", - sensor_index); + trace_spapr_rtas_get_sensor_state_invalid(sensor_index); ret = RTAS_OUT_PARAM_ERROR; goto out; } @@ -568,8 +558,7 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu, drc_index = rtas_ld(wa_addr, 0); drc = spapr_dr_connector_by_index(drc_index); if (!drc) { - DPRINTF("rtas_ibm_configure_connector: invalid DRC index: %xh\n", - drc_index); + trace_spapr_rtas_ibm_configure_connector_invalid(drc_index); rc = RTAS_OUT_PARAM_ERROR; goto out; } @@ -577,8 +566,7 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu, drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); fdt = drck->get_fdt(drc, NULL); if (!fdt) { - DPRINTF("rtas_ibm_configure_connector: Missing FDT for DRC index: %xh\n", - drc_index); + trace_spapr_rtas_ibm_configure_connector_missing_fdt(drc_index); rc = SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE; goto out; } @@ -692,6 +680,24 @@ target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPRMachineState *spapr, return H_PARAMETER; } +uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args, + uint32_t nret, uint64_t rets) +{ + int token; + + for (token = 0; token < RTAS_TOKEN_MAX - RTAS_TOKEN_BASE; token++) { + if (strcmp(cmd, rtas_table[token].name) == 0) { + sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + PowerPCCPU *cpu = POWERPC_CPU(first_cpu); + + rtas_table[token].fn(cpu, spapr, token + RTAS_TOKEN_BASE, + nargs, args, nret, rets); + return H_SUCCESS; + } + } + return H_PARAMETER; +} + void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn) { assert((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX)); diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 497028f..d68dd35 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -36,19 +36,10 @@ #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" #include "hw/ppc/xics.h" +#include "trace.h" #include <libfdt.h> -/* #define DEBUG_SPAPR */ - -#ifdef DEBUG_SPAPR -#define DPRINTF(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif - static Property spapr_vio_props[] = { DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, irq, 0), \ DEFINE_PROP_END_OF_LIST(), @@ -202,9 +193,7 @@ static target_ulong h_reg_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr, dev->crq.qsize = queue_len; dev->crq.qnext = 0; - DPRINTF("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x" - TARGET_FMT_lx "/0x" TARGET_FMT_lx "\n", - reg, queue_addr, queue_len); + trace_spapr_vio_h_reg_crq(reg, queue_addr, queue_len); return H_SUCCESS; } @@ -214,7 +203,7 @@ static target_ulong free_crq(VIOsPAPRDevice *dev) dev->crq.qsize = 0; dev->crq.qnext = 0; - DPRINTF("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg); + trace_spapr_vio_free_crq(dev->reg); return H_SUCCESS; } diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index dfeab93..2297ead 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -35,6 +35,39 @@ spapr_iommu_ddw_create(uint64_t buid, uint32_t cfgaddr, uint64_t pg_size, uint64 spapr_iommu_ddw_remove(uint32_t liobn) "liobn=%"PRIx32 spapr_iommu_ddw_reset(uint64_t buid, uint32_t cfgaddr) "buid=%"PRIx64" addr=%"PRIx32 +# hw/ppc/spapr_drc.c +spapr_drc_set_isolation_state(uint32_t index, int state) "drc: 0x%"PRIx32", state: %"PRIx32 +spapr_drc_set_isolation_state_finalizing(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_set_isolation_state_deferring(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_set_indicator_state(uint32_t index, int state) "drc: 0x%"PRIx32", state: 0x%x" +spapr_drc_set_allocation_state(uint32_t index, int state) "drc: 0x%"PRIx32", state: 0x%x" +spapr_drc_set_allocation_state_finalizing(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_set_configured(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_set_configured_skipping(uint32_t index) "drc: 0x%"PRIx32", isolated device" +spapr_drc_entity_sense(uint32_t index, int state) "drc: 0x%"PRIx32", state: 0x%x" +spapr_drc_attach(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_detach(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_awaiting_isolated(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_awaiting_unusable(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_awaiting_allocation(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_reset(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_realize(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_realize_child(uint32_t index, char *childname) "drc: 0x%"PRIx32", child name: %s" +spapr_drc_realize_complete(uint32_t index) "drc: 0x%"PRIx32 +spapr_drc_unrealize(uint32_t index) "drc: 0x%"PRIx32 + +# hw/ppc/spapr_rtas.c +spapr_rtas_set_indicator_invalid(uint32_t index) "sensor index: 0x%"PRIx32 +spapr_rtas_set_indicator_not_supported(uint32_t index, uint32_t type) "sensor index: 0x%"PRIx32", type: %"PRIu32 +spapr_rtas_get_sensor_state_not_supported(uint32_t index, uint32_t type) "sensor index: 0x%"PRIx32", type: %"PRIu32 +spapr_rtas_get_sensor_state_invalid(uint32_t index) "sensor index: 0x%"PRIx32 +spapr_rtas_ibm_configure_connector_invalid(uint32_t index) "DRC index: 0x%"PRIx32 +spapr_rtas_ibm_configure_connector_missing_fdt(uint32_t index) "DRC index: 0x%"PRIx32 + +# hw/ppc/spapr_vio.c +spapr_vio_h_reg_crq(uint64_t reg, uint64_t queue_addr, uint64_t queue_len) "CRQ for dev 0x%" PRIx64 " registered at 0x%" PRIx64 "/0x%" PRIx64 +spapr_vio_free_crq(uint32_t reg) "CRQ for dev 0x%" PRIx32 " freed" + # hw/ppc/ppc.c ppc_tb_adjust(uint64_t offs1, uint64_t offs2, int64_t diff, int64_t seconds) "adjusted from 0x%"PRIx64" to 0x%"PRIx64", diff %"PRId64" (%"PRId64"s)" diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index 8fbd50f..d8a2296 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -42,19 +42,10 @@ #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" #include "viosrp.h" +#include "trace.h" #include <libfdt.h> -/*#define DEBUG_VSCSI*/ - -#ifdef DEBUG_VSCSI -#define DPRINTF(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif - /* * Virtual SCSI device */ @@ -237,8 +228,7 @@ static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req, int total_len = sizeof(iu->srp.rsp); uint8_t sol_not = iu->srp.cmd.sol_not; - DPRINTF("VSCSI: Sending resp status: 0x%x, " - "res_in: %d, res_out: %d\n", status, res_in, res_out); + trace_spapr_vscsi_send_rsp(status, res_in, res_out); memset(iu, 0, sizeof(struct srp_rsp)); iu->srp.rsp.opcode = SRP_RSP; @@ -298,13 +288,13 @@ static int vscsi_fetch_desc(VSCSIState *s, struct vscsi_req *req, switch (req->dma_fmt) { case SRP_NO_DATA_DESC: { - DPRINTF("VSCSI: no data descriptor\n"); + trace_spapr_vscsi_fetch_desc_no_data(); return 0; } case SRP_DATA_DESC_DIRECT: { memcpy(ret, cmd->add_data + req->cdb_offset, sizeof(*ret)); assert(req->cur_desc_num == 0); - DPRINTF("VSCSI: direct segment\n"); + trace_spapr_vscsi_fetch_desc_direct(); break; } case SRP_DATA_DESC_INDIRECT: { @@ -312,30 +302,29 @@ static int vscsi_fetch_desc(VSCSIState *s, struct vscsi_req *req, (cmd->add_data + req->cdb_offset); if (n < req->local_desc) { *ret = tmp->desc_list[n]; - DPRINTF("VSCSI: indirect segment local tag=0x%x desc#%d/%d\n", - req->qtag, n, req->local_desc); - + trace_spapr_vscsi_fetch_desc_indirect(req->qtag, n, + req->local_desc); } else if (n < req->total_desc) { int rc; struct srp_direct_buf tbl_desc = vscsi_swap_desc(tmp->table_desc); unsigned desc_offset = n * sizeof(struct srp_direct_buf); if (desc_offset >= tbl_desc.len) { - DPRINTF("VSCSI: #%d is ouf of range (%d bytes)\n", - n, desc_offset); + trace_spapr_vscsi_fetch_desc_out_of_range(n, desc_offset); return -1; } rc = spapr_vio_dma_read(&s->vdev, tbl_desc.va + desc_offset, ret, sizeof(struct srp_direct_buf)); if (rc) { - DPRINTF("VSCSI: spapr_vio_dma_read -> %d reading ext_desc\n", - rc); + trace_spapr_vscsi_fetch_desc_dma_read_error(rc); return -1; } - DPRINTF("VSCSI: indirect segment ext. tag=0x%x desc#%d/%d { va=%"PRIx64" len=%x }\n", - req->qtag, n, req->total_desc, tbl_desc.va, tbl_desc.len); + trace_spapr_vscsi_fetch_desc_indirect_seg_ext(req->qtag, n, + req->total_desc, + tbl_desc.va, + tbl_desc.len); } else { - DPRINTF("VSCSI: Out of descriptors !\n"); + trace_spapr_vscsi_fetch_desc_out_of_desc(); return 0; } break; @@ -347,15 +336,16 @@ static int vscsi_fetch_desc(VSCSIState *s, struct vscsi_req *req, *ret = vscsi_swap_desc(*ret); if (buf_offset > ret->len) { - DPRINTF(" offset=%x is out of a descriptor #%d boundary=%x\n", - buf_offset, req->cur_desc_num, ret->len); + trace_spapr_vscsi_fetch_desc_out_of_desc_boundary(buf_offset, + req->cur_desc_num, + ret->len); return -1; } ret->va += buf_offset; ret->len -= buf_offset; - DPRINTF(" cur=%d offs=%x ret { va=%"PRIx64" len=%x }\n", - req->cur_desc_num, req->cur_desc_offset, ret->va, ret->len); + trace_spapr_vscsi_fetch_desc_done(req->cur_desc_num, req->cur_desc_offset, + ret->va, ret->len); return ret->len ? 1 : 0; } @@ -398,7 +388,7 @@ static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req, int rc = 0; uint32_t llen, total = 0; - DPRINTF("VSCSI: indirect segment 0x%x bytes\n", len); + trace_spapr_vscsi_srp_indirect_data(len); /* While we have data ... */ while (len) { @@ -417,11 +407,10 @@ static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req, rc = spapr_vio_dma_write(&s->vdev, md.va, buf, llen); } if (rc) { - DPRINTF("VSCSI: spapr_vio_dma_r/w(%d) -> %d\n", req->writing, rc); + trace_spapr_vscsi_srp_indirect_data_rw(req->writing, rc); break; } - DPRINTF("VSCSI: data: %02x %02x %02x %02x...\n", - buf[0], buf[1], buf[2], buf[3]); + trace_spapr_vscsi_srp_indirect_data_buf(buf[0], buf[1], buf[2], buf[3]); len -= llen; buf += llen; @@ -447,7 +436,7 @@ static int vscsi_srp_transfer_data(VSCSIState *s, vscsi_req *req, switch (req->dma_fmt) { case SRP_NO_DATA_DESC: - DPRINTF("VSCSI: no data desc transfer, skipping 0x%x bytes\n", len); + trace_spapr_vscsi_srp_transfer_data(len); break; case SRP_DATA_DESC_DIRECT: err = vscsi_srp_direct_data(s, req, buf, len); @@ -527,8 +516,7 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) uint8_t *buf; int rc = 0; - DPRINTF("VSCSI: SCSI xfer complete tag=0x%x len=0x%x, req=%p\n", - sreq->tag, len, req); + trace_spapr_vscsi_transfer_data(sreq->tag, len, req); if (req == NULL) { fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); return; @@ -557,8 +545,7 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t re vscsi_req *req = sreq->hba_private; int32_t res_in = 0, res_out = 0; - DPRINTF("VSCSI: SCSI cmd complete, tag=0x%x status=0x%x, req=%p\n", - sreq->tag, status, req); + trace_spapr_vscsi_command_complete(sreq->tag, status, req); if (req == NULL) { fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); return; @@ -567,16 +554,15 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t re if (status == CHECK_CONDITION) { req->senselen = scsi_req_get_sense(req->sreq, req->sense, sizeof(req->sense)); - DPRINTF("VSCSI: Sense data, %d bytes:\n", req->senselen); - DPRINTF(" %02x %02x %02x %02x %02x %02x %02x %02x\n", + trace_spapr_vscsi_command_complete_sense_data1(req->senselen, req->sense[0], req->sense[1], req->sense[2], req->sense[3], req->sense[4], req->sense[5], req->sense[6], req->sense[7]); - DPRINTF(" %02x %02x %02x %02x %02x %02x %02x %02x\n", + trace_spapr_vscsi_command_complete_sense_data2( req->sense[8], req->sense[9], req->sense[10], req->sense[11], req->sense[12], req->sense[13], req->sense[14], req->sense[15]); } - DPRINTF("VSCSI: Command complete err=%d\n", status); + trace_spapr_vscsi_command_complete_status(status); if (status == 0) { /* We handle overflows, not underflows for normal commands, * but hopefully nobody cares @@ -635,8 +621,8 @@ static void vscsi_save_request(QEMUFile *f, SCSIRequest *sreq) vmstate_save_state(f, &vmstate_spapr_vscsi_req, req, NULL); - DPRINTF("VSCSI: saving tag=%u, current desc#%d, offset=%x\n", - req->qtag, req->cur_desc_num, req->cur_desc_offset); + trace_spapr_vscsi_save_request(req->qtag, req->cur_desc_num, + req->cur_desc_offset); } static void *vscsi_load_request(QEMUFile *f, SCSIRequest *sreq) @@ -660,8 +646,8 @@ static void *vscsi_load_request(QEMUFile *f, SCSIRequest *sreq) req->sreq = scsi_req_ref(sreq); - DPRINTF("VSCSI: restoring tag=%u, current desc#%d, offset=%x\n", - req->qtag, req->cur_desc_num, req->cur_desc_offset); + trace_spapr_vscsi_load_request(req->qtag, req->cur_desc_num, + req->cur_desc_offset); return req; } @@ -672,7 +658,7 @@ static void vscsi_process_login(VSCSIState *s, vscsi_req *req) struct srp_login_rsp *rsp = &iu->srp.login_rsp; uint64_t tag = iu->srp.rsp.tag; - DPRINTF("VSCSI: Got login, sendin response !\n"); + trace_spapr_vscsi__process_login(); /* TODO handle case that requested size is wrong and * buffer format is wrong @@ -795,8 +781,7 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun); if (!sdev) { - DPRINTF("VSCSI: Command for lun %08" PRIx64 " with no drive\n", - be64_to_cpu(srp->cmd.lun)); + trace_spapr_vscsi_queue_cmd_no_drive(be64_to_cpu(srp->cmd.lun)); if (srp->cmd.cdb[0] == INQUIRY) { vscsi_inquiry_no_target(s, req); } else { @@ -808,9 +793,8 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, req); n = scsi_req_enqueue(req->sreq); - DPRINTF("VSCSI: Queued command tag 0x%x CMD 0x%x=%s LUN %d ret: %d\n", - req->qtag, srp->cmd.cdb[0], scsi_command_name(srp->cmd.cdb[0]), - lun, n); + trace_spapr_vscsi_queue_cmd(req->qtag, srp->cmd.cdb[0], + scsi_command_name(srp->cmd.cdb[0]), lun, n); if (n) { /* Transfer direction must be set before preprocessing the @@ -1141,7 +1125,7 @@ static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data) crq.s.IU_length = be16_to_cpu(crq.s.IU_length); crq.s.IU_data_ptr = be64_to_cpu(crq.s.IU_data_ptr); - DPRINTF("VSCSI: do_crq %02x %02x ...\n", crq.raw[0], crq.raw[1]); + trace_spapr_vscsi_do_crq(crq.raw[0], crq.raw[1]); switch (crq.s.valid) { case 0xc0: /* Init command/response */ diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events index ed64858..d1995b8 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -202,3 +202,30 @@ esp_pci_dma_abort(uint32_t val) "ABORT (%.8x)" esp_pci_dma_start(uint32_t val) "START (%.8x)" esp_pci_sbac_read(uint32_t reg) "sbac: 0x%8.8x" esp_pci_sbac_write(uint32_t reg, uint32_t val) "sbac: 0x%8.8x -> 0x%8.8x" + +# hw/scsi/spapr_vscsi.c +spapr_vscsi_send_rsp(uint8_t status, int32_t res_in, int32_t res_out) "status: 0x%x, res_in: %"PRId32", res_out: %"PRId32 +spapr_vscsi_fetch_desc_no_data(void) "no data descriptor" +spapr_vscsi_fetch_desc_direct(void) "direct segment" +spapr_vscsi_fetch_desc_indirect(uint32_t qtag, unsigned desc, unsigned local_desc) "indirect segment local tag=0x%"PRIx32" desc#%u/%u" +spapr_vscsi_fetch_desc_out_of_range(unsigned desc, unsigned desc_offset) "#%u is ouf of range (%u bytes)" +spapr_vscsi_fetch_desc_dma_read_error(int rc) "spapr_vio_dma_read -> %d reading ext_desc" +spapr_vscsi_fetch_desc_indirect_seg_ext(uint32_t qtag, unsigned n, unsigned desc, uint64_t va, uint32_t len) "indirect segment ext. tag=0x%"PRIx32" desc#%u/%u { va=0x%"PRIx64" len=0x%"PRIx32" }" +spapr_vscsi_fetch_desc_out_of_desc(void) "Out of descriptors !" +spapr_vscsi_fetch_desc_out_of_desc_boundary(unsigned offset, unsigned desc, uint32_t len) " offset=0x%x is out of a descriptor #%u boundary=%"PRIx32 +spapr_vscsi_fetch_desc_done(unsigned desc_num, unsigned desc_offset, uint64_t va, uint32_t len) " cur=%u offs=0x%x ret { va=0x%"PRIx64" len=0x%"PRIx32" }" +spapr_vscsi_srp_indirect_data(uint32_t len) "indirect segment 0x%"PRIx32" bytes" +spapr_vscsi_srp_indirect_data_rw(int writing, int rc) "spapr_vio_dma_r/w(%d) -> %d" +spapr_vscsi_srp_indirect_data_buf(unsigned a, unsigned b, unsigned c, unsigned d) " data: %02x %02x %02x %02x..." +spapr_vscsi_srp_transfer_data(uint32_t len) "no data desc transfer, skipping 0x%"PRIx32" bytes" +spapr_vscsi_transfer_data(uint32_t tag, uint32_t len, void *req) "SCSI xfer complete tag=0x%"PRIx32" len=0x%"PRIx32", req=%p" +spapr_vscsi_command_complete(uint32_t tag, uint32_t status, void *req) "SCSI cmd complete, tag=0x%"PRIx32" status=0x%"PRIx32", req=%p" +spapr_vscsi_command_complete_sense_data1(uint32_t len, unsigned s0, unsigned s1, unsigned s2, unsigned s3, unsigned s4, unsigned s5, unsigned s6, unsigned s7) "Sense data, %d bytes: %02x %02x %02x %02x %02x %02x %02x %02x" +spapr_vscsi_command_complete_sense_data2(unsigned s8, unsigned s9, unsigned s10, unsigned s11, unsigned s12, unsigned s13, unsigned s14, unsigned s15) " %02x %02x %02x %02x %02x %02x %02x %02x" +spapr_vscsi_command_complete_status(uint32_t status) "Command complete err=%"PRIu32 +spapr_vscsi_save_request(uint32_t qtag, unsigned desc, unsigned offset) "saving tag=%"PRIu32", current desc#%u, offset=0x%x" +spapr_vscsi_load_request(uint32_t qtag, unsigned desc, unsigned offset) "restoring tag=%"PRIu32", current desc#%u, offset=0x%x" +spapr_vscsi__process_login(void) "Got login, sending response !" +spapr_vscsi_queue_cmd_no_drive(uint64_t lun) "Command for lun %08" PRIx64 " with no drive" +spapr_vscsi_queue_cmd(uint32_t qtag, unsigned cdb, const char *cmd, int lun, int ret) "Queued command tag 0x%"PRIx32" CMD 0x%x=%s LUN %d ret: %d" +spapr_vscsi_do_crq(unsigned c0, unsigned c1) "crq: %02x %02x ..." diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 3ff0886..24001dc 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/smbios/smbios.c b/hw/smbios/smbios.c index 74c7102..9a6552a 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -20,6 +20,7 @@ #include "qemu/config-file.h" #include "qemu/error-report.h" #include "sysemu/sysemu.h" +#include "qemu/uuid.h" #include "sysemu/cpus.h" #include "hw/smbios/smbios.h" #include "hw/loader.h" @@ -79,7 +80,7 @@ static struct { static struct { const char *manufacturer, *product, *version, *serial, *sku, *family; - /* uuid is in qemu_uuid[] */ + /* uuid is in qemu_uuid */ } type1; static struct { @@ -408,7 +409,7 @@ static void smbios_build_type_1_fields(void) * BIOS. */ smbios_add_field(1, offsetof(struct smbios_type_1, uuid), - qemu_uuid, 16); + &qemu_uuid, 16); } } @@ -483,9 +484,9 @@ static void smbios_build_type_0_table(void) /* Encode UUID from the big endian encoding described on RFC4122 to the wire * format specified by SMBIOS version 2.6. */ -static void smbios_encode_uuid(struct smbios_uuid *uuid, const uint8_t *buf) +static void smbios_encode_uuid(struct smbios_uuid *uuid, QemuUUID *in) { - memcpy(uuid, buf, 16); + memcpy(uuid, &in, 16); if (smbios_uuid_encoded) { uuid->time_low = bswap32(uuid->time_low); uuid->time_mid = bswap16(uuid->time_mid); @@ -502,7 +503,7 @@ static void smbios_build_type_1_table(void) SMBIOS_TABLE_SET_STR(1, version_str, type1.version); SMBIOS_TABLE_SET_STR(1, serial_number_str, type1.serial); if (qemu_uuid_set) { - smbios_encode_uuid(&t->uuid, qemu_uuid); + smbios_encode_uuid(&t->uuid, &qemu_uuid); } else { memset(&t->uuid, 0, 16); } @@ -1001,7 +1002,7 @@ void smbios_entry_add(QemuOpts *opts) val = qemu_opt_get(opts, "uuid"); if (val) { - if (qemu_uuid_parse(val, qemu_uuid) != 0) { + if (qemu_uuid_parse(val, &qemu_uuid) != 0) { error_report("Invalid UUID"); exit(1); } diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c index 4226199..e4e395f 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 3385e5d..22ceabe 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 111a16d..98fddd7 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 0f21faf..e1fcf73 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 36d8f46..8e18236 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 ae69345..0c18934 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 0e9e2e9..f576507 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 da4dd45..1a648c5 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 dd000f5..712d1ae 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 eddf348..8677b75 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 82bc73c..010ccbf 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 e45a65b..2a07b59 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 2194832..4488590 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 93650b7..0b3d717 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 255b2fc..9afb2d0 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 fb3e08b..bfee1f3 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 2ea970d..59439c0 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/hw/xenpv/xen_domainbuild.c b/hw/xenpv/xen_domainbuild.c index 5a9f5ac..b439b0e 100644 --- a/hw/xenpv/xen_domainbuild.c +++ b/hw/xenpv/xen_domainbuild.c @@ -53,11 +53,7 @@ int xenstore_domain_init1(const char *kernel, const char *ramdisk, char *dom, uuid_string[42], vm[256], path[256]; int i; - snprintf(uuid_string, sizeof(uuid_string), UUID_FMT, - qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], qemu_uuid[3], - qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], qemu_uuid[7], - qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], qemu_uuid[11], - qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], qemu_uuid[15]); + qemu_uuid_unparse(&qemu_uuid, uuid_string); dom = xs_get_domain_path(xenstore, xen_domid); snprintf(vm, sizeof(vm), "/vm/%s", uuid_string); diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h new file mode 100644 index 0000000..932704c --- /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 e68807d..0000000 --- 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 d40e5c8..9f5119a 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 f510e7e..25659b9 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/input/adb-keys.h b/include/hw/input/adb-keys.h new file mode 100644 index 0000000..525fba8 --- /dev/null +++ b/include/hw/input/adb-keys.h @@ -0,0 +1,141 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2016 John Arbuckle + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +/* + * adb-keys.h + * + * Provides an enum of all the Macintosh keycodes. + * Additional information: http://www.archive.org/stream/apple-guide-macintosh-family-hardware/Apple_Guide_to_the_Macintosh_Family_Hardware_2e#page/n345/mode/2up + * page 308 + */ + +#ifndef ADB_KEYS_H +#define ADB_KEYS_H + +enum { + ADB_KEY_A = 0x00, + ADB_KEY_B = 0x0b, + ADB_KEY_C = 0x08, + ADB_KEY_D = 0x02, + ADB_KEY_E = 0x0e, + ADB_KEY_F = 0x03, + ADB_KEY_G = 0x05, + ADB_KEY_H = 0x04, + ADB_KEY_I = 0x22, + ADB_KEY_J = 0x26, + ADB_KEY_K = 0x28, + ADB_KEY_L = 0x25, + ADB_KEY_M = 0x2e, + ADB_KEY_N = 0x2d, + ADB_KEY_O = 0x1f, + ADB_KEY_P = 0x23, + ADB_KEY_Q = 0x0c, + ADB_KEY_R = 0x0f, + ADB_KEY_S = 0x01, + ADB_KEY_T = 0x11, + ADB_KEY_U = 0x20, + ADB_KEY_V = 0x09, + ADB_KEY_W = 0x0d, + ADB_KEY_X = 0x07, + ADB_KEY_Y = 0x10, + ADB_KEY_Z = 0x06, + + ADB_KEY_0 = 0x1d, + ADB_KEY_1 = 0x12, + ADB_KEY_2 = 0x13, + ADB_KEY_3 = 0x14, + ADB_KEY_4 = 0x15, + ADB_KEY_5 = 0x17, + ADB_KEY_6 = 0x16, + ADB_KEY_7 = 0x1a, + ADB_KEY_8 = 0x1c, + ADB_KEY_9 = 0x19, + + ADB_KEY_GRAVE_ACCENT = 0x32, + ADB_KEY_MINUS = 0x1b, + ADB_KEY_EQUAL = 0x18, + ADB_KEY_DELETE = 0x33, + ADB_KEY_CAPS_LOCK = 0x39, + ADB_KEY_TAB = 0x30, + ADB_KEY_RETURN = 0x24, + ADB_KEY_LEFT_BRACKET = 0x21, + ADB_KEY_RIGHT_BRACKET = 0x1e, + ADB_KEY_BACKSLASH = 0x2a, + ADB_KEY_SEMICOLON = 0x29, + ADB_KEY_APOSTROPHE = 0x27, + ADB_KEY_COMMA = 0x2b, + ADB_KEY_PERIOD = 0x2f, + ADB_KEY_FORWARD_SLASH = 0x2c, + ADB_KEY_LEFT_SHIFT = 0x38, + ADB_KEY_RIGHT_SHIFT = 0x7b, + ADB_KEY_SPACEBAR = 0x31, + ADB_KEY_LEFT_CONTROL = 0x36, + ADB_KEY_RIGHT_CONTROL = 0x7d, + ADB_KEY_LEFT_OPTION = 0x3a, + ADB_KEY_RIGHT_OPTION = 0x7c, + ADB_KEY_COMMAND = 0x37, + + ADB_KEY_KP_0 = 0x52, + ADB_KEY_KP_1 = 0x53, + ADB_KEY_KP_2 = 0x54, + ADB_KEY_KP_3 = 0x55, + ADB_KEY_KP_4 = 0x56, + ADB_KEY_KP_5 = 0x57, + ADB_KEY_KP_6 = 0x58, + ADB_KEY_KP_7 = 0x59, + ADB_KEY_KP_8 = 0x5b, + ADB_KEY_KP_9 = 0x5c, + ADB_KEY_KP_PERIOD = 0x41, + ADB_KEY_KP_ENTER = 0x4c, + ADB_KEY_KP_PLUS = 0x45, + ADB_KEY_KP_SUBTRACT = 0x4e, + ADB_KEY_KP_MULTIPLY = 0x43, + ADB_KEY_KP_DIVIDE = 0x4b, + ADB_KEY_KP_EQUAL = 0x51, + ADB_KEY_KP_CLEAR = 0x47, + + ADB_KEY_UP = 0x3e, + ADB_KEY_DOWN = 0x3d, + ADB_KEY_LEFT = 0x3b, + ADB_KEY_RIGHT = 0x3c, + + ADB_KEY_HELP = 0x72, + ADB_KEY_HOME = 0x73, + ADB_KEY_PAGE_UP = 0x74, + ADB_KEY_PAGE_DOWN = 0x79, + ADB_KEY_END = 0x77, + ADB_KEY_FORWARD_DELETE = 0x75, + + ADB_KEY_ESC = 0x35, + ADB_KEY_F1 = 0x7a, + ADB_KEY_F2 = 0x78, + ADB_KEY_F3 = 0x63, + ADB_KEY_F4 = 0x76, + ADB_KEY_F5 = 0x60, + ADB_KEY_F6 = 0x61, + ADB_KEY_F7 = 0x62, + ADB_KEY_F8 = 0x64, + ADB_KEY_F9 = 0x65, + ADB_KEY_F10 = 0x6d, + ADB_KEY_F11 = 0x67, + ADB_KEY_F12 = 0x6f, + ADB_KEY_F13 = 0x69, + ADB_KEY_F14 = 0x6b, + ADB_KEY_F15 = 0x71, + + ADB_KEY_VOLUME_UP = 0x48, + ADB_KEY_VOLUME_DOWN = 0x49, + ADB_KEY_VOLUME_MUTE = 0x4a, + ADB_KEY_POWER = 0x7f7f +}; + +/* Could not find the value for this key. */ +/* #define ADB_KEY_EJECT */ + +#endif /* ADB_KEYS_H */ diff --git a/include/hw/loader.h b/include/hw/loader.h index 4879b63..0381706 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 fdfd982..14ffc43 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 7e081f6..551c8af 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 f2e08e3..c469ffe 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/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 1a2b11b..30dbd46 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -75,6 +75,8 @@ struct sPAPRPHBState { bool ddw_enabled; uint64_t page_size_mask; uint64_t dma64_win_addr; + + uint32_t numa_node; }; #define SPAPR_PCI_MAX_INDEX 255 diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h index 1c9b319..283969b 100644 --- a/include/hw/ppc/spapr_cpu_core.h +++ b/include/hw/ppc/spapr_cpu_core.h @@ -16,6 +16,10 @@ #define TYPE_SPAPR_CPU_CORE "spapr-cpu-core" #define SPAPR_CPU_CORE(obj) \ OBJECT_CHECK(sPAPRCPUCore, (obj), TYPE_SPAPR_CPU_CORE) +#define SPAPR_CPU_CORE_CLASS(klass) \ + OBJECT_CLASS_CHECK(sPAPRCPUCoreClass, (klass), TYPE_SPAPR_CPU_CORE) +#define SPAPR_CPU_CORE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(sPAPRCPUCoreClass, (obj), TYPE_SPAPR_CPU_CORE) typedef struct sPAPRCPUCore { /*< private >*/ @@ -23,9 +27,13 @@ typedef struct sPAPRCPUCore { /*< public >*/ void *threads; - ObjectClass *cpu_class; } sPAPRCPUCore; +typedef struct sPAPRCPUCoreClass { + DeviceClass parent_class; + ObjectClass *cpu_class; +} sPAPRCPUCoreClass; + void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp); char *spapr_get_cpu_core_type(const char *model); @@ -33,4 +41,5 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp); void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp); +void spapr_cpu_core_class_init(ObjectClass *oc, void *data); #endif diff --git a/include/hw/ppc/spapr_rtas.h b/include/hw/ppc/spapr_rtas.h new file mode 100644 index 0000000..383611f --- /dev/null +++ b/include/hw/ppc/spapr_rtas.h @@ -0,0 +1,10 @@ +#ifndef HW_SPAPR_RTAS_H +#define HW_SPAPR_RTAS_H +/* + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args, + uint32_t nret, uint64_t rets); +#endif /* HW_SPAPR_RTAS_H */ diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 2db9f93..5aac67a 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -149,7 +149,7 @@ struct ICSState { static inline bool ics_valid_irq(ICSState *ics, uint32_t nr) { - return (nr >= ics->offset) + return (ics->offset != 0) && (nr >= ics->offset) && (nr < (ics->offset + ics->nr_irqs)); } diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h index e397db5..26c7fdc 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/uuid.h b/include/qemu/uuid.h new file mode 100644 index 0000000..afe4840 --- /dev/null +++ b/include/qemu/uuid.h @@ -0,0 +1,59 @@ +/* + * QEMU UUID functions + * + * Copyright 2016 Red Hat, Inc. + * + * Authors: + * Fam Zheng <famz@redhat.com> + * + * 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. + * + */ + +#ifndef QEMU_UUID_H +#define QEMU_UUID_H + +#include "qemu-common.h" + +/* Version 4 UUID (pseudo random numbers), RFC4122 4.4. */ + +typedef struct { + union { + unsigned char data[16]; + struct { + /* Generated in BE endian, can be swapped with qemu_uuid_bswap. */ + uint32_t time_low; + uint16_t time_mid; + uint16_t time_high_and_version; + uint8_t clock_seq_and_reserved; + uint8_t clock_seq_low; + uint8_t node[6]; + } fields; + }; +} QemuUUID; + +#define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-" \ + "%02hhx%02hhx-%02hhx%02hhx-" \ + "%02hhx%02hhx-" \ + "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" + +#define UUID_FMT_LEN 36 + +#define UUID_NONE "00000000-0000-0000-0000-000000000000" + +void qemu_uuid_generate(QemuUUID *out); + +int qemu_uuid_is_null(const QemuUUID *uu); + +void qemu_uuid_unparse(const QemuUUID *uuid, char *out); + +char *qemu_uuid_unparse_strdup(const QemuUUID *uuid); + +int qemu_uuid_parse(const char *str, QemuUUID *uuid); + +void qemu_uuid_bswap(QemuUUID *uuid); + +#endif diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index ee7c760..ef2c50b 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -9,6 +9,7 @@ #include "qemu/notify.h" #include "qemu/main-loop.h" #include "qemu/bitmap.h" +#include "qemu/uuid.h" #include "qom/object.h" /* vl.c */ @@ -16,12 +17,8 @@ extern const char *bios_name; extern const char *qemu_name; -extern uint8_t qemu_uuid[]; +extern QemuUUID qemu_uuid; extern bool qemu_uuid_set; -int qemu_uuid_parse(const char *str, uint8_t *uuid); - -#define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" -#define UUID_NONE "00000000-0000-0000-0000-000000000000" bool runstate_check(RunState state); void runstate_set(RunState new_state); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 3d751f8..816272a 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -741,8 +741,12 @@ static uint32_t get_elf_hwcap(void) Altivec/FP/SPE support. Anything else is just a bonus. */ #define GET_FEATURE(flag, feature) \ do { if (cpu->env.insns_flags & flag) { features |= feature; } } while (0) -#define GET_FEATURE2(flag, feature) \ - do { if (cpu->env.insns_flags2 & flag) { features |= feature; } } while (0) +#define GET_FEATURE2(flags, feature) \ + do { \ + if ((cpu->env.insns_flags2 & flags) == flags) { \ + features |= feature; \ + } \ + } while (0) GET_FEATURE(PPC_64B, QEMU_PPC_FEATURE_64); GET_FEATURE(PPC_FLOAT, QEMU_PPC_FEATURE_HAS_FPU); GET_FEATURE(PPC_ALTIVEC, QEMU_PPC_FEATURE_HAS_ALTIVEC); diff --git a/linux-user/main.c b/linux-user/main.c index aba58c7..8daebe0 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1992,12 +1992,12 @@ void cpu_loop(CPUPPCState *env) if (ret == -TARGET_ERESTARTSYS) { break; } - env->nip += 4; if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) { /* Returning from a successful sigreturn syscall. Avoid corrupting register state. */ break; } + env->nip += 4; if (ret > (target_ulong)(-515)) { env->crf[0] |= 0x1; ret = -ret; diff --git a/linux-user/ppc/syscall_nr.h b/linux-user/ppc/syscall_nr.h index 46ed8a6..afa3654 100644 --- a/linux-user/ppc/syscall_nr.h +++ b/linux-user/ppc/syscall_nr.h @@ -120,7 +120,9 @@ #define TARGET_NR_sysinfo 116 #define TARGET_NR_ipc 117 #define TARGET_NR_fsync 118 +#if !defined(TARGET_PPC64) #define TARGET_NR_sigreturn 119 +#endif #define TARGET_NR_clone 120 #define TARGET_NR_setdomainname 121 #define TARGET_NR_uname 122 diff --git a/linux-user/signal.c b/linux-user/signal.c index e4eea69..c750053 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -4454,7 +4454,12 @@ struct target_mcontext { target_ulong mc_gregs[48]; /* Includes fpscr. */ uint64_t mc_fregs[33]; +#if defined(TARGET_PPC64) + /* Pointer to the vector regs */ + target_ulong v_regs; +#else target_ulong mc_pad[2]; +#endif /* We need to handle Altivec and SPE at the same time, which no kernel needs to do. Fortunately, the kernel defines this bit to be Altivec-register-large all the time, rather than trying to @@ -4464,15 +4469,30 @@ struct target_mcontext { uint32_t spe[33]; /* Altivec vector registers. The packing of VSCR and VRSAVE varies depending on whether we're PPC64 or not: PPC64 splits - them apart; PPC32 stuffs them together. */ + them apart; PPC32 stuffs them together. + We also need to account for the VSX registers on PPC64 + */ #if defined(TARGET_PPC64) -#define QEMU_NVRREG 34 +#define QEMU_NVRREG (34 + 16) + /* On ppc64, this mcontext structure is naturally *unaligned*, + * or rather it is aligned on a 8 bytes boundary but not on + * a 16 bytes one. This pad fixes it up. This is also why the + * vector regs are referenced by the v_regs pointer above so + * any amount of padding can be added here + */ + target_ulong pad; #else + /* On ppc32, we are already aligned to 16 bytes */ #define QEMU_NVRREG 33 #endif - ppc_avr_t altivec[QEMU_NVRREG]; + /* We cannot use ppc_avr_t here as we do *not* want the implied + * 16-bytes alignment that would result from it. This would have + * the effect of making the whole struct target_mcontext aligned + * which breaks the layout of struct target_ucontext on ppc64. + */ + uint64_t altivec[QEMU_NVRREG][2]; #undef QEMU_NVRREG - } mc_vregs __attribute__((__aligned__(16))); + } mc_vregs; }; /* See arch/powerpc/include/asm/sigcontext.h. */ @@ -4626,6 +4646,16 @@ static target_ulong get_sigframe(struct target_sigaction *ka, return (oldsp - frame_size) & ~0xFUL; } +#if ((defined(TARGET_WORDS_BIGENDIAN) && defined(HOST_WORDS_BIGENDIAN)) || \ + (!defined(HOST_WORDS_BIGENDIAN) && !defined(TARGET_WORDS_BIGENDIAN))) +#define PPC_VEC_HI 0 +#define PPC_VEC_LO 1 +#else +#define PPC_VEC_HI 1 +#define PPC_VEC_LO 0 +#endif + + static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame) { target_ulong msr = env->msr; @@ -4652,18 +4682,33 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame) /* Save Altivec registers if necessary. */ if (env->insns_flags & PPC_ALTIVEC) { + uint32_t *vrsave; for (i = 0; i < ARRAY_SIZE(env->avr); i++) { ppc_avr_t *avr = &env->avr[i]; - ppc_avr_t *vreg = &frame->mc_vregs.altivec[i]; + ppc_avr_t *vreg = (ppc_avr_t *)&frame->mc_vregs.altivec[i]; - __put_user(avr->u64[0], &vreg->u64[0]); - __put_user(avr->u64[1], &vreg->u64[1]); + __put_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]); + __put_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]); } /* Set MSR_VR in the saved MSR value to indicate that frame->mc_vregs contains valid data. */ msr |= MSR_VR; - __put_user((uint32_t)env->spr[SPR_VRSAVE], - &frame->mc_vregs.altivec[32].u32[3]); +#if defined(TARGET_PPC64) + vrsave = (uint32_t *)&frame->mc_vregs.altivec[33]; + /* 64-bit needs to put a pointer to the vectors in the frame */ + __put_user(h2g(frame->mc_vregs.altivec), &frame->v_regs); +#else + vrsave = (uint32_t *)&frame->mc_vregs.altivec[32]; +#endif + __put_user((uint32_t)env->spr[SPR_VRSAVE], vrsave); + } + + /* Save VSX second halves */ + if (env->insns_flags2 & PPC2_VSX) { + uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34]; + for (i = 0; i < ARRAY_SIZE(env->vsr); i++) { + __put_user(env->vsr[i], &vsregs[i]); + } } /* Save floating point registers. */ @@ -4743,17 +4788,39 @@ static void restore_user_regs(CPUPPCState *env, /* Restore Altivec registers if necessary. */ if (env->insns_flags & PPC_ALTIVEC) { + ppc_avr_t *v_regs; + uint32_t *vrsave; +#if defined(TARGET_PPC64) + uint64_t v_addr; + /* 64-bit needs to recover the pointer to the vectors from the frame */ + __get_user(v_addr, &frame->v_regs); + v_regs = g2h(v_addr); +#else + v_regs = (ppc_avr_t *)frame->mc_vregs.altivec; +#endif for (i = 0; i < ARRAY_SIZE(env->avr); i++) { ppc_avr_t *avr = &env->avr[i]; - ppc_avr_t *vreg = &frame->mc_vregs.altivec[i]; + ppc_avr_t *vreg = &v_regs[i]; - __get_user(avr->u64[0], &vreg->u64[0]); - __get_user(avr->u64[1], &vreg->u64[1]); + __get_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]); + __get_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]); } /* Set MSR_VEC in the saved MSR value to indicate that frame->mc_vregs contains valid data. */ - __get_user(env->spr[SPR_VRSAVE], - (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])); +#if defined(TARGET_PPC64) + vrsave = (uint32_t *)&v_regs[33]; +#else + vrsave = (uint32_t *)&v_regs[32]; +#endif + __get_user(env->spr[SPR_VRSAVE], vrsave); + } + + /* Restore VSX second halves */ + if (env->insns_flags2 & PPC2_VSX) { + uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34]; + for (i = 0; i < ARRAY_SIZE(env->vsr); i++) { + __get_user(env->vsr[i], &vsregs[i]); + } } /* Restore floating point registers. */ @@ -4784,6 +4851,7 @@ static void restore_user_regs(CPUPPCState *env, } } +#if !defined(TARGET_PPC64) static void setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, CPUPPCState *env) { @@ -4791,9 +4859,6 @@ static void setup_frame(int sig, struct target_sigaction *ka, struct target_sigcontext *sc; target_ulong frame_addr, newsp; int err = 0; -#if defined(TARGET_PPC64) - struct image_info *image = ((TaskState *)thread_cpu->opaque)->info; -#endif frame_addr = get_sigframe(ka, env, sizeof(*frame)); trace_user_setup_frame(env, frame_addr); @@ -4803,11 +4868,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, __put_user(ka->_sa_handler, &sc->handler); __put_user(set->sig[0], &sc->oldmask); -#if TARGET_ABI_BITS == 64 - __put_user(set->sig[0] >> 32, &sc->_unused[3]); -#else __put_user(set->sig[1], &sc->_unused[3]); -#endif __put_user(h2g(&frame->mctx), &sc->regs); __put_user(sig, &sc->signal); @@ -4836,22 +4897,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, env->gpr[3] = sig; env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx); -#if defined(TARGET_PPC64) - if (get_ppc64_abi(image) < 2) { - /* ELFv1 PPC64 function pointers are pointers to OPD entries. */ - struct target_func_ptr *handler = - (struct target_func_ptr *)g2h(ka->_sa_handler); - env->nip = tswapl(handler->entry); - env->gpr[2] = tswapl(handler->toc); - } else { - /* ELFv2 PPC64 function pointers are entry points, but R12 - * must also be set */ - env->nip = tswapl((target_ulong) ka->_sa_handler); - env->gpr[12] = env->nip; - } -#else env->nip = (target_ulong) ka->_sa_handler; -#endif /* Signal handlers are entered in big-endian mode. */ env->msr &= ~(1ull << MSR_LE); @@ -4863,6 +4909,7 @@ sigsegv: unlock_user_struct(frame, frame_addr, 1); force_sigsegv(sig); } +#endif /* !defined(TARGET_PPC64) */ static void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, @@ -4960,6 +5007,7 @@ sigsegv: } +#if !defined(TARGET_PPC64) long do_sigreturn(CPUPPCState *env) { struct target_sigcontext *sc = NULL; @@ -4996,6 +5044,7 @@ sigsegv: force_sig(TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } +#endif /* !defined(TARGET_PPC64) */ /* See arch/powerpc/kernel/signal_32.c. */ static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig) @@ -5939,7 +5988,8 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig, #endif /* prepare the stack frame of the virtual CPU */ #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \ - || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX) + || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX) \ + || defined(TARGET_PPC64) /* These targets do not have traditional signals. */ setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env); #else @@ -1025,7 +1025,7 @@ int monitor_set_cpu(int cpu_index) CPUState *mon_get_cpu(void) { if (!cur_mon->mon_cpu) { - monitor_set_cpu(0); + monitor_set_cpu(first_cpu->cpu_index); } cpu_synchronize_state(cur_mon->mon_cpu); return cur_mon->mon_cpu; @@ -18,6 +18,7 @@ #include "qemu/cutils.h" #include "monitor/monitor.h" #include "sysemu/sysemu.h" +#include "qemu/uuid.h" #include "qmp-commands.h" #include "sysemu/char.h" #include "ui/qemu-spice.h" @@ -35,6 +36,7 @@ #include "qom/object_interfaces.h" #include "hw/mem/pc-dimm.h" #include "hw/acpi/acpi_dev_interface.h" +#include "qemu/uuid.h" NameInfo *qmp_query_name(Error **errp) { @@ -74,15 +76,8 @@ KvmInfo *qmp_query_kvm(Error **errp) UuidInfo *qmp_query_uuid(Error **errp) { UuidInfo *info = g_malloc0(sizeof(*info)); - char uuid[64]; - snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1], - qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5], - qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9], - qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], - qemu_uuid[14], qemu_uuid[15]); - - info->UUID = g_strdup(uuid); + info->UUID = qemu_uuid_unparse_strdup(&qemu_uuid); return info; } @@ -27,6 +27,10 @@ #include "qemu/config-file.h" #include "qemu/option.h" #include "qemu/error-report.h" +#include "qemu/cutils.h" +#ifdef TARGET_PPC64 +#include "hw/ppc/spapr_rtas.h" +#endif #define MAX_IRQ 256 @@ -325,12 +329,13 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) } else if (strcmp(words[0], "outb") == 0 || strcmp(words[0], "outw") == 0 || strcmp(words[0], "outl") == 0) { - uint16_t addr; - uint32_t value; + unsigned long addr; + unsigned long value; g_assert(words[1] && words[2]); - addr = strtoul(words[1], NULL, 0); - value = strtoul(words[2], NULL, 0); + g_assert(qemu_strtoul(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtoul(words[2], NULL, 0, &value) == 0); + g_assert(addr <= 0xffff); if (words[0][3] == 'b') { cpu_outb(addr, value); @@ -344,11 +349,12 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) } else if (strcmp(words[0], "inb") == 0 || strcmp(words[0], "inw") == 0 || strcmp(words[0], "inl") == 0) { - uint16_t addr; + unsigned long addr; uint32_t value = -1U; g_assert(words[1]); - addr = strtoul(words[1], NULL, 0); + g_assert(qemu_strtoul(words[1], NULL, 0, &addr) == 0); + g_assert(addr <= 0xffff); if (words[0][2] == 'b') { value = cpu_inb(addr); @@ -367,8 +373,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) uint64_t value; g_assert(words[1] && words[2]); - addr = strtoull(words[1], NULL, 0); - value = strtoull(words[2], NULL, 0); + g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtoull(words[2], NULL, 0, &value) == 0); if (words[0][5] == 'b') { uint8_t data = value; @@ -396,7 +402,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) uint64_t value = UINT64_C(-1); g_assert(words[1]); - addr = strtoull(words[1], NULL, 0); + g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); if (words[0][4] == 'b') { uint8_t data; @@ -422,8 +428,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) char *enc; g_assert(words[1] && words[2]); - addr = strtoull(words[1], NULL, 0); - len = strtoull(words[2], NULL, 0); + g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0); data = g_malloc(len); cpu_physical_memory_read(addr, data, len); @@ -444,8 +450,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) gchar *b64_data; g_assert(words[1] && words[2]); - addr = strtoull(words[1], NULL, 0); - len = strtoull(words[2], NULL, 0); + g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0); data = g_malloc(len); cpu_physical_memory_read(addr, data, len); @@ -461,8 +467,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) size_t data_len; g_assert(words[1] && words[2] && words[3]); - addr = strtoull(words[1], NULL, 0); - len = strtoull(words[2], NULL, 0); + g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0); data_len = strlen(words[3]); if (data_len < 3) { @@ -487,12 +493,12 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) } else if (strcmp(words[0], "memset") == 0) { uint64_t addr, len; uint8_t *data; - uint8_t pattern; + unsigned long pattern; g_assert(words[1] && words[2] && words[3]); - addr = strtoull(words[1], NULL, 0); - len = strtoull(words[2], NULL, 0); - pattern = strtoull(words[3], NULL, 0); + g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0); + g_assert(qemu_strtoul(words[3], NULL, 0, &pattern) == 0); if (len) { data = g_malloc(len); @@ -510,8 +516,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) gsize out_len; g_assert(words[1] && words[2] && words[3]); - addr = strtoull(words[1], NULL, 0); - len = strtoull(words[2], NULL, 0); + g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0); + g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0); data_len = strlen(words[3]); if (data_len < 3) { @@ -531,11 +537,25 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) qtest_send_prefix(chr); qtest_send(chr, "OK\n"); +#ifdef TARGET_PPC64 + } else if (strcmp(words[0], "rtas") == 0) { + uint64_t res, args, ret; + unsigned long nargs, nret; + + g_assert(qemu_strtoul(words[2], NULL, 0, &nargs) == 0); + g_assert(qemu_strtoull(words[3], NULL, 0, &args) == 0); + g_assert(qemu_strtoul(words[4], NULL, 0, &nret) == 0); + g_assert(qemu_strtoull(words[5], NULL, 0, &ret) == 0); + res = qtest_rtas_call(words[1], nargs, args, nret, ret); + + qtest_send_prefix(chr); + qtest_sendf(chr, "OK %"PRIu64"\n", res); +#endif } else if (qtest_enabled() && strcmp(words[0], "clock_step") == 0) { int64_t ns; if (words[1]) { - ns = strtoll(words[1], NULL, 0); + g_assert(qemu_strtoll(words[1], NULL, 0, &ns) == 0); } else { ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); } @@ -547,7 +567,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) int64_t ns; g_assert(words[1]); - ns = strtoll(words[1], NULL, 0); + g_assert(qemu_strtoll(words[1], NULL, 0, &ns) == 0); qtest_clock_warp(ns); qtest_send_prefix(chr); qtest_sendf(chr, "OK %"PRIi64"\n", diff --git a/scripts/show-fixed-bugs.sh b/scripts/show-fixed-bugs.sh new file mode 100755 index 0000000..36f3068 --- /dev/null +++ b/scripts/show-fixed-bugs.sh @@ -0,0 +1,91 @@ +#!/bin/sh + +# This script checks the git log for URLs to the QEMU launchpad bugtracker +# and optionally checks whether the corresponding bugs are not closed yet. + +show_help () { + echo "Usage:" + echo " -s <commit> : Start searching at this commit" + echo " -e <commit> : End searching at this commit" + echo " -c : Check if bugs are still open" + echo " -b : Open bugs in browser" +} + +while getopts "s:e:cbh" opt; do + case "$opt" in + s) start="$OPTARG" ;; + e) end="$OPTARG" ;; + c) check_if_open=1 ;; + b) show_in_browser=1 ;; + h) show_help ; exit 0 ;; + *) echo "Use -h for help." ; exit 1 ;; + esac +done + +if [ "x$start" = "x" ]; then + start=`git tag -l 'v[0-9]*\.[0-9]*\.0' | tail -n 2 | head -n 1` +fi +if [ "x$end" = "x" ]; then + end=`git tag -l 'v[0-9]*\.[0-9]*\.0' | tail -n 1` +fi + +if [ "x$start" = "x" ] || [ "x$end" = "x" ]; then + echo "Could not determine start or end revision ... Please note that this" + echo "script must be run from a checked out git repository of QEMU." + exit 1 +fi + +echo "Searching git log for bugs in the range $start..$end" + +urlstr='https://bugs.launchpad.net/\(bugs\|qemu/+bug\)/' +bug_urls=`git log $start..$end \ + | sed -n '\,'"$urlstr"', s,\(.*\)\('"$urlstr"'\)\([0-9]*\).*,\2\4,p' \ + | sort -u` + +echo Found bug URLs: +for i in $bug_urls ; do echo " $i" ; done + +if [ "x$check_if_open" = "x1" ]; then + echo + echo "Checking which ones are still open..." + for i in $bug_urls ; do + if ! curl -s -L "$i" | grep "value status" | grep -q "Fix Released" ; then + echo " $i" + final_bug_urls="$final_bug_urls $i" + fi + done +else + final_bug_urls=$bug_urls +fi + +if [ "x$final_bug_urls" = "x" ]; then + echo "No open bugs found." +elif [ "x$show_in_browser" = "x1" ]; then + # Try to determine which browser we should use + if [ "x$BROWSER" != "x" ]; then + bugbrowser="$BROWSER" + elif command -v xdg-open >/dev/null 2>&1; then + bugbrowser=xdg-open + elif command -v gnome-open >/dev/null 2>&1; then + bugbrowser=gnome-open + elif [ "`uname`" = "Darwin" ]; then + bugbrowser=open + elif command -v sensible-browser >/dev/null 2>&1; then + bugbrowser=sensible-browser + else + echo "Please set the BROWSER variable to the browser of your choice." + exit 1 + fi + # Now show the bugs in the browser + first=1 + for i in $final_bug_urls; do + "$bugbrowser" "$i" + if [ $first = 1 ]; then + # if it is the first entry, give the browser some time to start + # (to avoid messages like "Firefox is already running, but is + # not responding...") + sleep 4 + first=0 + fi + done +fi diff --git a/stubs/uuid.c b/stubs/uuid.c index 92ad717..a880de8 100644 --- a/stubs/uuid.c +++ b/stubs/uuid.c @@ -1,6 +1,6 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#include "sysemu/sysemu.h" +#include "qemu/uuid.h" #include "qmp-commands.h" UuidInfo *qmp_query_uuid(Error **errp) diff --git a/stubs/vmstate.c b/stubs/vmstate.c index 6590627..94b831e 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 ce8b8f4..1b9540e 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/target-i386/kvm.c b/target-i386/kvm.c index f1ad805..a0e42b2 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -1532,6 +1532,22 @@ static void kvm_msr_entry_add(X86CPU *cpu, uint32_t index, uint64_t value) msrs->nmsrs++; } +static int kvm_put_one_msr(X86CPU *cpu, int index, uint64_t value) +{ + kvm_msr_buf_reset(cpu); + kvm_msr_entry_add(cpu, index, value); + + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MSRS, cpu->kvm_msr_buf); +} + +void kvm_put_apicbase(X86CPU *cpu, uint64_t value) +{ + int ret; + + ret = kvm_put_one_msr(cpu, MSR_IA32_APICBASE, value); + assert(ret == 1); +} + static int kvm_put_tscdeadline_msr(X86CPU *cpu) { CPUX86State *env = &cpu->env; @@ -1541,10 +1557,7 @@ static int kvm_put_tscdeadline_msr(X86CPU *cpu) return 0; } - kvm_msr_buf_reset(cpu); - kvm_msr_entry_add(cpu, MSR_IA32_TSCDEADLINE, env->tsc_deadline); - - ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MSRS, cpu->kvm_msr_buf); + ret = kvm_put_one_msr(cpu, MSR_IA32_TSCDEADLINE, env->tsc_deadline); if (ret < 0) { return ret; } @@ -1567,11 +1580,8 @@ static int kvm_put_msr_feature_control(X86CPU *cpu) return 0; } - kvm_msr_buf_reset(cpu); - kvm_msr_entry_add(cpu, MSR_IA32_FEATURE_CONTROL, - cpu->env.msr_ia32_feature_control); - - ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MSRS, cpu->kvm_msr_buf); + ret = kvm_put_one_msr(cpu, MSR_IA32_FEATURE_CONTROL, + cpu->env.msr_ia32_feature_control); if (ret < 0) { return ret; } @@ -2442,6 +2452,7 @@ static int kvm_put_vcpu_events(X86CPU *cpu, int level) events.nmi.pad = 0; events.sipi_vector = env->sipi_vector; + events.flags = 0; if (has_msr_smbase) { events.smi.smm = !!(env->hflags & HF_SMM_MASK); @@ -2461,7 +2472,6 @@ static int kvm_put_vcpu_events(X86CPU *cpu, int level) events.flags |= KVM_VCPUEVENT_VALID_SMM; } - events.flags = 0; if (level >= KVM_PUT_RESET_STATE) { events.flags |= KVM_VCPUEVENT_VALID_NMI_PENDING | KVM_VCPUEVENT_VALID_SIPI_VECTOR; diff --git a/target-i386/kvm_i386.h b/target-i386/kvm_i386.h index 42b00af..36407e0 100644 --- a/target-i386/kvm_i386.h +++ b/target-i386/kvm_i386.h @@ -41,4 +41,6 @@ int kvm_device_msix_set_vector(KVMState *s, uint32_t dev_id, uint32_t vector, int kvm_device_msix_assign(KVMState *s, uint32_t dev_id); int kvm_device_msix_deassign(KVMState *s, uint32_t dev_id); +void kvm_put_apicbase(X86CPU *cpu, uint64_t value); + #endif diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 9617481..1c90adb 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1009,6 +1009,8 @@ struct CPUPPCState { bool tlb_dirty; /* Set to non-zero when modifying TLB */ bool kvm_sw_tlb; /* non-zero if KVM SW TLB API is active */ uint32_t tlb_need_flush; /* Delayed flush needed */ +#define TLB_NEED_LOCAL_FLUSH 0x1 +#define TLB_NEED_GLOBAL_FLUSH 0x2 #endif /* Other registers */ diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 04ed4da..921c39d 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -711,7 +711,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) /* Any interrupt is context synchronizing, check if TCG TLB * needs a delayed flush on ppc64 */ - check_tlb_flush(env); + check_tlb_flush(env, false); } void ppc_cpu_do_interrupt(CPUState *cs) @@ -973,7 +973,7 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) cs->interrupt_request |= CPU_INTERRUPT_EXITTB; /* Context synchronizing: check if TCG TLB needs flush */ - check_tlb_flush(env); + check_tlb_flush(env, false); } void helper_rfi(CPUPPCState *env) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index dcf3f95..a1c2962 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -18,7 +18,8 @@ DEF_HELPER_1(rfid, void, env) DEF_HELPER_1(hrfid, void, env) DEF_HELPER_2(store_lpcr, void, env, tl) #endif -DEF_HELPER_1(check_tlb_flush, void, env) +DEF_HELPER_1(check_tlb_flush_local, void, env) +DEF_HELPER_1(check_tlb_flush_global, void, env) #endif DEF_HELPER_3(lmw, void, env, tl, i32) @@ -50,6 +51,8 @@ DEF_HELPER_FLAGS_1(cnttzd, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(popcntd, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_2(bpermd, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_3(srad, tl, env, tl, tl) +DEF_HELPER_0(darn32, tl) +DEF_HELPER_0(darn64, tl) #endif DEF_HELPER_FLAGS_1(cntlsw32, TCG_CALL_NO_RWG_SE, i32, i32) @@ -250,6 +253,14 @@ DEF_HELPER_2(vspltisw, void, avr, i32) DEF_HELPER_3(vspltb, void, avr, avr, i32) DEF_HELPER_3(vsplth, void, avr, avr, i32) DEF_HELPER_3(vspltw, void, avr, avr, i32) +DEF_HELPER_3(vextractub, void, avr, avr, i32) +DEF_HELPER_3(vextractuh, void, avr, avr, i32) +DEF_HELPER_3(vextractuw, void, avr, avr, i32) +DEF_HELPER_3(vextractd, void, avr, avr, i32) +DEF_HELPER_3(vinsertb, void, avr, avr, i32) +DEF_HELPER_3(vinserth, void, avr, avr, i32) +DEF_HELPER_3(vinsertw, void, avr, avr, i32) +DEF_HELPER_3(vinsertd, void, avr, avr, i32) DEF_HELPER_2(vupkhpx, void, avr, avr) DEF_HELPER_2(vupklpx, void, avr, avr) DEF_HELPER_2(vupkhsb, void, avr, avr) @@ -262,6 +273,7 @@ DEF_HELPER_5(vmsumubm, void, env, avr, avr, avr, avr) DEF_HELPER_5(vmsummbm, void, env, avr, avr, avr, avr) DEF_HELPER_5(vsel, void, env, avr, avr, avr, avr) DEF_HELPER_5(vperm, void, env, avr, avr, avr, avr) +DEF_HELPER_5(vpermr, void, env, avr, avr, avr, avr) DEF_HELPER_4(vpkshss, void, env, avr, avr, avr) DEF_HELPER_4(vpkshus, void, env, avr, avr, avr) DEF_HELPER_4(vpkswss, void, env, avr, avr, avr) @@ -317,10 +329,15 @@ DEF_HELPER_2(vclzb, void, avr, avr) DEF_HELPER_2(vclzh, void, avr, avr) DEF_HELPER_2(vclzw, void, avr, avr) DEF_HELPER_2(vclzd, void, avr, avr) +DEF_HELPER_2(vctzb, void, avr, avr) +DEF_HELPER_2(vctzh, void, avr, avr) +DEF_HELPER_2(vctzw, void, avr, avr) +DEF_HELPER_2(vctzd, void, avr, avr) DEF_HELPER_2(vpopcntb, void, avr, avr) DEF_HELPER_2(vpopcnth, void, avr, avr) DEF_HELPER_2(vpopcntw, void, avr, avr) DEF_HELPER_2(vpopcntd, void, avr, avr) +DEF_HELPER_3(vbpermd, void, avr, avr, avr) DEF_HELPER_3(vbpermq, void, avr, avr, avr) DEF_HELPER_2(vgbbd, void, avr, avr) DEF_HELPER_3(vpmsumb, void, avr, avr, avr) diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h index 3d279f1..bb9ce60 100644 --- a/target-ppc/helper_regs.h +++ b/target-ppc/helper_regs.h @@ -154,16 +154,33 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, } #if !defined(CONFIG_USER_ONLY) -static inline void check_tlb_flush(CPUPPCState *env) +static inline void check_tlb_flush(CPUPPCState *env, bool global) { CPUState *cs = CPU(ppc_env_get_cpu(env)); - if (env->tlb_need_flush) { - env->tlb_need_flush = 0; + if (env->tlb_need_flush & TLB_NEED_LOCAL_FLUSH) { tlb_flush(cs, 1); + env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; + } + + /* Propagate TLB invalidations to other CPUs when the guest uses broadcast + * TLB invalidation instructions. + */ + if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) { + CPUState *other_cs; + CPU_FOREACH(other_cs) { + if (other_cs != cs) { + PowerPCCPU *cpu = POWERPC_CPU(other_cs); + CPUPPCState *other_env = &cpu->env; + + other_env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; + tlb_flush(other_cs, 1); + } + } + env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH; } } #else -static inline void check_tlb_flush(CPUPPCState *env) { } +static inline void check_tlb_flush(CPUPPCState *env, bool global) { } #endif #endif /* HELPER_REGS_H */ diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 552b2e0..51a9ac5 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -182,6 +182,22 @@ target_ulong helper_cnttzd(target_ulong t) { return ctz64(t); } + +/* Return invalid random number. + * + * FIXME: Add rng backend or other mechanism to get cryptographically suitable + * random number + */ +target_ulong helper_darn32(void) +{ + return -1; +} + +target_ulong helper_darn64(void) +{ + return -1; +} + #endif #if defined(TARGET_PPC64) @@ -1126,14 +1142,57 @@ void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, *r = result; } +void helper_vpermr(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, + ppc_avr_t *c) +{ + ppc_avr_t result; + int i; + + VECTOR_FOR_INORDER_I(i, u8) { + int s = c->u8[i] & 0x1f; +#if defined(HOST_WORDS_BIGENDIAN) + int index = 15 - (s & 0xf); +#else + int index = s & 0xf; +#endif + + if (s & 0x10) { + result.u8[i] = a->u8[index]; + } else { + result.u8[i] = b->u8[index]; + } + } + *r = result; +} + #if defined(HOST_WORDS_BIGENDIAN) #define VBPERMQ_INDEX(avr, i) ((avr)->u8[(i)]) +#define VBPERMD_INDEX(i) (i) #define VBPERMQ_DW(index) (((index) & 0x40) != 0) +#define EXTRACT_BIT(avr, i, index) (extract64((avr)->u64[i], index, 1)) #else #define VBPERMQ_INDEX(avr, i) ((avr)->u8[15-(i)]) +#define VBPERMD_INDEX(i) (1 - i) #define VBPERMQ_DW(index) (((index) & 0x40) == 0) +#define EXTRACT_BIT(avr, i, index) \ + (extract64((avr)->u64[1 - i], 63 - index, 1)) #endif +void helper_vbpermd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) +{ + int i, j; + ppc_avr_t result = { .u64 = { 0, 0 } }; + VECTOR_FOR_INORDER_I(i, u64) { + for (j = 0; j < 8; j++) { + int index = VBPERMQ_INDEX(b, (i * 8) + j); + if (index < 64 && EXTRACT_BIT(a, i, index)) { + result.u64[VBPERMD_INDEX(i)] |= (0x80 >> j); + } + } + } + *r = result; +} + void helper_vbpermq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int i; @@ -1792,6 +1851,51 @@ VSPLT(w, u32) #undef VSPLT #undef SPLAT_ELEMENT #undef _SPLAT_MASKED +#if defined(HOST_WORDS_BIGENDIAN) +#define VINSERT(suffix, element) \ + void helper_vinsert##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t index) \ + { \ + memmove(&r->u8[index], &b->u8[8 - sizeof(r->element)], \ + sizeof(r->element[0])); \ + } +#else +#define VINSERT(suffix, element) \ + void helper_vinsert##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t index) \ + { \ + uint32_t d = (16 - index) - sizeof(r->element[0]); \ + memmove(&r->u8[d], &b->u8[8], sizeof(r->element[0])); \ + } +#endif +VINSERT(b, u8) +VINSERT(h, u16) +VINSERT(w, u32) +VINSERT(d, u64) +#undef VINSERT +#if defined(HOST_WORDS_BIGENDIAN) +#define VEXTRACT(suffix, element) \ + void helper_vextract##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t index) \ + { \ + uint32_t es = sizeof(r->element[0]); \ + memmove(&r->u8[8 - es], &b->u8[index], es); \ + memset(&r->u8[8], 0, 8); \ + memset(&r->u8[0], 0, 8 - es); \ + } +#else +#define VEXTRACT(suffix, element) \ + void helper_vextract##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t index) \ + { \ + uint32_t es = sizeof(r->element[0]); \ + uint32_t s = (16 - index) - es; \ + memmove(&r->u8[8], &b->u8[s], es); \ + memset(&r->u8[0], 0, 8); \ + memset(&r->u8[8 + es], 0, 8 - es); \ + } +#endif +VEXTRACT(ub, u8) +VEXTRACT(uh, u16) +VEXTRACT(uw, u32) +VEXTRACT(d, u64) +#undef VEXTRACT #define VSPLTI(suffix, element, splat_type) \ void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \ @@ -2038,6 +2142,21 @@ VGENERIC_DO(clzd, u64) #undef clzw #undef clzd +#define ctzb(v) ((v) ? ctz32(v) : 8) +#define ctzh(v) ((v) ? ctz32(v) : 16) +#define ctzw(v) ctz32((v)) +#define ctzd(v) ctz64((v)) + +VGENERIC_DO(ctzb, u8) +VGENERIC_DO(ctzh, u16) +VGENERIC_DO(ctzw, u32) +VGENERIC_DO(ctzd, u64) + +#undef ctzb +#undef ctzh +#undef ctzw +#undef ctzd + #define popcntb(v) ctpop8(v) #define popcnth(v) ctpop16(v) #define popcntw(v) ctpop32(v) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index dcb68b9..a18d4d5 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -36,6 +36,7 @@ #include "hw/sysbus.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" +#include "hw/ppc/spapr_cpu_core.h" #include "hw/ppc/ppc.h" #include "sysemu/watchdog.h" #include "trace.h" @@ -427,6 +428,7 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu) CPUPPCState *env = &cpu->env; long rampagesize; int iq, ik, jq, jk; + bool has_64k_pages = false; /* We only handle page sizes for 64-bit server guests for now */ if (!(env->mmu_model & POWERPC_MMU_64)) { @@ -470,6 +472,9 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu) ksps->enc[jk].page_shift)) { continue; } + if (ksps->enc[jk].page_shift == 16) { + has_64k_pages = true; + } qsps->enc[jq].page_shift = ksps->enc[jk].page_shift; qsps->enc[jq].pte_enc = ksps->enc[jk].pte_enc; if (++jq >= PPC_PAGE_SIZES_MAX_SZ) { @@ -484,6 +489,9 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu) if (!(smmu_info.flags & KVM_PPC_1T_SEGMENTS)) { env->mmu_model &= ~POWERPC_MMU_1TSEG; } + if (!has_64k_pages) { + env->mmu_model &= ~POWERPC_MMU_64K; + } } #else /* defined (TARGET_PPC64) */ @@ -2055,6 +2063,12 @@ void kvmppc_enable_set_mode_hcall(void) kvmppc_enable_hcall(kvm_state, H_SET_MODE); } +void kvmppc_enable_clear_ref_mod_hcalls(void) +{ + kvmppc_enable_hcall(kvm_state, H_CLEAR_REF); + kvmppc_enable_hcall(kvm_state, H_CLEAR_MOD); +} + void kvmppc_set_papr(PowerPCCPU *cpu) { CPUState *cs = CPU(cpu); @@ -2364,19 +2378,6 @@ PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void) return pvr_pcc; } -#if defined(TARGET_PPC64) -static void spapr_cpu_core_host_initfn(Object *obj) -{ - sPAPRCPUCore *core = SPAPR_CPU_CORE(obj); - char *name = g_strdup_printf("%s-" TYPE_POWERPC_CPU, "host"); - ObjectClass *oc = object_class_by_name(name); - - g_assert(oc); - g_free((void *)name); - core->cpu_class = oc; -} -#endif - static int kvm_ppc_register_host_cpu_type(void) { TypeInfo type_info = { @@ -2404,14 +2405,16 @@ static int kvm_ppc_register_host_cpu_type(void) #if defined(TARGET_PPC64) type_info.name = g_strdup_printf("%s-"TYPE_SPAPR_CPU_CORE, "host"); type_info.parent = TYPE_SPAPR_CPU_CORE, - type_info.instance_size = sizeof(sPAPRCPUCore), - type_info.instance_init = spapr_cpu_core_host_initfn, - type_info.class_init = NULL; + type_info.instance_size = sizeof(sPAPRCPUCore); + type_info.instance_init = NULL; + type_info.class_init = spapr_cpu_core_class_init; + type_info.class_data = (void *) "host"; type_register(&type_info); g_free((void *)type_info.name); /* Register generic spapr CPU family class for current host CPU type */ type_info.name = g_strdup_printf("%s-"TYPE_SPAPR_CPU_CORE, dc->desc); + type_info.class_data = (void *) dc->desc; type_register(&type_info); g_free((void *)type_info.name); #endif diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 5461d10..a778184 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -24,6 +24,7 @@ int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level); void kvmppc_enable_logical_ci_hcalls(void); void kvmppc_enable_set_mode_hcall(void); +void kvmppc_enable_clear_ref_mod_hcalls(void); void kvmppc_set_papr(PowerPCCPU *cpu); int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version); void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy); @@ -113,6 +114,10 @@ static inline void kvmppc_enable_set_mode_hcall(void) { } +static inline void kvmppc_enable_clear_ref_mod_hcalls(void) +{ +} + static inline void kvmppc_set_papr(PowerPCCPU *cpu) { } diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c index 8118143..fdb7a78 100644 --- a/target-ppc/mmu-hash64.c +++ b/target-ppc/mmu-hash64.c @@ -110,7 +110,7 @@ void helper_slbia(CPUPPCState *env) * and we still don't have a tlb_flush_mask(env, n, mask) * in QEMU, we just invalidate all TLBs */ - env->tlb_need_flush = 1; + env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; } } } @@ -132,7 +132,7 @@ void helper_slbie(CPUPPCState *env, target_ulong addr) * and we still don't have a tlb_flush_mask(env, n, mask) * in QEMU, we just invalidate all TLBs */ - env->tlb_need_flush = 1; + env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; } } @@ -912,7 +912,7 @@ void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, * invalidate, and we still don't have a tlb_flush_mask(env, n, * mask) in QEMU, we just invalidate all TLBs */ - tlb_flush(CPU(cpu), 1); + cpu->env.tlb_need_flush = TLB_NEED_GLOBAL_FLUSH | TLB_NEED_LOCAL_FLUSH; } void ppc_hash64_update_rmls(CPUPPCState *env) diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 696bb03..d09fc0a 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -1965,7 +1965,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) * we just mark the TLB to be flushed later (context synchronizing * event or sync instruction on 32-bit). */ - env->tlb_need_flush = 1; + env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; break; #if defined(TARGET_PPC64) case POWERPC_MMU_64B: @@ -1979,7 +1979,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU, * we just invalidate all TLBs */ - env->tlb_need_flush = 1; + env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; break; #endif /* defined(TARGET_PPC64) */ default: @@ -2065,7 +2065,7 @@ void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value) } } #else - env->tlb_need_flush = 1; + env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; #endif } } @@ -2757,7 +2757,7 @@ static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn, void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address) { - PowerPCCPU *cpu = ppc_env_get_cpu(env); + CPUState *cs; if (address & 0x4) { /* flush all entries */ @@ -2774,11 +2774,15 @@ void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address) if (address & 0x8) { /* flush TLB1 entries */ booke206_invalidate_ea_tlb(env, 1, address); - tlb_flush(CPU(cpu), 1); + CPU_FOREACH(cs) { + tlb_flush(cs, 1); + } } else { /* flush TLB0 entries */ booke206_invalidate_ea_tlb(env, 0, address); - tlb_flush_page(CPU(cpu), address & MAS2_EPN_MASK); + CPU_FOREACH(cs) { + tlb_flush_page(cs, address & MAS2_EPN_MASK); + } } } @@ -2867,9 +2871,14 @@ void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type) } -void helper_check_tlb_flush(CPUPPCState *env) +void helper_check_tlb_flush_local(CPUPPCState *env) +{ + check_tlb_flush(env, false); +} + +void helper_check_tlb_flush_global(CPUPPCState *env) { - check_tlb_flush(env); + check_tlb_flush(env, true); } /*****************************************************************************/ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 618334a..8eefd82 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -498,6 +498,8 @@ EXTRACT_HELPER(UIMM, 0, 16); EXTRACT_HELPER(SIMM5, 16, 5); /* 5 bits signed immediate value */ EXTRACT_HELPER(UIMM5, 16, 5); +/* 4 bits unsigned immediate value */ +EXTRACT_HELPER(UIMM4, 16, 4); /* Bit count */ EXTRACT_HELPER(NB, 11, 5); /* Shift count */ @@ -526,6 +528,10 @@ EXTRACT_HELPER(FPW, 16, 1); /* addpcis */ EXTRACT_HELPER_DXFORM(DX, 10, 6, 6, 5, 16, 1, 1, 0, 0) +#if defined(TARGET_PPC64) +/* darn */ +EXTRACT_HELPER(L, 16, 2); +#endif /*** Jump target decoding ***/ /* Immediate address */ @@ -589,6 +595,8 @@ EXTRACT_HELPER(DM, 8, 2); EXTRACT_HELPER(UIM, 16, 2); EXTRACT_HELPER(SHW, 8, 2); EXTRACT_HELPER(SP, 19, 2); +EXTRACT_HELPER(IMM8, 11, 8); + /*****************************************************************************/ /* PowerPC instructions table */ @@ -1891,6 +1899,21 @@ static void gen_cnttzd(DisasContext *ctx) gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } } + +/* darn */ +static void gen_darn(DisasContext *ctx) +{ + int l = L(ctx->opcode); + + if (l == 0) { + gen_helper_darn32(cpu_gpr[rD(ctx->opcode)]); + } else if (l <= 2) { + /* Return 64-bit random for both CRN and RRN */ + gen_helper_darn64(cpu_gpr[rD(ctx->opcode)]); + } else { + tcg_gen_movi_i64(cpu_gpr[rD(ctx->opcode)], -1); + } +} #endif /*** Integer rotate ***/ @@ -2460,87 +2483,75 @@ static inline void gen_align_no_le(DisasContext *ctx) } /*** Integer load ***/ -static inline void gen_qemu_ld8u(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - tcg_gen_qemu_ld8u(arg1, arg2, ctx->mem_idx); -} +#define DEF_MEMOP(op) ((op) | ctx->default_tcg_memop_mask) +#define BSWAP_MEMOP(op) ((op) | (ctx->default_tcg_memop_mask ^ MO_BSWAP)) -static inline void gen_qemu_ld16u(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UW | ctx->default_tcg_memop_mask; - tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); +#define GEN_QEMU_LOAD_TL(ldop, op) \ +static void glue(gen_qemu_, ldop)(DisasContext *ctx, \ + TCGv val, \ + TCGv addr) \ +{ \ + tcg_gen_qemu_ld_tl(val, addr, ctx->mem_idx, op); \ } -static inline void gen_qemu_ld16s(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_SW | ctx->default_tcg_memop_mask; - tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); -} +GEN_QEMU_LOAD_TL(ld8u, DEF_MEMOP(MO_UB)) +GEN_QEMU_LOAD_TL(ld16u, DEF_MEMOP(MO_UW)) +GEN_QEMU_LOAD_TL(ld16s, DEF_MEMOP(MO_SW)) +GEN_QEMU_LOAD_TL(ld32u, DEF_MEMOP(MO_UL)) +GEN_QEMU_LOAD_TL(ld32s, DEF_MEMOP(MO_SL)) -static inline void gen_qemu_ld32u(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UL | ctx->default_tcg_memop_mask; - tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); -} +GEN_QEMU_LOAD_TL(ld16ur, BSWAP_MEMOP(MO_UW)) +GEN_QEMU_LOAD_TL(ld32ur, BSWAP_MEMOP(MO_UL)) -static void gen_qemu_ld32u_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr) -{ - TCGv tmp = tcg_temp_new(); - gen_qemu_ld32u(ctx, tmp, addr); - tcg_gen_extu_tl_i64(val, tmp); - tcg_temp_free(tmp); +#define GEN_QEMU_LOAD_64(ldop, op) \ +static void glue(gen_qemu_, glue(ldop, _i64))(DisasContext *ctx, \ + TCGv_i64 val, \ + TCGv addr) \ +{ \ + tcg_gen_qemu_ld_i64(val, addr, ctx->mem_idx, op); \ } -static inline void gen_qemu_ld32s(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_SL | ctx->default_tcg_memop_mask; - tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); -} +GEN_QEMU_LOAD_64(ld8u, DEF_MEMOP(MO_UB)) +GEN_QEMU_LOAD_64(ld16u, DEF_MEMOP(MO_UW)) +GEN_QEMU_LOAD_64(ld32u, DEF_MEMOP(MO_UL)) +GEN_QEMU_LOAD_64(ld32s, DEF_MEMOP(MO_SL)) +GEN_QEMU_LOAD_64(ld64, DEF_MEMOP(MO_Q)) -static void gen_qemu_ld32s_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr) -{ - TCGv tmp = tcg_temp_new(); - gen_qemu_ld32s(ctx, tmp, addr); - tcg_gen_ext_tl_i64(val, tmp); - tcg_temp_free(tmp); -} +#if defined(TARGET_PPC64) +GEN_QEMU_LOAD_64(ld64ur, BSWAP_MEMOP(MO_Q)) +#endif -static inline void gen_qemu_ld64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) -{ - TCGMemOp op = MO_Q | ctx->default_tcg_memop_mask; - tcg_gen_qemu_ld_i64(arg1, arg2, ctx->mem_idx, op); +#define GEN_QEMU_STORE_TL(stop, op) \ +static void glue(gen_qemu_, stop)(DisasContext *ctx, \ + TCGv val, \ + TCGv addr) \ +{ \ + tcg_gen_qemu_st_tl(val, addr, ctx->mem_idx, op); \ } -static inline void gen_qemu_st8(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - tcg_gen_qemu_st8(arg1, arg2, ctx->mem_idx); -} +GEN_QEMU_STORE_TL(st8, DEF_MEMOP(MO_UB)) +GEN_QEMU_STORE_TL(st16, DEF_MEMOP(MO_UW)) +GEN_QEMU_STORE_TL(st32, DEF_MEMOP(MO_UL)) -static inline void gen_qemu_st16(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UW | ctx->default_tcg_memop_mask; - tcg_gen_qemu_st_tl(arg1, arg2, ctx->mem_idx, op); -} +GEN_QEMU_STORE_TL(st16r, BSWAP_MEMOP(MO_UW)) +GEN_QEMU_STORE_TL(st32r, BSWAP_MEMOP(MO_UL)) -static inline void gen_qemu_st32(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UL | ctx->default_tcg_memop_mask; - tcg_gen_qemu_st_tl(arg1, arg2, ctx->mem_idx, op); +#define GEN_QEMU_STORE_64(stop, op) \ +static void glue(gen_qemu_, glue(stop, _i64))(DisasContext *ctx, \ + TCGv_i64 val, \ + TCGv addr) \ +{ \ + tcg_gen_qemu_st_i64(val, addr, ctx->mem_idx, op); \ } -static void gen_qemu_st32_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr) -{ - TCGv tmp = tcg_temp_new(); - tcg_gen_trunc_i64_tl(tmp, val); - gen_qemu_st32(ctx, tmp, addr); - tcg_temp_free(tmp); -} +GEN_QEMU_STORE_64(st8, DEF_MEMOP(MO_UB)) +GEN_QEMU_STORE_64(st16, DEF_MEMOP(MO_UW)) +GEN_QEMU_STORE_64(st32, DEF_MEMOP(MO_UL)) +GEN_QEMU_STORE_64(st64, DEF_MEMOP(MO_Q)) -static inline void gen_qemu_st64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) -{ - TCGMemOp op = MO_Q | ctx->default_tcg_memop_mask; - tcg_gen_qemu_st_i64(arg1, arg2, ctx->mem_idx, op); -} +#if defined(TARGET_PPC64) +GEN_QEMU_STORE_64(st64r, BSWAP_MEMOP(MO_Q)) +#endif #define GEN_LD(name, ldop, opc, type) \ static void glue(gen_, name)(DisasContext *ctx) \ @@ -2628,12 +2639,12 @@ GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B); /* lwax */ GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B); /* ldux */ -GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B); +GEN_LDUX(ld, ld64_i64, 0x15, 0x01, PPC_64B); /* ldx */ -GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B); +GEN_LDX(ld, ld64_i64, 0x15, 0x00, PPC_64B); /* CI load/store variants */ -GEN_LDX_HVRM(ldcix, ld64, 0x15, 0x1b, PPC_CILDST) +GEN_LDX_HVRM(ldcix, ld64_i64, 0x15, 0x1b, PPC_CILDST) GEN_LDX_HVRM(lwzcix, ld32u, 0x15, 0x15, PPC_CILDST) GEN_LDX_HVRM(lhzcix, ld16u, 0x15, 0x19, PPC_CILDST) GEN_LDX_HVRM(lbzcix, ld8u, 0x15, 0x1a, PPC_CILDST) @@ -2656,7 +2667,7 @@ static void gen_ld(DisasContext *ctx) gen_qemu_ld32s(ctx, cpu_gpr[rD(ctx->opcode)], EA); } else { /* ld - ldu */ - gen_qemu_ld64(ctx, cpu_gpr[rD(ctx->opcode)], EA); + gen_qemu_ld64_i64(ctx, cpu_gpr[rD(ctx->opcode)], EA); } if (Rc(ctx->opcode)) tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); @@ -2693,16 +2704,16 @@ static void gen_lq(DisasContext *ctx) EA = tcg_temp_new(); gen_addr_imm_index(ctx, EA, 0x0F); - /* We only need to swap high and low halves. gen_qemu_ld64 does necessary - 64-bit byteswap already. */ + /* We only need to swap high and low halves. gen_qemu_ld64_i64 does + necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_ld64(ctx, cpu_gpr[rd+1], EA); + gen_qemu_ld64_i64(ctx, cpu_gpr[rd + 1], EA); gen_addr_add(ctx, EA, EA, 8); - gen_qemu_ld64(ctx, cpu_gpr[rd], EA); + gen_qemu_ld64_i64(ctx, cpu_gpr[rd], EA); } else { - gen_qemu_ld64(ctx, cpu_gpr[rd], EA); + gen_qemu_ld64_i64(ctx, cpu_gpr[rd], EA); gen_addr_add(ctx, EA, EA, 8); - gen_qemu_ld64(ctx, cpu_gpr[rd+1], EA); + gen_qemu_ld64_i64(ctx, cpu_gpr[rd + 1], EA); } tcg_temp_free(EA); } @@ -2785,9 +2796,9 @@ GEN_STS(sth, st16, 0x0C, PPC_INTEGER); /* stw stwu stwux stwx */ GEN_STS(stw, st32, 0x04, PPC_INTEGER); #if defined(TARGET_PPC64) -GEN_STUX(std, st64, 0x15, 0x05, PPC_64B); -GEN_STX(std, st64, 0x15, 0x04, PPC_64B); -GEN_STX_HVRM(stdcix, st64, 0x15, 0x1f, PPC_CILDST) +GEN_STUX(std, st64_i64, 0x15, 0x05, PPC_64B); +GEN_STX(std, st64_i64, 0x15, 0x04, PPC_64B); +GEN_STX_HVRM(stdcix, st64_i64, 0x15, 0x1f, PPC_CILDST) GEN_STX_HVRM(stwcix, st32, 0x15, 0x1c, PPC_CILDST) GEN_STX_HVRM(sthcix, st16, 0x15, 0x1d, PPC_CILDST) GEN_STX_HVRM(stbcix, st8, 0x15, 0x1e, PPC_CILDST) @@ -2824,16 +2835,16 @@ static void gen_std(DisasContext *ctx) EA = tcg_temp_new(); gen_addr_imm_index(ctx, EA, 0x03); - /* We only need to swap high and low halves. gen_qemu_st64 does + /* We only need to swap high and low halves. gen_qemu_st64_i64 does necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_st64(ctx, cpu_gpr[rs+1], EA); + gen_qemu_st64_i64(ctx, cpu_gpr[rs + 1], EA); gen_addr_add(ctx, EA, EA, 8); - gen_qemu_st64(ctx, cpu_gpr[rs], EA); + gen_qemu_st64_i64(ctx, cpu_gpr[rs], EA); } else { - gen_qemu_st64(ctx, cpu_gpr[rs], EA); + gen_qemu_st64_i64(ctx, cpu_gpr[rs], EA); gen_addr_add(ctx, EA, EA, 8); - gen_qemu_st64(ctx, cpu_gpr[rs+1], EA); + gen_qemu_st64_i64(ctx, cpu_gpr[rs + 1], EA); } tcg_temp_free(EA); } else { @@ -2847,7 +2858,7 @@ static void gen_std(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_imm_index(ctx, EA, 0x03); - gen_qemu_st64(ctx, cpu_gpr[rs], EA); + gen_qemu_st64_i64(ctx, cpu_gpr[rs], EA); if (Rc(ctx->opcode)) tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); tcg_temp_free(EA); @@ -2857,57 +2868,23 @@ static void gen_std(DisasContext *ctx) /*** Integer load and store with byte reverse ***/ /* lhbrx */ -static inline void gen_qemu_ld16ur(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UW | (ctx->default_tcg_memop_mask ^ MO_BSWAP); - tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); -} GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER); /* lwbrx */ -static inline void gen_qemu_ld32ur(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UL | (ctx->default_tcg_memop_mask ^ MO_BSWAP); - tcg_gen_qemu_ld_tl(arg1, arg2, ctx->mem_idx, op); -} GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER); #if defined(TARGET_PPC64) /* ldbrx */ -static inline void gen_qemu_ld64ur(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_Q | (ctx->default_tcg_memop_mask ^ MO_BSWAP); - tcg_gen_qemu_ld_i64(arg1, arg2, ctx->mem_idx, op); -} -GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX, CHK_NONE); +GEN_LDX_E(ldbr, ld64ur_i64, 0x14, 0x10, PPC_NONE, PPC2_DBRX, CHK_NONE); +/* stdbrx */ +GEN_STX_E(stdbr, st64r_i64, 0x14, 0x14, PPC_NONE, PPC2_DBRX, CHK_NONE); #endif /* TARGET_PPC64 */ /* sthbrx */ -static inline void gen_qemu_st16r(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UW | (ctx->default_tcg_memop_mask ^ MO_BSWAP); - tcg_gen_qemu_st_tl(arg1, arg2, ctx->mem_idx, op); -} GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER); - /* stwbrx */ -static inline void gen_qemu_st32r(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_UL | (ctx->default_tcg_memop_mask ^ MO_BSWAP); - tcg_gen_qemu_st_tl(arg1, arg2, ctx->mem_idx, op); -} GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER); -#if defined(TARGET_PPC64) -/* stdbrx */ -static inline void gen_qemu_st64r(DisasContext *ctx, TCGv arg1, TCGv arg2) -{ - TCGMemOp op = MO_Q | (ctx->default_tcg_memop_mask ^ MO_BSWAP); - tcg_gen_qemu_st_i64(arg1, arg2, ctx->mem_idx, op); -} -GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX, CHK_NONE); -#endif /* TARGET_PPC64 */ - /*** Integer load and store multiple ***/ /* lmw */ @@ -3064,7 +3041,7 @@ static void gen_eieio(DisasContext *ctx) } #if !defined(CONFIG_USER_ONLY) -static inline void gen_check_tlb_flush(DisasContext *ctx) +static inline void gen_check_tlb_flush(DisasContext *ctx, bool global) { TCGv_i32 t; TCGLabel *l; @@ -3076,12 +3053,16 @@ static inline void gen_check_tlb_flush(DisasContext *ctx) t = tcg_temp_new_i32(); tcg_gen_ld_i32(t, cpu_env, offsetof(CPUPPCState, tlb_need_flush)); tcg_gen_brcondi_i32(TCG_COND_EQ, t, 0, l); - gen_helper_check_tlb_flush(cpu_env); + if (global) { + gen_helper_check_tlb_flush_global(cpu_env); + } else { + gen_helper_check_tlb_flush_local(cpu_env); + } gen_set_label(l); tcg_temp_free_i32(t); } #else -static inline void gen_check_tlb_flush(DisasContext *ctx) { } +static inline void gen_check_tlb_flush(DisasContext *ctx, bool global) { } #endif /* isync */ @@ -3092,49 +3073,51 @@ static void gen_isync(DisasContext *ctx) * kernel mode however so check MSR_PR */ if (!ctx->pr) { - gen_check_tlb_flush(ctx); + gen_check_tlb_flush(ctx, false); } gen_stop_exception(ctx); } -#define LARX(name, len, loadop) \ +#define MEMOP_GET_SIZE(x) (1 << ((x) & MO_SIZE)) + +#define LARX(name, memop) \ static void gen_##name(DisasContext *ctx) \ { \ TCGv t0; \ TCGv gpr = cpu_gpr[rD(ctx->opcode)]; \ + int len = MEMOP_GET_SIZE(memop); \ gen_set_access_type(ctx, ACCESS_RES); \ t0 = tcg_temp_local_new(); \ gen_addr_reg_index(ctx, t0); \ if ((len) > 1) { \ gen_check_align(ctx, t0, (len)-1); \ } \ - gen_qemu_##loadop(ctx, gpr, t0); \ + tcg_gen_qemu_ld_tl(gpr, t0, ctx->mem_idx, memop); \ tcg_gen_mov_tl(cpu_reserve, t0); \ tcg_gen_st_tl(gpr, cpu_env, offsetof(CPUPPCState, reserve_val)); \ tcg_temp_free(t0); \ } /* lwarx */ -LARX(lbarx, 1, ld8u); -LARX(lharx, 2, ld16u); -LARX(lwarx, 4, ld32u); - +LARX(lbarx, DEF_MEMOP(MO_UB)) +LARX(lharx, DEF_MEMOP(MO_UW)) +LARX(lwarx, DEF_MEMOP(MO_UL)) #if defined(CONFIG_USER_ONLY) static void gen_conditional_store(DisasContext *ctx, TCGv EA, - int reg, int size) + int reg, int memop) { TCGv t0 = tcg_temp_new(); tcg_gen_st_tl(EA, cpu_env, offsetof(CPUPPCState, reserve_ea)); - tcg_gen_movi_tl(t0, (size << 5) | reg); + tcg_gen_movi_tl(t0, (MEMOP_GET_SIZE(memop) << 5) | reg); tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, reserve_info)); tcg_temp_free(t0); gen_exception_err(ctx, POWERPC_EXCP_STCX, 0); } #else static void gen_conditional_store(DisasContext *ctx, TCGv EA, - int reg, int size) + int reg, int memop) { TCGLabel *l1; @@ -3142,65 +3125,36 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA, l1 = gen_new_label(); tcg_gen_brcond_tl(TCG_COND_NE, EA, cpu_reserve, l1); tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ); -#if defined(TARGET_PPC64) - if (size == 8) { - gen_qemu_st64(ctx, cpu_gpr[reg], EA); - } else -#endif - if (size == 4) { - gen_qemu_st32(ctx, cpu_gpr[reg], EA); - } else if (size == 2) { - gen_qemu_st16(ctx, cpu_gpr[reg], EA); -#if defined(TARGET_PPC64) - } else if (size == 16) { - TCGv gpr1, gpr2 , EA8; - if (unlikely(ctx->le_mode)) { - gpr1 = cpu_gpr[reg+1]; - gpr2 = cpu_gpr[reg]; - } else { - gpr1 = cpu_gpr[reg]; - gpr2 = cpu_gpr[reg+1]; - } - gen_qemu_st64(ctx, gpr1, EA); - EA8 = tcg_temp_local_new(); - gen_addr_add(ctx, EA8, EA, 8); - gen_qemu_st64(ctx, gpr2, EA8); - tcg_temp_free(EA8); -#endif - } else { - gen_qemu_st8(ctx, cpu_gpr[reg], EA); - } + tcg_gen_qemu_st_tl(cpu_gpr[reg], EA, ctx->mem_idx, memop); gen_set_label(l1); tcg_gen_movi_tl(cpu_reserve, -1); } #endif -#define STCX(name, len) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv t0; \ - if (unlikely((len == 16) && (rD(ctx->opcode) & 1))) { \ - gen_inval_exception(ctx, \ - POWERPC_EXCP_INVAL_INVAL); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_RES); \ - t0 = tcg_temp_local_new(); \ - gen_addr_reg_index(ctx, t0); \ - if (len > 1) { \ - gen_check_align(ctx, t0, (len)-1); \ - } \ - gen_conditional_store(ctx, t0, rS(ctx->opcode), len); \ - tcg_temp_free(t0); \ -} - -STCX(stbcx_, 1); -STCX(sthcx_, 2); -STCX(stwcx_, 4); +#define STCX(name, memop) \ +static void gen_##name(DisasContext *ctx) \ +{ \ + TCGv t0; \ + int len = MEMOP_GET_SIZE(memop); \ + gen_set_access_type(ctx, ACCESS_RES); \ + t0 = tcg_temp_local_new(); \ + gen_addr_reg_index(ctx, t0); \ + if (len > 1) { \ + gen_check_align(ctx, t0, (len) - 1); \ + } \ + gen_conditional_store(ctx, t0, rS(ctx->opcode), memop); \ + tcg_temp_free(t0); \ +} + +STCX(stbcx_, DEF_MEMOP(MO_UB)) +STCX(sthcx_, DEF_MEMOP(MO_UW)) +STCX(stwcx_, DEF_MEMOP(MO_UL)) #if defined(TARGET_PPC64) /* ldarx */ -LARX(ldarx, 8, ld64); +LARX(ldarx, DEF_MEMOP(MO_Q)) +/* stdcx. */ +STCX(stdcx_, DEF_MEMOP(MO_Q)) /* lqarx */ static void gen_lqarx(DisasContext *ctx) @@ -3226,21 +3180,63 @@ static void gen_lqarx(DisasContext *ctx) gpr1 = cpu_gpr[rd]; gpr2 = cpu_gpr[rd+1]; } - gen_qemu_ld64(ctx, gpr1, EA); + tcg_gen_qemu_ld_i64(gpr1, EA, ctx->mem_idx, DEF_MEMOP(MO_Q)); tcg_gen_mov_tl(cpu_reserve, EA); - gen_addr_add(ctx, EA, EA, 8); - gen_qemu_ld64(ctx, gpr2, EA); + tcg_gen_qemu_ld_i64(gpr2, EA, ctx->mem_idx, DEF_MEMOP(MO_Q)); tcg_gen_st_tl(gpr1, cpu_env, offsetof(CPUPPCState, reserve_val)); tcg_gen_st_tl(gpr2, cpu_env, offsetof(CPUPPCState, reserve_val2)); + tcg_temp_free(EA); +} + +/* stqcx. */ +static void gen_stqcx_(DisasContext *ctx) +{ + TCGv EA; + int reg = rS(ctx->opcode); + int len = 16; +#if !defined(CONFIG_USER_ONLY) + TCGLabel *l1; + TCGv gpr1, gpr2; +#endif + + if (unlikely((rD(ctx->opcode) & 1))) { + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); + return; + } + gen_set_access_type(ctx, ACCESS_RES); + EA = tcg_temp_local_new(); + gen_addr_reg_index(ctx, EA); + if (len > 1) { + gen_check_align(ctx, EA, (len) - 1); + } + +#if defined(CONFIG_USER_ONLY) + gen_conditional_store(ctx, EA, reg, 16); +#else + tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); + l1 = gen_new_label(); + tcg_gen_brcond_tl(TCG_COND_NE, EA, cpu_reserve, l1); + tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ); + if (unlikely(ctx->le_mode)) { + gpr1 = cpu_gpr[reg + 1]; + gpr2 = cpu_gpr[reg]; + } else { + gpr1 = cpu_gpr[reg]; + gpr2 = cpu_gpr[reg + 1]; + } + tcg_gen_qemu_st_tl(gpr1, EA, ctx->mem_idx, DEF_MEMOP(MO_Q)); + gen_addr_add(ctx, EA, EA, 8); + tcg_gen_qemu_st_tl(gpr2, EA, ctx->mem_idx, DEF_MEMOP(MO_Q)); + + gen_set_label(l1); + tcg_gen_movi_tl(cpu_reserve, -1); +#endif tcg_temp_free(EA); } -/* stdcx. */ -STCX(stdcx_, 8); -STCX(stqcx_, 16); #endif /* defined(TARGET_PPC64) */ /* sync */ @@ -3257,7 +3253,7 @@ static void gen_sync(DisasContext *ctx) * check MSR_PR as well. */ if (((l == 2) || !(ctx->insns_flags & PPC_64B)) && !ctx->pr) { - gen_check_tlb_flush(ctx); + gen_check_tlb_flush(ctx, true); } } @@ -3585,10 +3581,13 @@ static void gen_rfi(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) GEN_PRIV; #else - /* FIXME: This instruction doesn't exist anymore on 64-bit server - * processors compliant with arch 2.x, we should remove it there, - * but we need to fix OpenBIOS not to use it on 970 first + /* This instruction doesn't exist anymore on 64-bit server + * processors compliant with arch 2.x */ + if (ctx->insns_flags & PPC_SEGMENT_64B) { + gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); + return; + } /* Restore CPU state */ CHK_SV; gen_update_cfar(ctx, ctx->nip - 4); @@ -4442,6 +4441,7 @@ static void gen_tlbie(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) GEN_PRIV; #else + TCGv_i32 t1; CHK_HV; if (NARROW_MODE(ctx)) { @@ -4452,6 +4452,11 @@ static void gen_tlbie(DisasContext *ctx) } else { gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); } + t1 = tcg_temp_new_i32(); + tcg_gen_ld_i32(t1, cpu_env, offsetof(CPUPPCState, tlb_need_flush)); + tcg_gen_ori_i32(t1, t1, TLB_NEED_GLOBAL_FLUSH); + tcg_gen_st_i32(t1, cpu_env, offsetof(CPUPPCState, tlb_need_flush)); + tcg_temp_free_i32(t1); #endif /* defined(CONFIG_USER_ONLY) */ } @@ -4463,11 +4468,10 @@ static void gen_tlbsync(DisasContext *ctx) #else CHK_HV; - /* tlbsync is a nop for server, ptesync handles delayed tlb flush, - * embedded however needs to deal with tlbsync. We don't try to be - * fancy and swallow the overhead of checking for both. - */ - gen_check_tlb_flush(ctx); + /* BookS does both ptesync and tlbsync make tlbsync a nop for server */ + if (ctx->insns_flags & PPC_BOOKE) { + gen_check_tlb_flush(ctx, true); + } #endif /* defined(CONFIG_USER_ONLY) */ } @@ -6240,6 +6244,7 @@ GEN_HANDLER_E(prtyw, 0x1F, 0x1A, 0x04, 0x0000F801, PPC_NONE, PPC2_ISA205), GEN_HANDLER(popcntd, 0x1F, 0x1A, 0x0F, 0x0000F801, PPC_POPCNTWD), GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B), GEN_HANDLER_E(cnttzd, 0x1F, 0x1A, 0x11, 0x00000000, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(darn, 0x1F, 0x13, 0x17, 0x001CF801, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(prtyd, 0x1F, 0x1A, 0x05, 0x0000F801, PPC_NONE, PPC2_ISA205), GEN_HANDLER_E(bpermd, 0x1F, 0x1C, 0x07, 0x00000001, PPC_NONE, PPC2_PERM_ISA206), #endif @@ -6614,12 +6619,12 @@ GEN_LDS(lwz, ld32u, 0x00, PPC_INTEGER) #if defined(TARGET_PPC64) GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B) GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B) -GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B) -GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B) -GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX, CHK_NONE) +GEN_LDUX(ld, ld64_i64, 0x15, 0x01, PPC_64B) +GEN_LDX(ld, ld64_i64, 0x15, 0x00, PPC_64B) +GEN_LDX_E(ldbr, ld64ur_i64, 0x14, 0x10, PPC_NONE, PPC2_DBRX, CHK_NONE) /* HV/P7 and later only */ -GEN_LDX_HVRM(ldcix, ld64, 0x15, 0x1b, PPC_CILDST) +GEN_LDX_HVRM(ldcix, ld64_i64, 0x15, 0x1b, PPC_CILDST) GEN_LDX_HVRM(lwzcix, ld32u, 0x15, 0x18, PPC_CILDST) GEN_LDX_HVRM(lhzcix, ld16u, 0x15, 0x19, PPC_CILDST) GEN_LDX_HVRM(lbzcix, ld8u, 0x15, 0x1a, PPC_CILDST) @@ -6650,10 +6655,10 @@ GEN_STS(stb, st8, 0x06, PPC_INTEGER) GEN_STS(sth, st16, 0x0C, PPC_INTEGER) GEN_STS(stw, st32, 0x04, PPC_INTEGER) #if defined(TARGET_PPC64) -GEN_STUX(std, st64, 0x15, 0x05, PPC_64B) -GEN_STX(std, st64, 0x15, 0x04, PPC_64B) -GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX, CHK_NONE) -GEN_STX_HVRM(stdcix, st64, 0x15, 0x1f, PPC_CILDST) +GEN_STUX(std, st64_i64, 0x15, 0x05, PPC_64B) +GEN_STX(std, st64_i64, 0x15, 0x04, PPC_64B) +GEN_STX_E(stdbr, st64r_i64, 0x14, 0x14, PPC_NONE, PPC2_DBRX, CHK_NONE) +GEN_STX_HVRM(stdcix, st64_i64, 0x15, 0x1f, PPC_CILDST) GEN_STX_HVRM(stwcix, st32, 0x15, 0x1c, PPC_CILDST) GEN_STX_HVRM(sthcix, st16, 0x15, 0x1d, PPC_CILDST) GEN_STX_HVRM(stbcix, st8, 0x15, 0x1e, PPC_CILDST) diff --git a/target-ppc/translate/fp-impl.inc.c b/target-ppc/translate/fp-impl.inc.c index 9ba9289..872af7b 100644 --- a/target-ppc/translate/fp-impl.inc.c +++ b/target-ppc/translate/fp-impl.inc.c @@ -672,7 +672,7 @@ static inline void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) } /* lfd lfdu lfdux lfdx */ -GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT); +GEN_LDFS(lfd, ld64_i64, 0x12, PPC_FLOAT); /* lfs lfsu lfsux lfsx */ GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT); @@ -687,16 +687,16 @@ static void gen_lfdp(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); gen_addr_imm_index(ctx, EA, 0); - /* We only need to swap high and low halves. gen_qemu_ld64 does necessary - 64-bit byteswap already. */ + /* We only need to swap high and low halves. gen_qemu_ld64_i64 does + necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); } else { - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); } tcg_temp_free(EA); } @@ -712,16 +712,16 @@ static void gen_lfdpx(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - /* We only need to swap high and low halves. gen_qemu_ld64 does necessary - 64-bit byteswap already. */ + /* We only need to swap high and low halves. gen_qemu_ld64_i64 does + necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); } else { - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); } tcg_temp_free(EA); } @@ -848,7 +848,7 @@ static inline void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) } /* stfd stfdu stfdux stfdx */ -GEN_STFS(stfd, st64, 0x16, PPC_FLOAT); +GEN_STFS(stfd, st64_i64, 0x16, PPC_FLOAT); /* stfs stfsu stfsux stfsx */ GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT); @@ -863,16 +863,16 @@ static void gen_stfdp(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); gen_addr_imm_index(ctx, EA, 0); - /* We only need to swap high and low halves. gen_qemu_st64 does necessary - 64-bit byteswap already. */ + /* We only need to swap high and low halves. gen_qemu_st64_i64 does + necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); } else { - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); } tcg_temp_free(EA); } @@ -888,16 +888,16 @@ static void gen_stfdpx(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - /* We only need to swap high and low halves. gen_qemu_st64 does necessary - 64-bit byteswap already. */ + /* We only need to swap high and low halves. gen_qemu_st64_i64 does + necessary 64-bit byteswap already. */ if (unlikely(ctx->le_mode)) { - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); } else { - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); + gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA); } tcg_temp_free(EA); } @@ -924,9 +924,9 @@ static void gen_lfq(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); gen_addr_imm_index(ctx, t0, 0); - gen_qemu_ld64(ctx, cpu_fpr[rd], t0); + gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0); gen_addr_add(ctx, t0, t0, 8); - gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0); + gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0); tcg_temp_free(t0); } @@ -940,9 +940,9 @@ static void gen_lfqu(DisasContext *ctx) t0 = tcg_temp_new(); t1 = tcg_temp_new(); gen_addr_imm_index(ctx, t0, 0); - gen_qemu_ld64(ctx, cpu_fpr[rd], t0); + gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0); gen_addr_add(ctx, t1, t0, 8); - gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1); + gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1); if (ra != 0) tcg_gen_mov_tl(cpu_gpr[ra], t0); tcg_temp_free(t0); @@ -958,10 +958,10 @@ static void gen_lfqux(DisasContext *ctx) TCGv t0, t1; t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_qemu_ld64(ctx, cpu_fpr[rd], t0); + gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0); t1 = tcg_temp_new(); gen_addr_add(ctx, t1, t0, 8); - gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1); + gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1); tcg_temp_free(t1); if (ra != 0) tcg_gen_mov_tl(cpu_gpr[ra], t0); @@ -976,9 +976,9 @@ static void gen_lfqx(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_qemu_ld64(ctx, cpu_fpr[rd], t0); + gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0); gen_addr_add(ctx, t0, t0, 8); - gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0); + gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0); tcg_temp_free(t0); } @@ -990,9 +990,9 @@ static void gen_stfq(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); gen_addr_imm_index(ctx, t0, 0); - gen_qemu_st64(ctx, cpu_fpr[rd], t0); + gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0); gen_addr_add(ctx, t0, t0, 8); - gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0); + gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0); tcg_temp_free(t0); } @@ -1005,10 +1005,10 @@ static void gen_stfqu(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); gen_addr_imm_index(ctx, t0, 0); - gen_qemu_st64(ctx, cpu_fpr[rd], t0); + gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0); t1 = tcg_temp_new(); gen_addr_add(ctx, t1, t0, 8); - gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1); + gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1); tcg_temp_free(t1); if (ra != 0) tcg_gen_mov_tl(cpu_gpr[ra], t0); @@ -1024,10 +1024,10 @@ static void gen_stfqux(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_qemu_st64(ctx, cpu_fpr[rd], t0); + gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0); t1 = tcg_temp_new(); gen_addr_add(ctx, t1, t0, 8); - gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1); + gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1); tcg_temp_free(t1); if (ra != 0) tcg_gen_mov_tl(cpu_gpr[ra], t0); @@ -1042,9 +1042,9 @@ static void gen_stfqx(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_FLOAT); t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); - gen_qemu_st64(ctx, cpu_fpr[rd], t0); + gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0); gen_addr_add(ctx, t0, t0, 8); - gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0); + gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0); tcg_temp_free(t0); } diff --git a/target-ppc/translate/fp-ops.inc.c b/target-ppc/translate/fp-ops.inc.c index 291a1e6..d36ab4e 100644 --- a/target-ppc/translate/fp-ops.inc.c +++ b/target-ppc/translate/fp-ops.inc.c @@ -85,7 +85,7 @@ GEN_STUF(name, stop, op | 0x21, type) \ GEN_STUXF(name, stop, op | 0x01, type) \ GEN_STXF(name, stop, 0x17, op | 0x00, type) -GEN_STFS(stfd, st64, 0x16, PPC_FLOAT) +GEN_STFS(stfd, st64_i64, 0x16, PPC_FLOAT) GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT) GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX) GEN_HANDLER_E(stfdp, 0x3D, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205), diff --git a/target-ppc/translate/spe-impl.inc.c b/target-ppc/translate/spe-impl.inc.c index 0ce403a..8c1c16c 100644 --- a/target-ppc/translate/spe-impl.inc.c +++ b/target-ppc/translate/spe-impl.inc.c @@ -617,7 +617,7 @@ static inline void gen_addr_spe_imm_index(DisasContext *ctx, TCGv EA, int sh) static inline void gen_op_evldd(DisasContext *ctx, TCGv addr) { TCGv_i64 t0 = tcg_temp_new_i64(); - gen_qemu_ld64(ctx, t0, addr); + gen_qemu_ld64_i64(ctx, t0, addr); gen_store_gpr64(rD(ctx->opcode), t0); tcg_temp_free_i64(t0); } @@ -725,7 +725,7 @@ static inline void gen_op_evstdd(DisasContext *ctx, TCGv addr) { TCGv_i64 t0 = tcg_temp_new_i64(); gen_load_gpr64(t0, rS(ctx->opcode)); - gen_qemu_st64(ctx, t0, addr); + gen_qemu_st64_i64(ctx, t0, addr); tcg_temp_free_i64(t0); } diff --git a/target-ppc/translate/vmx-impl.inc.c b/target-ppc/translate/vmx-impl.inc.c index b984122..3ce374d 100644 --- a/target-ppc/translate/vmx-impl.inc.c +++ b/target-ppc/translate/vmx-impl.inc.c @@ -26,16 +26,16 @@ static void glue(gen_, name)(DisasContext *ctx) EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ tcg_gen_andi_tl(EA, EA, ~0xf); \ - /* We only need to swap high and low halves. gen_qemu_ld64 does necessary \ - 64-bit byteswap already. */ \ + /* We only need to swap high and low halves. gen_qemu_ld64_i64 does \ + necessary 64-bit byteswap already. */ \ if (ctx->le_mode) { \ - gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + gen_qemu_ld64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + gen_qemu_ld64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ } else { \ - gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + gen_qemu_ld64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + gen_qemu_ld64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ } \ tcg_temp_free(EA); \ } @@ -52,16 +52,16 @@ static void gen_st##name(DisasContext *ctx) \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ tcg_gen_andi_tl(EA, EA, ~0xf); \ - /* We only need to swap high and low halves. gen_qemu_st64 does necessary \ - 64-bit byteswap already. */ \ + /* We only need to swap high and low halves. gen_qemu_st64_i64 does \ + necessary 64-bit byteswap already. */ \ if (ctx->le_mode) { \ - gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + gen_qemu_st64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + gen_qemu_st64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ } else { \ - gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ + gen_qemu_st64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \ tcg_gen_addi_tl(EA, EA, 8); \ - gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ + gen_qemu_st64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \ } \ tcg_temp_free(EA); \ } @@ -569,6 +569,21 @@ static void glue(gen_, name)(DisasContext *ctx) \ tcg_temp_free_ptr(rd); \ } +#define GEN_VXFORM_NOA_2(name, opc2, opc3, opc4) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr rb, rd; \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name(rd, rb); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ + } + GEN_VXFORM_NOA(vupkhsb, 7, 8); GEN_VXFORM_NOA(vupkhsh, 7, 9); GEN_VXFORM_NOA(vupkhsw, 7, 25); @@ -639,13 +654,55 @@ static void glue(gen_, name)(DisasContext *ctx) \ tcg_temp_free_ptr(rd); \ } +#define GEN_VXFORM_UIMM_SPLAT(name, opc2, opc3, splat_max) \ +static void glue(gen_, name)(DisasContext *ctx) \ + { \ + TCGv_ptr rb, rd; \ + uint8_t uimm = UIMM4(ctx->opcode); \ + TCGv_i32 t0 = tcg_temp_new_i32(); \ + if (unlikely(!ctx->altivec_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VPU); \ + return; \ + } \ + if (uimm > splat_max) { \ + uimm = 0; \ + } \ + tcg_gen_movi_i32(t0, uimm); \ + rb = gen_avr_ptr(rB(ctx->opcode)); \ + rd = gen_avr_ptr(rD(ctx->opcode)); \ + gen_helper_##name(rd, rb, t0); \ + tcg_temp_free_i32(t0); \ + tcg_temp_free_ptr(rb); \ + tcg_temp_free_ptr(rd); \ + } + GEN_VXFORM_UIMM(vspltb, 6, 8); GEN_VXFORM_UIMM(vsplth, 6, 9); GEN_VXFORM_UIMM(vspltw, 6, 10); +GEN_VXFORM_UIMM_SPLAT(vextractub, 6, 8, 15); +GEN_VXFORM_UIMM_SPLAT(vextractuh, 6, 9, 14); +GEN_VXFORM_UIMM_SPLAT(vextractuw, 6, 10, 12); +GEN_VXFORM_UIMM_SPLAT(vextractd, 6, 11, 8); +GEN_VXFORM_UIMM_SPLAT(vinsertb, 6, 12, 15); +GEN_VXFORM_UIMM_SPLAT(vinserth, 6, 13, 14); +GEN_VXFORM_UIMM_SPLAT(vinsertw, 6, 14, 12); +GEN_VXFORM_UIMM_SPLAT(vinsertd, 6, 15, 8); GEN_VXFORM_UIMM_ENV(vcfux, 5, 12); GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13); GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14); GEN_VXFORM_UIMM_ENV(vctsxs, 5, 15); +GEN_VXFORM_DUAL(vspltb, PPC_NONE, PPC2_ALTIVEC_207, + vextractub, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vsplth, PPC_NONE, PPC2_ALTIVEC_207, + vextractuh, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltw, PPC_NONE, PPC2_ALTIVEC_207, + vextractuw, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltisb, PPC_NONE, PPC2_ALTIVEC_207, + vinsertb, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltish, PPC_NONE, PPC2_ALTIVEC_207, + vinserth, PPC_NONE, PPC2_ISA300); +GEN_VXFORM_DUAL(vspltisw, PPC_NONE, PPC2_ALTIVEC_207, + vinsertw, PPC_NONE, PPC2_ISA300); static void gen_vsldoi(DisasContext *ctx) { @@ -709,6 +766,24 @@ static void gen_vmladduhm(DisasContext *ctx) tcg_temp_free_ptr(rd); } +static void gen_vpermr(DisasContext *ctx) +{ + TCGv_ptr ra, rb, rc, rd; + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + ra = gen_avr_ptr(rA(ctx->opcode)); + rb = gen_avr_ptr(rB(ctx->opcode)); + rc = gen_avr_ptr(rC(ctx->opcode)); + rd = gen_avr_ptr(rD(ctx->opcode)); + gen_helper_vpermr(cpu_env, rd, ra, rb, rc); + tcg_temp_free_ptr(ra); + tcg_temp_free_ptr(rb); + tcg_temp_free_ptr(rc); + tcg_temp_free_ptr(rd); +} + GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18) GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19) GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20) @@ -719,6 +794,10 @@ GEN_VXFORM_NOA(vclzb, 1, 28) GEN_VXFORM_NOA(vclzh, 1, 29) GEN_VXFORM_NOA(vclzw, 1, 30) GEN_VXFORM_NOA(vclzd, 1, 31) +GEN_VXFORM_NOA_2(vctzb, 1, 24, 28) +GEN_VXFORM_NOA_2(vctzh, 1, 24, 29) +GEN_VXFORM_NOA_2(vctzw, 1, 24, 30) +GEN_VXFORM_NOA_2(vctzd, 1, 24, 31) GEN_VXFORM_NOA(vpopcntb, 1, 28) GEN_VXFORM_NOA(vpopcnth, 1, 29) GEN_VXFORM_NOA(vpopcntw, 1, 30) @@ -731,6 +810,7 @@ GEN_VXFORM_DUAL(vclzw, PPC_NONE, PPC2_ALTIVEC_207, \ vpopcntw, PPC_NONE, PPC2_ALTIVEC_207) GEN_VXFORM_DUAL(vclzd, PPC_NONE, PPC2_ALTIVEC_207, \ vpopcntd, PPC_NONE, PPC2_ALTIVEC_207) +GEN_VXFORM(vbpermd, 6, 23); GEN_VXFORM(vbpermq, 6, 21); GEN_VXFORM_NOA(vgbbd, 6, 20); GEN_VXFORM(vpmsumb, 4, 16) diff --git a/target-ppc/translate/vmx-ops.inc.c b/target-ppc/translate/vmx-ops.inc.c index 2a9f225..a7022a0 100644 --- a/target-ppc/translate/vmx-ops.inc.c +++ b/target-ppc/translate/vmx-ops.inc.c @@ -41,6 +41,13 @@ GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ALTIVEC_207) #define GEN_VXFORM_300(name, opc2, opc3) \ GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ISA300) +#define GEN_VXFORM_300_EXT(name, opc2, opc3, inval) \ +GEN_HANDLER_E(name, 0x04, opc2, opc3, inval, PPC_NONE, PPC2_ISA300) + +#define GEN_VXFORM_300_EO(name, opc2, opc3, opc4) \ +GEN_HANDLER_E_2(name, 0x04, opc2, opc3, opc4, 0x00000000, PPC_NONE, \ + PPC2_ISA300) + #define GEN_VXFORM_DUAL(name0, name1, opc2, opc3, type0, type1) \ GEN_HANDLER_E(name0##_##name1, 0x4, opc2, opc3, 0x00000000, type0, type1) @@ -191,11 +198,28 @@ GEN_VXRFORM(vcmpgefp, 3, 7) GEN_VXRFORM_DUAL(vcmpgtfp, vcmpgtud, 3, 11, PPC_ALTIVEC, PPC_NONE) GEN_VXRFORM_DUAL(vcmpbfp, vcmpgtsd, 3, 15, PPC_ALTIVEC, PPC_NONE) -#define GEN_VXFORM_SIMM(name, opc2, opc3) \ - GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) -GEN_VXFORM_SIMM(vspltisb, 6, 12), -GEN_VXFORM_SIMM(vspltish, 6, 13), -GEN_VXFORM_SIMM(vspltisw, 6, 14), +#define GEN_VXFORM_DUAL_INV(name0, name1, opc2, opc3, inval0, inval1, type) \ +GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, \ + PPC_NONE) +GEN_VXFORM_DUAL_INV(vspltb, vextractub, 6, 8, 0x00000000, 0x100000, + PPC2_ALTIVEC_207), +GEN_VXFORM_DUAL_INV(vsplth, vextractuh, 6, 9, 0x00000000, 0x100000, + PPC2_ALTIVEC_207), +GEN_VXFORM_DUAL_INV(vspltw, vextractuw, 6, 10, 0x00000000, 0x100000, + PPC2_ALTIVEC_207), +GEN_VXFORM_300_EXT(vextractd, 6, 11, 0x100000), +GEN_VXFORM_DUAL_INV(vspltisb, vinsertb, 6, 12, 0x00000000, 0x100000, + PPC2_ALTIVEC_207), +GEN_VXFORM_DUAL_INV(vspltish, vinserth, 6, 13, 0x00000000, 0x100000, + PPC2_ALTIVEC_207), +GEN_VXFORM_DUAL_INV(vspltisw, vinsertw, 6, 14, 0x00000000, 0x100000, + PPC2_ALTIVEC_207), +GEN_VXFORM_300_EXT(vinsertd, 6, 15, 0x100000), +GEN_VXFORM_300_EO(vctzb, 0x01, 0x18, 0x1C), +GEN_VXFORM_300_EO(vctzh, 0x01, 0x18, 0x1D), +GEN_VXFORM_300_EO(vctzw, 0x01, 0x18, 0x1E), +GEN_VXFORM_300_EO(vctzd, 0x01, 0x18, 0x1F), +GEN_VXFORM_300(vpermr, 0x1D, 0xFF), #define GEN_VXFORM_NOA(name, opc2, opc3) \ GEN_HANDLER(name, 0x04, opc2, opc3, 0x001f0000, PPC_ALTIVEC) @@ -218,9 +242,6 @@ GEN_VXFORM_NOA(vrfiz, 5, 9), #define GEN_VXFORM_UIMM(name, opc2, opc3) \ GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) -GEN_VXFORM_UIMM(vspltb, 6, 8), -GEN_VXFORM_UIMM(vsplth, 6, 9), -GEN_VXFORM_UIMM(vspltw, 6, 10), GEN_VXFORM_UIMM(vcfux, 5, 12), GEN_VXFORM_UIMM(vcfsx, 5, 13), GEN_VXFORM_UIMM(vctuxs, 5, 14), @@ -241,6 +262,7 @@ GEN_VXFORM_DUAL(vclzh, vpopcnth, 1, 29, PPC_NONE, PPC2_ALTIVEC_207), GEN_VXFORM_DUAL(vclzw, vpopcntw, 1, 30, PPC_NONE, PPC2_ALTIVEC_207), GEN_VXFORM_DUAL(vclzd, vpopcntd, 1, 31, PPC_NONE, PPC2_ALTIVEC_207), +GEN_VXFORM_300(vbpermd, 6, 23), GEN_VXFORM_207(vbpermq, 6, 21), GEN_VXFORM_207(vgbbd, 6, 20), GEN_VXFORM_207(vpmsumb, 4, 16), diff --git a/target-ppc/translate/vsx-impl.inc.c b/target-ppc/translate/vsx-impl.inc.c index 9f77b06..eee6052 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target-ppc/translate/vsx-impl.inc.c @@ -34,8 +34,10 @@ static void gen_##name(DisasContext *ctx) \ tcg_temp_free(EA); \ } -VSX_LOAD_SCALAR(lxsdx, ld64) +VSX_LOAD_SCALAR(lxsdx, ld64_i64) VSX_LOAD_SCALAR(lxsiwax, ld32s_i64) +VSX_LOAD_SCALAR(lxsibzx, ld8u_i64) +VSX_LOAD_SCALAR(lxsihzx, ld16u_i64) VSX_LOAD_SCALAR(lxsiwzx, ld32u_i64) VSX_LOAD_SCALAR(lxsspx, ld32fs) @@ -49,9 +51,9 @@ static void gen_lxvd2x(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); + gen_qemu_ld64_i64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_ld64(ctx, cpu_vsrl(xT(ctx->opcode)), EA); + gen_qemu_ld64_i64(ctx, cpu_vsrl(xT(ctx->opcode)), EA); tcg_temp_free(EA); } @@ -65,7 +67,7 @@ static void gen_lxvdsx(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); + gen_qemu_ld64_i64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xT(ctx->opcode))); tcg_temp_free(EA); } @@ -115,7 +117,10 @@ static void gen_##name(DisasContext *ctx) \ tcg_temp_free(EA); \ } -VSX_STORE_SCALAR(stxsdx, st64) +VSX_STORE_SCALAR(stxsdx, st64_i64) + +VSX_STORE_SCALAR(stxsibx, st8_i64) +VSX_STORE_SCALAR(stxsihx, st16_i64) VSX_STORE_SCALAR(stxsiwx, st32_i64) VSX_STORE_SCALAR(stxsspx, st32fs) @@ -129,9 +134,9 @@ static void gen_stxvd2x(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - gen_qemu_st64(ctx, cpu_vsrh(xS(ctx->opcode)), EA); + gen_qemu_st64_i64(ctx, cpu_vsrh(xS(ctx->opcode)), EA); tcg_gen_addi_tl(EA, EA, 8); - gen_qemu_st64(ctx, cpu_vsrl(xS(ctx->opcode)), EA); + gen_qemu_st64_i64(ctx, cpu_vsrl(xS(ctx->opcode)), EA); tcg_temp_free(EA); } @@ -647,6 +652,26 @@ static void gen_xxspltw(DisasContext *ctx) tcg_temp_free_i64(b2); } +#define pattern(x) (((x) & 0xff) * (~(uint64_t)0 / 0xff)) + +static void gen_xxspltib(DisasContext *ctx) +{ + unsigned char uim8 = IMM8(ctx->opcode); + if (xS(ctx->opcode) < 32) { + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + } else { + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + } + tcg_gen_movi_i64(cpu_vsrh(xT(ctx->opcode)), pattern(uim8)); + tcg_gen_movi_i64(cpu_vsrl(xT(ctx->opcode)), pattern(uim8)); +} + static void gen_xxsldwi(DisasContext *ctx) { TCGv_i64 xth, xtl; diff --git a/target-ppc/translate/vsx-ops.inc.c b/target-ppc/translate/vsx-ops.inc.c index 8b9da65..414b73b 100644 --- a/target-ppc/translate/vsx-ops.inc.c +++ b/target-ppc/translate/vsx-ops.inc.c @@ -1,12 +1,16 @@ GEN_HANDLER_E(lxsdx, 0x1F, 0x0C, 0x12, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxsiwax, 0x1F, 0x0C, 0x02, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(lxsiwzx, 0x1F, 0x0C, 0x00, 0, PPC_NONE, PPC2_VSX207), +GEN_HANDLER_E(lxsibzx, 0x1F, 0x0D, 0x18, 0, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(lxsihzx, 0x1F, 0x0D, 0x19, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(lxsspx, 0x1F, 0x0C, 0x10, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(stxsibx, 0x1F, 0xD, 0x1C, 0, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(stxsihx, 0x1F, 0xD, 0x1D, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(stxsiwx, 0x1F, 0xC, 0x04, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(stxsspx, 0x1F, 0xC, 0x14, 0, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX), @@ -20,6 +24,10 @@ GEN_HANDLER_E(mfvsrd, 0x1F, 0x13, 0x01, 0x0000F800, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(mtvsrd, 0x1F, 0x13, 0x05, 0x0000F800, PPC_NONE, PPC2_VSX207), #endif +#define GEN_XX1FORM(name, opc2, opc3, fl2) \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2) + #define GEN_XX2FORM(name, opc2, opc3, fl2) \ GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \ GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2) @@ -222,6 +230,7 @@ VSX_LOGICAL(xxlorc, 0x8, 0x15, PPC2_VSX207), GEN_XX3FORM(xxmrghw, 0x08, 0x02, PPC2_VSX), GEN_XX3FORM(xxmrglw, 0x08, 0x06, PPC2_VSX), GEN_XX2FORM(xxspltw, 0x08, 0x0A, PPC2_VSX), +GEN_XX1FORM(xxspltib, 0x08, 0x0B, PPC2_ISA300), GEN_XX3FORM_DM(xxsldwi, 0x08, 0x00), #define GEN_XXSEL_ROW(opc3) \ diff --git a/tests/.gitignore b/tests/.gitignore index b4a9cfc..24ac6cf 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -70,6 +70,7 @@ test-string-output-visitor test-thread-pool test-throttle test-timed-average +test-uuid test-visitor-serialization test-vmstate test-write-threshold diff --git a/tests/Makefile.include b/tests/Makefile.include index 6052a38..d8101b3 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -115,6 +115,7 @@ check-unit-y += tests/test-logging$(EXESUF) check-unit-$(CONFIG_REPLICATION) += tests/test-replication$(EXESUF) check-unit-y += tests/test-bufferiszero$(EXESUF) gcov-files-check-bufferiszero-y = util/bufferiszero.c +check-unit-y += tests/test-uuid$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh @@ -268,6 +269,7 @@ check-qtest-ppc64-y += tests/prom-env-test$(EXESUF) check-qtest-ppc64-y += tests/drive_del-test$(EXESUF) check-qtest-ppc64-y += tests/postcopy-test$(EXESUF) check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF) +check-qtest-ppc64-y += tests/rtas-test$(EXESUF) check-qtest-sh4-y = tests/endianness-test$(EXESUF) @@ -296,6 +298,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 @@ -583,6 +586,9 @@ tests/test-crypto-block$(EXESUF): tests/test-crypto-block.o $(test-crypto-obj-y) libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o +libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o +libqos-spapr-obj-y += tests/libqos/libqos-spapr.o +libqos-spapr-obj-y += tests/libqos/rtas.o libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o libqos-pc-obj-y += tests/libqos/ahci.o @@ -597,6 +603,7 @@ tests/m48t59-test$(EXESUF): tests/m48t59-test.o tests/endianness-test$(EXESUF): tests/endianness-test.o tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y) tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y) +tests/rtas-test$(EXESUF): tests/rtas-test.o $(libqos-spapr-obj-y) tests/fdc-test$(EXESUF): tests/fdc-test.o tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y) tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) @@ -658,6 +665,8 @@ 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/test-uuid$(EXESUF): tests/test-uuid.o $(test-util-obj-y) tests/migration/stress$(EXESUF): tests/migration/stress.o $(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ," LINK $(TARGET_DIR)$@") diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index 19d4cc7..2fcc3c6 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -117,7 +117,7 @@ docker-run-%: docker-qemu-src $(if $(DEBUG),-i,--net=none) \ -e TARGET_LIST=$(TARGET_LIST) \ -e EXTRA_CONFIGURE_OPTS=$(EXTRA_CONFIGURE_OPTS) \ - -e V=$V -e J=$J -e DEBUG=$(DEBUG)\ + -e V=$V -e J=$J -e DEBUG=$(DEBUG) -e SHOW_ENV=$(SHOW_ENV)\ -e CCACHE_DIR=/var/tmp/ccache \ -v $$(readlink -e $(DOCKER_SRC_COPY)):/var/tmp/qemu:z$(COMMA)ro \ -v $(DOCKER_CCACHE_DIR):/var/tmp/ccache:z \ diff --git a/tests/docker/common.rc b/tests/docker/common.rc index 0c6d8d5..510a3ad 100755 --- a/tests/docker/common.rc +++ b/tests/docker/common.rc @@ -23,11 +23,13 @@ requires() build_qemu() { - $QEMU_SRC/configure \ - --enable-werror \ - ${TARGET_LIST:+"--target-list=${TARGET_LIST}"} \ - --prefix="$PWD/install" \ - $EXTRA_CONFIGURE_OPTS \ - "$@" + config_opts="--enable-werror \ + ${TARGET_LIST:+--target-list=${TARGET_LIST}} \ + --prefix=$PWD/install \ + $EXTRA_CONFIGURE_OPTS \ + $@" + echo "Configure options:" + echo $config_opts + $QEMU_SRC/configure $config_opts make $MAKEFLAGS } diff --git a/tests/docker/docker.py b/tests/docker/docker.py index b85c165..37d8319 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -21,6 +21,7 @@ import uuid import argparse import tempfile import re +import signal from tarfile import TarFile, TarInfo from StringIO import StringIO from shutil import copy, rmtree @@ -37,9 +38,12 @@ def _guess_docker_command(): """ Guess a working docker command or raise exception if not found""" commands = [["docker"], ["sudo", "-n", "docker"]] for cmd in commands: - if subprocess.call(cmd + ["images"], - stdout=DEVNULL, stderr=DEVNULL) == 0: - return cmd + try: + if subprocess.call(cmd + ["images"], + stdout=DEVNULL, stderr=DEVNULL) == 0: + return cmd + except OSError: + pass commands_txt = "\n".join([" " + " ".join(x) for x in commands]) raise Exception("Cannot find working docker command. Tried:\n%s" % \ commands_txt) @@ -98,6 +102,8 @@ class Docker(object): self._command = _guess_docker_command() self._instances = [] atexit.register(self._kill_instances) + signal.signal(signal.SIGTERM, self._kill_instances) + signal.signal(signal.SIGHUP, self._kill_instances) def _do(self, cmd, quiet=True, infile=None, **kwargs): if quiet: @@ -130,7 +136,7 @@ class Docker(object): self._do_kill_instances(False, False) return 0 - def _kill_instances(self): + def _kill_instances(self, *args, **kwargs): return self._do_kill_instances(True) def _output(self, cmd, **kwargs): diff --git a/tests/docker/dockerfiles/centos6.docker b/tests/docker/dockerfiles/centos6.docker index 8f4fe46..34e0d3b 100644 --- a/tests/docker/dockerfiles/centos6.docker +++ b/tests/docker/dockerfiles/centos6.docker @@ -1,6 +1,8 @@ FROM centos:6 -RUN yum install -y \ +RUN yum install -y epel-release +ENV PACKAGES libfdt-devel ccache \ tar git make gcc g++ \ zlib-devel glib2-devel SDL-devel pixman-devel \ epel-release -RUN yum install -y libfdt-devel ccache +RUN yum install -y $PACKAGES +RUN rpm -q $PACKAGES | sort > /packages.txt diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index 1d26a8e..478163b 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -1,7 +1,17 @@ -FROM fedora:23 -RUN dnf install -y \ +FROM fedora:latest +ENV PACKAGES \ ccache git tar PyYAML sparse flex bison \ glib2-devel pixman-devel zlib-devel SDL-devel libfdt-devel \ gcc gcc-c++ clang make perl which bc findutils \ - mingw{32,64}-{pixman,glib2,gmp,SDL,pkg-config,gtk2,gtk3,gnutls,nettle,libtasn1,libjpeg-turbo,libpng,curl,libssh2,bzip2} + mingw32-pixman mingw32-glib2 mingw32-gmp mingw32-SDL mingw32-pkg-config \ + mingw32-gtk2 mingw32-gtk3 mingw32-gnutls mingw32-nettle mingw32-libtasn1 \ + mingw32-libjpeg-turbo mingw32-libpng mingw32-curl mingw32-libssh2 \ + mingw32-bzip2 \ + mingw64-pixman mingw64-glib2 mingw64-gmp mingw64-SDL mingw64-pkg-config \ + mingw64-gtk2 mingw64-gtk3 mingw64-gnutls mingw64-nettle mingw64-libtasn1 \ + mingw64-libjpeg-turbo mingw64-libpng mingw64-curl mingw64-libssh2 \ + mingw64-bzip2 + +RUN dnf install -y $PACKAGES +RUN rpm -q $PACKAGES | sort > /packages.txt ENV FEATURES mingw clang pyyaml diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker index a8b88c3..a360a05 100644 --- a/tests/docker/dockerfiles/ubuntu.docker +++ b/tests/docker/dockerfiles/ubuntu.docker @@ -2,10 +2,12 @@ FROM ubuntu:14.04 RUN echo "deb http://archive.ubuntu.com/ubuntu/ trusty universe multiverse" >> \ /etc/apt/sources.list RUN apt-get update -RUN apt-get -y install flex bison \ +ENV PACKAGES flex bison \ libusb-1.0-0-dev libiscsi-dev librados-dev libncurses5-dev \ libseccomp-dev libgnutls-dev libssh2-1-dev libspice-server-dev \ libspice-protocol-dev libnss3-dev libfdt-dev \ libgtk-3-dev libvte-2.90-dev libsdl1.2-dev libpng12-dev libpixman-1-dev \ git make ccache python-yaml gcc clang sparse +RUN apt-get -y install $PACKAGES +RUN dpkg -l $PACKAGES | sort > /packages.txt ENV FEATURES clang pyyaml diff --git a/tests/docker/run b/tests/docker/run index d85d49a..c1e4513 100755 --- a/tests/docker/run +++ b/tests/docker/run @@ -40,20 +40,34 @@ for p in dtc pixman; do fi done +if test -n "$SHOW_ENV"; then + if test -f /packages.txt; then + echo "Packages installed:" + cat /packages.txt + echo + fi + echo "Environment variables:" + env + echo +fi + export QEMU_SRC="$TEST_DIR/src" cd "$QEMU_SRC/tests/docker" CMD="$QEMU_SRC/tests/docker/$@" -if test -n "$DEBUG"; then - echo "* Prepared to run command:" - echo " $CMD" - echo "* Hit Ctrl-D to continue, or type 'exit 1' to abort" - echo - $SHELL +if test -z "$DEBUG"; then + exec $CMD fi +# DEBUG workflow +echo "* Prepared to run command:" +echo " $CMD" +echo "* Hit Ctrl-D to continue, or type 'exit 1' to abort" +echo +$SHELL + if "$CMD"; then exit 0 elif test -n "$DEBUG"; then diff --git a/tests/docker/test-quick b/tests/docker/test-quick index 07cdc59..7885dfa 100755 --- a/tests/docker/test-quick +++ b/tests/docker/test-quick @@ -13,7 +13,7 @@ . common.rc -DEF_TARGET_LIST="$(echo {x86_64,aarch64}-softmmu)" +DEF_TARGET_LIST="x86_64-softmmu,aarch64-softmmu" TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \ build_qemu make check $MAKEFLAGS diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c index 72b5e3b..df34092 100644 --- a/tests/libqos/libqos-pc.c +++ b/tests/libqos/libqos-pc.c @@ -21,6 +21,8 @@ QOSState *qtest_pc_boot(const char *cmdline_fmt, ...) qs = qtest_vboot(&qos_ops, cmdline_fmt, ap); va_end(ap); + qtest_irq_intercept_in(global_qtest, "ioapic"); + return qs; } diff --git a/tests/libqos/libqos-spapr.c b/tests/libqos/libqos-spapr.c new file mode 100644 index 0000000..f19408b --- /dev/null +++ b/tests/libqos/libqos-spapr.c @@ -0,0 +1,30 @@ +#include "qemu/osdep.h" +#include "libqos/libqos-spapr.h" +#include "libqos/malloc-spapr.h" + +static QOSOps qos_ops = { + .init_allocator = spapr_alloc_init_flags, + .uninit_allocator = spapr_alloc_uninit +}; + +QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap) +{ + return qtest_vboot(&qos_ops, cmdline_fmt, ap); +} + +QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...) +{ + QOSState *qs; + va_list ap; + + va_start(ap, cmdline_fmt); + qs = qtest_vboot(&qos_ops, cmdline_fmt, ap); + va_end(ap); + + return qs; +} + +void qtest_spapr_shutdown(QOSState *qs) +{ + return qtest_shutdown(qs); +} diff --git a/tests/libqos/libqos-spapr.h b/tests/libqos/libqos-spapr.h new file mode 100644 index 0000000..dcb5c43 --- /dev/null +++ b/tests/libqos/libqos-spapr.h @@ -0,0 +1,10 @@ +#ifndef LIBQOS_SPAPR_H +#define LIBQOS_SPAPR_H + +#include "libqos/libqos.h" + +QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap); +QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...); +void qtest_spapr_shutdown(QOSState *qs); + +#endif diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c index c7ba441..a852dc5 100644 --- a/tests/libqos/libqos.c +++ b/tests/libqos/libqos.c @@ -20,7 +20,6 @@ QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap) cmdline = g_strdup_vprintf(cmdline_fmt, ap); qs->qts = qtest_start(cmdline); qs->ops = ops; - qtest_irq_intercept_in(global_qtest, "ioapic"); if (ops && ops->init_allocator) { qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS); } diff --git a/tests/libqos/malloc-spapr.c b/tests/libqos/malloc-spapr.c new file mode 100644 index 0000000..006404a --- /dev/null +++ b/tests/libqos/malloc-spapr.c @@ -0,0 +1,38 @@ +/* + * libqos malloc support for SPAPR + * + * 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 "libqos/malloc-spapr.h" + +#include "qemu-common.h" + +#define PAGE_SIZE 4096 + +/* Memory must be a multiple of 256 MB, + * so we have at least 256MB + */ +#define SPAPR_MIN_SIZE 0x10000000 + +void spapr_alloc_uninit(QGuestAllocator *allocator) +{ + alloc_uninit(allocator); +} + +QGuestAllocator *spapr_alloc_init_flags(QAllocOpts flags) +{ + QGuestAllocator *s; + + s = alloc_init_flags(flags, 1 << 20, SPAPR_MIN_SIZE); + alloc_set_page_size(s, PAGE_SIZE); + + return s; +} + +QGuestAllocator *spapr_alloc_init(void) +{ + return spapr_alloc_init_flags(ALLOC_NO_FLAGS); +} diff --git a/tests/libqos/malloc-spapr.h b/tests/libqos/malloc-spapr.h new file mode 100644 index 0000000..64d0e77 --- /dev/null +++ b/tests/libqos/malloc-spapr.h @@ -0,0 +1,17 @@ +/* + * libqos malloc support for SPAPR + * + * 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 LIBQOS_MALLOC_SPAPR_H +#define LIBQOS_MALLOC_SPAPR_H + +#include "libqos/malloc.h" + +QGuestAllocator *spapr_alloc_init(void); +QGuestAllocator *spapr_alloc_init_flags(QAllocOpts flags); +void spapr_alloc_uninit(QGuestAllocator *allocator); + +#endif diff --git a/tests/libqos/rtas.c b/tests/libqos/rtas.c new file mode 100644 index 0000000..820321a --- /dev/null +++ b/tests/libqos/rtas.c @@ -0,0 +1,71 @@ +/* + * 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 "libqtest.h" +#include "libqos/rtas.h" + +static void qrtas_copy_args(uint64_t target_args, uint32_t nargs, + uint32_t *args) +{ + int i; + + for (i = 0; i < nargs; i++) { + writel(target_args + i * sizeof(uint32_t), args[i]); + } +} + +static void qrtas_copy_ret(uint64_t target_ret, uint32_t nret, uint32_t *ret) +{ + int i; + + for (i = 0; i < nret; i++) { + ret[i] = readl(target_ret + i * sizeof(uint32_t)); + } +} + +static uint64_t qrtas_call(QGuestAllocator *alloc, const char *name, + uint32_t nargs, uint32_t *args, + uint32_t nret, uint32_t *ret) +{ + uint64_t res; + uint64_t target_args, target_ret; + + target_args = guest_alloc(alloc, nargs * sizeof(uint32_t)); + target_ret = guest_alloc(alloc, nret * sizeof(uint32_t)); + + qrtas_copy_args(target_args, nargs, args); + res = qtest_rtas_call(global_qtest, name, + nargs, target_args, nret, target_ret); + qrtas_copy_ret(target_ret, nret, ret); + + guest_free(alloc, target_ret); + guest_free(alloc, target_args); + + return res; +} + +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns) +{ + int res; + uint32_t ret[8]; + + res = qrtas_call(alloc, "get-time-of-day", 0, NULL, 8, ret); + if (res != 0) { + return res; + } + + res = ret[0]; + memset(tm, 0, sizeof(*tm)); + tm->tm_year = ret[1] - 1900; + tm->tm_mon = ret[2] - 1; + tm->tm_mday = ret[3]; + tm->tm_hour = ret[4]; + tm->tm_min = ret[5]; + tm->tm_sec = ret[6]; + *ns = ret[7]; + + return res; +} diff --git a/tests/libqos/rtas.h b/tests/libqos/rtas.h new file mode 100644 index 0000000..a1b60a8 --- /dev/null +++ b/tests/libqos/rtas.h @@ -0,0 +1,11 @@ +/* + * 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 LIBQOS_RTAS_H +#define LIBQOS_RTAS_H +#include "libqos/malloc.h" + +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns); +#endif /* LIBQOS_RTAS_H */ diff --git a/tests/libqtest.c b/tests/libqtest.c index 42ccb62..6f6bdf1 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -751,6 +751,16 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size) g_strfreev(args); } +uint64_t qtest_rtas_call(QTestState *s, const char *name, + uint32_t nargs, uint64_t args, + uint32_t nret, uint64_t ret) +{ + qtest_sendf(s, "rtas %s %u 0x%"PRIx64" %u 0x%"PRIx64"\n", + name, nargs, args, nret, ret); + qtest_rsp(s, 0); + return 0; +} + void qtest_add_func(const char *str, void (*fn)(void)) { gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str); diff --git a/tests/libqtest.h b/tests/libqtest.h index d2b4853..f7402e0 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -318,6 +318,21 @@ uint64_t qtest_readq(QTestState *s, uint64_t addr); void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size); /** + * qtest_rtas_call: + * @s: #QTestState instance to operate on. + * @name: name of the command to call. + * @nargs: Number of args. + * @args: Guest address to read args from. + * @nret: Number of return value. + * @ret: Guest address to write return values to. + * + * Call an RTAS function + */ +uint64_t qtest_rtas_call(QTestState *s, const char *name, + uint32_t nargs, uint64_t args, + uint32_t nret, uint64_t ret); + +/** * qtest_bufread: * @s: #QTestState instance to operate on. * @addr: Guest address to read from. diff --git a/tests/ptimer-test-stubs.c b/tests/ptimer-test-stubs.c new file mode 100644 index 0000000..92a22fb --- /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 0000000..f207eeb --- /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 0000000..98d9b8f --- /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/rtas-test.c b/tests/rtas-test.c new file mode 100644 index 0000000..73c7803 --- /dev/null +++ b/tests/rtas-test.c @@ -0,0 +1,41 @@ +#include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "libqtest.h" + +#include "libqos/libqos-spapr.h" +#include "libqos/rtas.h" + +static void test_rtas_get_time_of_day(void) +{ + QOSState *qs; + struct tm tm; + uint32_t ns; + uint64_t ret; + time_t t1, t2; + + qs = qtest_spapr_boot("-machine pseries"); + g_assert(qs != NULL); + + t1 = time(NULL); + ret = qrtas_get_time_of_day(qs->alloc, &tm, &ns); + g_assert_cmpint(ret, ==, 0); + t2 = mktimegm(&tm); + g_assert(t2 - t1 < 5); /* 5 sec max to run the test */ + + qtest_spapr_shutdown(qs); +} + +int main(int argc, char *argv[]) +{ + const char *arch = qtest_get_arch(); + + g_test_init(&argc, &argv, NULL); + + if (strcmp(arch, "ppc64")) { + g_printerr("RTAS requires ppc64-softmmu/qemu-system-ppc64\n"); + exit(EXIT_FAILURE); + } + qtest_add_func("rtas/get-time-of-day", test_rtas_get_time_of_day); + + return g_test_run(); +} diff --git a/tests/test-crypto-block.c b/tests/test-crypto-block.c index a38110d..1957a86 100644 --- a/tests/test-crypto-block.c +++ b/tests/test-crypto-block.c @@ -28,7 +28,7 @@ #include <sys/resource.h> #endif -#if defined(CONFIG_UUID) && (defined(_WIN32) || defined RUSAGE_THREAD) +#if (defined(_WIN32) || defined RUSAGE_THREAD) #define TEST_LUKS #else #undef TEST_LUKS diff --git a/tests/test-uuid.c b/tests/test-uuid.c new file mode 100644 index 0000000..77dcdc4 --- /dev/null +++ b/tests/test-uuid.c @@ -0,0 +1,177 @@ +/* + * QEMU UUID Library + * + * Copyright (c) 2016 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qemu/uuid.h" + +struct { + const char *uuidstr; + QemuUUID uuid; + bool uuidstr_is_valid; + bool check_unparse; +} uuid_test_data[] = { + { /* Normal */ + "586ece27-7f09-41e0-9e74-e901317e9d42", + { { { + 0x58, 0x6e, 0xce, 0x27, 0x7f, 0x09, 0x41, 0xe0, + 0x9e, 0x74, 0xe9, 0x01, 0x31, 0x7e, 0x9d, 0x42, + } } }, + true, true, + }, { /* NULL */ + "00000000-0000-0000-0000-000000000000", + { }, + true, true, + }, { /* Upper case */ + "0CC6C752-3961-4028-A286-C05CC616D396", + { { { + 0x0c, 0xc6, 0xc7, 0x52, 0x39, 0x61, 0x40, 0x28, + 0xa2, 0x86, 0xc0, 0x5c, 0xc6, 0x16, 0xd3, 0x96, + } } }, + true, false, + }, { /* Mixed case */ + "0CC6C752-3961-4028-a286-c05cc616D396", + { { { + 0x0c, 0xc6, 0xc7, 0x52, 0x39, 0x61, 0x40, 0x28, + 0xa2, 0x86, 0xc0, 0x5c, 0xc6, 0x16, 0xd3, 0x96, + } } }, + true, false, + }, { /* Empty */ + "" + }, { /* Too short */ + "abc", + }, { /* Non-hex */ + "abcdefgh-0000-0000-0000-000000000000", + }, { /* No '-' */ + "0cc6c75239614028a286c05cc616d396", + }, { /* '-' in wrong position */ + "0cc6c-7523961-4028-a286-c05cc616d396", + }, { /* Double '-' */ + "0cc6c752--3961-4028-a286-c05cc616d396", + }, { /* Too long */ + "0000000000000000000000000000000000000000000000", + }, { /* Invalid char in the beginning */ + ")cc6c752-3961-4028-a286-c05cc616d396", + }, { /* Invalid char in the beginning, in extra */ + ")0cc6c752-3961-4028-a286-c05cc616d396", + }, { /* Invalid char in the middle */ + "0cc6c752-39*1-4028-a286-c05cc616d396", + }, { /* Invalid char in the middle, in extra */ + "0cc6c752-39*61-4028-a286-c05cc616d396", + }, { /* Invalid char in the end */ + "0cc6c752-3961-4028-a286-c05cc616d39&", + }, { /* Invalid char in the end, in extra */ + "0cc6c752-3961-4028-a286-c05cc616d396&", + }, { /* Short end and trailing space */ + "0cc6c752-3961-4028-a286-c05cc616d39 ", + }, { /* Leading space and short end */ + " 0cc6c752-3961-4028-a286-c05cc616d39", + }, +}; + +static inline bool uuid_is_valid(QemuUUID *uuid) +{ + return qemu_uuid_is_null(uuid) || + ((uuid->data[6] & 0xf0) == 0x40 && (uuid->data[8] & 0xc0) == 0x80); +} + +static void test_uuid_generate(void) +{ + QemuUUID uuid; + int i; + + for (i = 0; i < 100; ++i) { + qemu_uuid_generate(&uuid); + g_assert(uuid_is_valid(&uuid)); + } +} + +static void test_uuid_is_null(void) +{ + QemuUUID uuid_null = { }; + QemuUUID uuid_not_null = { { { + 0x58, 0x6e, 0xce, 0x27, 0x7f, 0x09, 0x41, 0xe0, + 0x9e, 0x74, 0xe9, 0x01, 0x31, 0x7e, 0x9d, 0x42 + } } }; + QemuUUID uuid_not_null_2 = { { { 1 } } }; + + g_assert(qemu_uuid_is_null(&uuid_null)); + g_assert_false(qemu_uuid_is_null(&uuid_not_null)); + g_assert_false(qemu_uuid_is_null(&uuid_not_null_2)); +} + +static void test_uuid_parse(void) +{ + int i, r; + + for (i = 0; i < ARRAY_SIZE(uuid_test_data); i++) { + QemuUUID uuid; + bool is_valid = uuid_test_data[i].uuidstr_is_valid; + + r = qemu_uuid_parse(uuid_test_data[i].uuidstr, &uuid); + g_assert_cmpint(!r, ==, is_valid); + if (is_valid) { + g_assert_cmpint(is_valid, ==, uuid_is_valid(&uuid)); + g_assert_cmpmem(&uuid_test_data[i].uuid, sizeof(uuid), + &uuid, sizeof(uuid)); + } + } +} + +static void test_uuid_unparse(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(uuid_test_data); i++) { + char out[37]; + + if (!uuid_test_data[i].check_unparse) { + continue; + } + qemu_uuid_unparse(&uuid_test_data[i].uuid, out); + g_assert_cmpstr(uuid_test_data[i].uuidstr, ==, out); + } +} + +static void test_uuid_unparse_strdup(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(uuid_test_data); i++) { + char *out; + + if (!uuid_test_data[i].check_unparse) { + continue; + } + out = qemu_uuid_unparse_strdup(&uuid_test_data[i].uuid); + g_assert_cmpstr(uuid_test_data[i].uuidstr, ==, out); + } +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/uuid/generate", test_uuid_generate); + g_test_add_func("/uuid/is_null", test_uuid_is_null); + g_test_add_func("/uuid/parse", test_uuid_parse); + g_test_add_func("/uuid/unparse", test_uuid_unparse); + g_test_add_func("/uuid/unparse_strdup", test_uuid_unparse_strdup); + + return g_test_run(); +} diff --git a/ui/spice-core.c b/ui/spice-core.c index da05054..1452e77 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -796,7 +796,7 @@ void qemu_spice_init(void) qemu_opt_foreach(opts, add_channel, &tls_port, NULL); spice_server_set_name(spice_server, qemu_name); - spice_server_set_uuid(spice_server, qemu_uuid); + spice_server_set_uuid(spice_server, (unsigned char *)&qemu_uuid); seamless_migration = qemu_opt_get_bool(opts, "seamless-migration", 0); spice_server_set_seamless_migration(spice_server, seamless_migration); diff --git a/util/Makefile.objs b/util/Makefile.objs index ffca8f3..36c7dcc 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -21,6 +21,7 @@ util-obj-y += iov.o qemu-config.o qemu-sockets.o uri.o notify.o util-obj-y += qemu-option.o qemu-progress.o util-obj-y += hexdump.o util-obj-y += crc32c.o +util-obj-y += uuid.o util-obj-y += throttle.o util-obj-y += getauxval.o util-obj-y += readline.o diff --git a/util/uuid.c b/util/uuid.c new file mode 100644 index 0000000..dd6b5fd --- /dev/null +++ b/util/uuid.c @@ -0,0 +1,114 @@ +/* + * QEMU UUID functions + * + * Copyright 2016 Red Hat, Inc. + * + * Authors: + * Fam Zheng <famz@redhat.com> + * + * 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. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/uuid.h" +#include "qemu/bswap.h" + +void qemu_uuid_generate(QemuUUID *uuid) +{ + int i; + uint32_t tmp[4]; + + QEMU_BUILD_BUG_ON(sizeof(QemuUUID) != 16); + + for (i = 0; i < 4; ++i) { + tmp[i] = g_random_int(); + } + memcpy(uuid, tmp, sizeof(tmp)); + /* Set the two most significant bits (bits 6 and 7) of the + clock_seq_hi_and_reserved to zero and one, respectively. */ + uuid->data[8] = (uuid->data[8] & 0x3f) | 0x80; + /* Set the four most significant bits (bits 12 through 15) of the + time_hi_and_version field to the 4-bit version number. + */ + uuid->data[6] = (uuid->data[6] & 0xf) | 0x40; +} + +int qemu_uuid_is_null(const QemuUUID *uu) +{ + static QemuUUID null_uuid; + return memcmp(uu, &null_uuid, sizeof(QemuUUID)) == 0; +} + +void qemu_uuid_unparse(const QemuUUID *uuid, char *out) +{ + const unsigned char *uu = &uuid->data[0]; + snprintf(out, UUID_FMT_LEN + 1, UUID_FMT, + uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7], + uu[8], uu[9], uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]); +} + +char *qemu_uuid_unparse_strdup(const QemuUUID *uuid) +{ + const unsigned char *uu = &uuid->data[0]; + return g_strdup_printf(UUID_FMT, + uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], + uu[7], uu[8], uu[9], uu[10], uu[11], uu[12], + uu[13], uu[14], uu[15]); +} + +static bool qemu_uuid_is_valid(const char *str) +{ + int i; + + for (i = 0; i < strlen(str); i++) { + const char c = str[i]; + if (i == 8 || i == 13 || i == 18 || i == 23) { + if (str[i] != '-') { + return false; + } + } else { + if ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f')) { + continue; + } + return false; + } + } + return i == 36; +} + +int qemu_uuid_parse(const char *str, QemuUUID *uuid) +{ + unsigned char *uu = &uuid->data[0]; + int ret; + + if (!qemu_uuid_is_valid(str)) { + return -1; + } + + ret = sscanf(str, UUID_FMT, &uu[0], &uu[1], &uu[2], &uu[3], + &uu[4], &uu[5], &uu[6], &uu[7], &uu[8], &uu[9], + &uu[10], &uu[11], &uu[12], &uu[13], &uu[14], + &uu[15]); + + if (ret != 16) { + return -1; + } + return 0; +} + +/* Swap from UUID format endian (BE) to the opposite or vice versa. + */ +void qemu_uuid_bswap(QemuUUID *uuid) +{ + assert(QEMU_PTR_IS_ALIGNED(uuid, sizeof(uint32_t))); + bswap32s(&uuid->fields.time_low); + bswap16s(&uuid->fields.time_mid); + bswap16s(&uuid->fields.time_high_and_version); +} @@ -25,6 +25,7 @@ #include "qemu-version.h" #include "qemu/cutils.h" #include "qemu/help_option.h" +#include "qemu/uuid.h" #ifdef CONFIG_SECCOMP #include "sysemu/seccomp.h" @@ -182,10 +183,10 @@ uint8_t qemu_extra_params_fw[2]; int icount_align_option; -/* The bytes in qemu_uuid[] are in the order specified by RFC4122, _not_ in the +/* The bytes in qemu_uuid are in the order specified by RFC4122, _not_ in the * little-endian "wire format" described in the SMBIOS 2.6 specification. */ -uint8_t qemu_uuid[16]; +QemuUUID qemu_uuid; bool qemu_uuid_set; static NotifierList exit_notifiers = @@ -3779,7 +3780,7 @@ int main(int argc, char **argv, char **envp) cursor_hide = 0; break; case QEMU_OPTION_uuid: - if(qemu_uuid_parse(optarg, qemu_uuid) < 0) { + if (qemu_uuid_parse(optarg, &qemu_uuid) < 0) { error_report("failed to parse UUID string: wrong format"); exit(1); } |