diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2020-07-15 17:16:39 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2020-07-15 17:16:39 +0100 |
commit | dfcade7cefb433f8cf46788b771a085a625286d8 (patch) | |
tree | e8f0a7b835c807b753cdbc4cb39ae1f7e8962717 | |
parent | f1d5948669041d01d245ce42894fcec2eebbaab1 (diff) | |
parent | 0571d280d057b851e3bb3ea7c350b86c950aea6e (diff) |
Merge remote-tracking branch 'remotes/stsquad/tags/pull-misc-for-rc0-150720-3' into staging
Final fixes for 5.1-rc0
- minor documentation nit
- docker.py bootstrap fixes
- tweak containers.yml wildcards
- fix float16 nan detection
- conditional use of -Wpsabi
- fix missing iotlb data for plugins
- proper locking for helper based bb count
- drop ppc64abi32 from the plugin check-tcg test
# gpg: Signature made Wed 15 Jul 2020 11:59:08 BST
# gpg: using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44
# gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [full]
# Primary key fingerprint: 6685 AE99 E751 67BC AFC8 DF35 FBD0 DB09 5A9E 2A44
* remotes/stsquad/tags/pull-misc-for-rc0-150720-3:
.travis.yml: skip ppc64abi32-linux-user with plugins
plugins: expand the bb plugin to be thread safe and track per-cpu
cputlb: ensure we save the IOTLB data in case of reset
tests/plugins: don't unconditionally add -Wpsabi
fpu/softfloat: fix up float16 nan recognition
gitlab-ci/containers: Add missing wildcard where we should look for changes
docker.py: fix fetching of FROM layers
tests/docker: Remove the libssh workaround from the ubuntu 20.04 image
docs/devel: fix grammar in multi-thread-tcg
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | .gitlab-ci.d/containers.yml | 1 | ||||
-rw-r--r-- | .travis.yml | 3 | ||||
-rw-r--r-- | accel/tcg/cputlb.c | 38 | ||||
-rwxr-xr-x | configure | 3 | ||||
-rw-r--r-- | docs/devel/multi-thread-tcg.rst | 2 | ||||
-rw-r--r-- | fpu/softfloat-specialize.inc.c | 4 | ||||
-rw-r--r-- | include/hw/core/cpu.h | 16 | ||||
-rw-r--r-- | include/qemu/typedefs.h | 1 | ||||
-rwxr-xr-x | tests/docker/docker.py | 16 | ||||
-rw-r--r-- | tests/docker/dockerfiles/ubuntu2004.docker | 3 | ||||
-rw-r--r-- | tests/plugin/Makefile | 22 | ||||
-rw-r--r-- | tests/plugin/bb.c | 97 |
12 files changed, 174 insertions, 32 deletions
diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml index f3c0ca4d61..8c89efeb6d 100644 --- a/.gitlab-ci.d/containers.yml +++ b/.gitlab-ci.d/containers.yml @@ -24,6 +24,7 @@ - changes: - .gitlab-ci.d/containers.yml - tests/docker/* + - tests/docker/dockerfiles/* - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' - if: '$CI_COMMIT_REF_NAME == "testing/next"' diff --git a/.travis.yml b/.travis.yml index ab429500fc..6695c0620f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -350,9 +350,10 @@ jobs: # Run check-tcg against linux-user (with plugins) # we skip sparc64-linux-user until it has been fixed somewhat # we skip cris-linux-user as it doesn't use the common run loop + # we skip ppc64abi32-linux-user as it seems to have a broken libc - name: "GCC plugins check-tcg (user)" env: - - CONFIG="--disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user,cris-linux-user" + - CONFIG="--disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user,cris-linux-user,ppc64abi32-linux-user" - TEST_BUILD_CMD="make build-tcg" - TEST_CMD="make check-tcg" - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg" diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 1e815357c7..d370aedb47 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1073,6 +1073,24 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, return val; } +/* + * Save a potentially trashed IOTLB entry for later lookup by plugin. + * + * We also need to track the thread storage address because the RCU + * cleanup that runs when we leave the critical region (the current + * execution) is actually in a different thread. + */ +static void save_iotlb_data(CPUState *cs, hwaddr addr, + MemoryRegionSection *section, hwaddr mr_offset) +{ +#ifdef CONFIG_PLUGIN + SavedIOTLB *saved = &cs->saved_iotlb; + saved->addr = addr; + saved->section = section; + saved->mr_offset = mr_offset; +#endif +} + static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, int mmu_idx, uint64_t val, target_ulong addr, uintptr_t retaddr, MemOp op) @@ -1092,6 +1110,12 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, } cpu->mem_io_pc = retaddr; + /* + * The memory_region_dispatch may trigger a flush/resize + * so for plugins we save the iotlb_data just in case. + */ + save_iotlb_data(cpu, iotlbentry->addr, section, mr_offset); + if (mr->global_locking && !qemu_mutex_iothread_locked()) { qemu_mutex_lock_iothread(); locked = true; @@ -1381,8 +1405,11 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, * in the softmmu lookup code (or helper). We don't handle re-fills or * checking the victim table. This is purely informational. * - * This should never fail as the memory access being instrumented - * should have just filled the TLB. + * This almost never fails as the memory access being instrumented + * should have just filled the TLB. The one corner case is io_writex + * which can cause TLB flushes and potential resizing of the TLBs + * loosing the information we need. In those cases we need to recover + * data from a copy of the io_tlb entry. */ bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx, @@ -1406,8 +1433,13 @@ bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx, data->v.ram.hostaddr = addr + tlbe->addend; } return true; + } else { + SavedIOTLB *saved = &cpu->saved_iotlb; + data->is_io = true; + data->v.io.section = saved->section; + data->v.io.offset = saved->mr_offset; + return true; } - return false; } #endif @@ -7115,6 +7115,9 @@ echo "GIT_UPDATE=$git_update" >> $config_host_mak echo "ARCH=$ARCH" >> $config_host_mak +echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak +echo "GLIB_LDFLAGS=$glib_ldflags" >> $config_host_mak + if test "$default_devices" = "yes" ; then echo "CONFIG_MINIKCONF_MODE=--defconfig" >> $config_host_mak else diff --git a/docs/devel/multi-thread-tcg.rst b/docs/devel/multi-thread-tcg.rst index 42158b77c7..21483870db 100644 --- a/docs/devel/multi-thread-tcg.rst +++ b/docs/devel/multi-thread-tcg.rst @@ -107,7 +107,7 @@ including: - debugging operations (breakpoint insertion/removal) - some CPU helper functions - - linux-user spawning it's first thread + - linux-user spawning its first thread This is done with the async_safe_run_on_cpu() mechanism to ensure all vCPUs are quiescent when changes are being made to shared global diff --git a/fpu/softfloat-specialize.inc.c b/fpu/softfloat-specialize.inc.c index 44f5b661f8..034d18199c 100644 --- a/fpu/softfloat-specialize.inc.c +++ b/fpu/softfloat-specialize.inc.c @@ -254,7 +254,7 @@ bool float16_is_quiet_nan(float16 a_, float_status *status) if (snan_bit_is_one(status)) { return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF); } else { - return ((a & ~0x8000) >= 0x7C80); + return ((a >> 9) & 0x3F) == 0x3F; } #endif } @@ -271,7 +271,7 @@ bool float16_is_signaling_nan(float16 a_, float_status *status) #else uint16_t a = float16_val(a_); if (snan_bit_is_one(status)) { - return ((a & ~0x8000) >= 0x7C80); + return ((a >> 9) & 0x3F) == 0x3F; } else { return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF); } diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 5542577d2b..8f145733ce 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -259,6 +259,18 @@ struct CPUWatchpoint { QTAILQ_ENTRY(CPUWatchpoint) entry; }; +#ifdef CONFIG_PLUGIN +/* + * For plugins we sometime need to save the resolved iotlb data before + * the memory regions get moved around by io_writex. + */ +typedef struct SavedIOTLB { + hwaddr addr; + MemoryRegionSection *section; + hwaddr mr_offset; +} SavedIOTLB; +#endif + struct KVMState; struct kvm_run; @@ -417,7 +429,11 @@ struct CPUState { DECLARE_BITMAP(plugin_mask, QEMU_PLUGIN_EV_MAX); +#ifdef CONFIG_PLUGIN GArray *plugin_mem_cbs; + /* saved iotlb data from io_writex */ + SavedIOTLB saved_iotlb; +#endif /* TODO Move common fields from CPUArchState here. */ int cpu_index; diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 15f5047bf1..427027a970 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -116,6 +116,7 @@ typedef struct QObject QObject; typedef struct QString QString; typedef struct RAMBlock RAMBlock; typedef struct Range Range; +typedef struct SavedIOTLB SavedIOTLB; typedef struct SHPCDevice SHPCDevice; typedef struct SSIBus SSIBus; typedef struct VirtIODevice VirtIODevice; diff --git a/tests/docker/docker.py b/tests/docker/docker.py index 2d67bbd15a..c9f20d8d09 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -306,14 +306,18 @@ class Docker(object): checksum = _text_checksum(_dockerfile_preprocess(dockerfile)) if registry is not None: - # see if we can fetch a cache copy, may fail... - pull_args = ["pull", "%s/%s" % (registry, tag)] - if self._do(pull_args, quiet=quiet) == 0: + sources = re.findall("FROM qemu\/(.*)", dockerfile) + # Fetch any cache layers we can, may fail + for s in sources: + pull_args = ["pull", "%s/qemu/%s" % (registry, s)] + if self._do(pull_args, quiet=quiet) != 0: + registry = None + break + # Make substitutions + if registry is not None: dockerfile = dockerfile.replace("FROM qemu/", "FROM %s/qemu/" % (registry)) - else: - registry = None tmp_df = tempfile.NamedTemporaryFile(mode="w+t", encoding='utf-8', @@ -339,6 +343,8 @@ class Docker(object): build_args += ["--build-arg", "BUILDKIT_INLINE_CACHE=1"] if registry is not None: + pull_args = ["pull", "%s/%s" % (registry, tag)] + self._do(pull_args, quiet=quiet) cache = "%s/%s" % (registry, tag) build_args += ["--cache-from", cache] build_args += argv diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index f7aac840bf..8d10934a2a 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -65,9 +65,6 @@ RUN apt-get update && \ RUN dpkg -l $PACKAGES | sort > /packages.txt ENV FEATURES clang tsan pyyaml sdl2 -# https://bugs.launchpad.net/qemu/+bug/1838763 -ENV QEMU_CONFIGURE_OPTS --disable-libssh - # Apply patch https://reviews.llvm.org/D75820 # This is required for TSan in clang-10 to compile with QEMU. RUN sed -i 's/^const/static const/g' /usr/lib/llvm-10/lib/clang/10.0.0/include/sanitizer/tsan_interface.h diff --git a/tests/plugin/Makefile b/tests/plugin/Makefile index 3a50451428..e9348fde4a 100644 --- a/tests/plugin/Makefile +++ b/tests/plugin/Makefile @@ -1,9 +1,16 @@ +# -*- Mode: makefile -*- +# +# This Makefile example is fairly independent from the main makefile +# so users can take and adapt it for their build. We only really +# include config-host.mak so we don't have to repeat probing for +# cflags that the main configure has already done for us. +# + BUILD_DIR := $(CURDIR)/../.. include $(BUILD_DIR)/config-host.mak -include $(SRC_PATH)/rules.mak -$(call set-vpath, $(SRC_PATH)/tests/plugin) +VPATH += $(SRC_PATH)/tests/plugin NAMES := NAMES += bb @@ -17,11 +24,18 @@ NAMES += lockstep SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES))) -QEMU_CFLAGS += -fPIC -Wpsabi -QEMU_CFLAGS += -I$(SRC_PATH)/include/qemu +# The main QEMU uses Glib extensively so it's perfectly fine to use it +# in plugins (which many example do). +CFLAGS = $(GLIB_CFLAGS) +CFLAGS += -fPIC +CFLAGS += $(if $(findstring no-psabi,$(QEMU_CFLAGS)),-Wpsabi) +CFLAGS += -I$(SRC_PATH)/include/qemu all: $(SONAMES) +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + lib%.so: %.o $(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDLIBS) diff --git a/tests/plugin/bb.c b/tests/plugin/bb.c index df19fd359d..e4cc7fdd6e 100644 --- a/tests/plugin/bb.c +++ b/tests/plugin/bb.c @@ -16,24 +16,67 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; -static uint64_t bb_count; -static uint64_t insn_count; +typedef struct { + GMutex lock; + int index; + uint64_t bb_count; + uint64_t insn_count; +} CPUCount; + +/* Used by the inline & linux-user counts */ static bool do_inline; +static CPUCount inline_count; + +/* Dump running CPU total on idle? */ +static bool idle_report; +static GPtrArray *counts; +static int max_cpus; + +static void gen_one_cpu_report(CPUCount *count, GString *report) +{ + if (count->bb_count) { + g_string_append_printf(report, "CPU%d: " + "bb's: %" PRIu64", insns: %" PRIu64 "\n", + count->index, + count->bb_count, count->insn_count); + } +} static void plugin_exit(qemu_plugin_id_t id, void *p) { - g_autofree gchar *out = g_strdup_printf( - "bb's: %" PRIu64", insns: %" PRIu64 "\n", - bb_count, insn_count); - qemu_plugin_outs(out); + g_autoptr(GString) report = g_string_new(""); + + if (do_inline || !max_cpus) { + g_string_printf(report, "bb's: %" PRIu64", insns: %" PRIu64 "\n", + inline_count.bb_count, inline_count.insn_count); + } else { + g_ptr_array_foreach(counts, (GFunc) gen_one_cpu_report, report); + } + qemu_plugin_outs(report->str); +} + +static void vcpu_idle(qemu_plugin_id_t id, unsigned int cpu_index) +{ + CPUCount *count = g_ptr_array_index(counts, cpu_index); + g_autoptr(GString) report = g_string_new(""); + gen_one_cpu_report(count, report); + + if (report->len > 0) { + g_string_prepend(report, "Idling "); + qemu_plugin_outs(report->str); + } } static void vcpu_tb_exec(unsigned int cpu_index, void *udata) { - unsigned long n_insns = (unsigned long)udata; + CPUCount *count = max_cpus ? + g_ptr_array_index(counts, cpu_index) : &inline_count; - insn_count += n_insns; - bb_count++; + unsigned long n_insns = (unsigned long)udata; + g_mutex_lock(&count->lock); + count->insn_count += n_insns; + count->bb_count++; + g_mutex_unlock(&count->lock); } static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) @@ -42,9 +85,10 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) if (do_inline) { qemu_plugin_register_vcpu_tb_exec_inline(tb, QEMU_PLUGIN_INLINE_ADD_U64, - &bb_count, 1); + &inline_count.bb_count, 1); qemu_plugin_register_vcpu_tb_exec_inline(tb, QEMU_PLUGIN_INLINE_ADD_U64, - &insn_count, n_insns); + &inline_count.insn_count, + n_insns); } else { qemu_plugin_register_vcpu_tb_exec_cb(tb, vcpu_tb_exec, QEMU_PLUGIN_CB_NO_REGS, @@ -56,8 +100,35 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, int argc, char **argv) { - if (argc && strcmp(argv[0], "inline") == 0) { - do_inline = true; + int i; + + for (i = 0; i < argc; i++) { + char *opt = argv[i]; + if (g_strcmp0(opt, "inline") == 0) { + do_inline = true; + } else if (g_strcmp0(opt, "idle") == 0) { + idle_report = true; + } else { + fprintf(stderr, "option parsing failed: %s\n", opt); + return -1; + } + } + + if (info->system_emulation && !do_inline) { + max_cpus = info->system.max_vcpus; + counts = g_ptr_array_new(); + for (i = 0; i < max_cpus; i++) { + CPUCount *count = g_new0(CPUCount, 1); + g_mutex_init(&count->lock); + count->index = i; + g_ptr_array_add(counts, count); + } + } else if (!do_inline) { + g_mutex_init(&inline_count.lock); + } + + if (idle_report) { + qemu_plugin_register_vcpu_idle_cb(id, vcpu_idle); } qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); |