All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults
@ 2016-10-27 15:09 Alex Bennée
  2016-10-27 15:09 ` [Qemu-devel] [PATCH v5 01/33] cpus: make all_vcpus_paused() return bool Alex Bennée
                   ` (33 more replies)
  0 siblings, 34 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:09 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée

This is the fifth iteration of the MTTCG patches and I'm finally
dropping the RFC tag from the series. Previous versions had suffered
from hangs which have been fixed by the additional cputlb fixes. A lot
of races where identified and fixed using ThreadSanitizer (although a
chunk of those fixes will come in a separate series).

I'm hoping to get this into 2.8 although if the maintainers aren't
quite ready to take the full tree I'd appreciate cherry picking a good
chunk of the clean-up patches to reduce the delta we need to hold over
some of the work to the 2.9 cycle. This series enables MTTCG for ARM
guests on x86_64 hosts by default.

Prerequisites
=============

Most of the pre-requisites have already been merged. The final one is
a solution for atomic instruction emulation. This series has been
based on v7 of Emilo & Richard's cmpxchg based atomics series. Once
that is merged this series should apply cleanly.

You can find the base of my tree at:

  https://github.com/stsquad/qemu/tree/mttcg/cmpxchg-atomics-v7-prepull

Changes
=======

Since the last posting there have been a number of updates to the
original patches:

   - usual update of r-b tags
   - fixed bunch of races identified by ThreadSanitizer
   - updated the single-threaded kick timer as per review comments
   - a bunch of BQL asserts (IRQ processing)
   - use of parallel_cpus/tb_flush to ensure correct codegen
   - cputlb updates for atomic setting of dirty flags
   - cputlb fixes where work was not being deferred to async safe work

It introduces a new patch to add run_on_cpu_data as a type for the
*_run_on_cpu functions. The main aim is to ensure a target pointer
(i.e. target_ulong) can always be passed in one argument even when
emulating 64 bit targets on a 32 bit build.

Finally there are some ARM specific updates:

   - cpu_reset is deferred to async work
   - arm specific messing to TLB removed
   - BQL taken for ARM_CP_IO register access
   - some helpers take BQL

The last two patches expand on the approach we take for device
emulation through MMIO. Any case where the emulation may touch global
state (device emulation, cross-vCPU) needs to take the BQL. Simple
helper functions which only update their own cpu->env are not
affected.

Testing on additional hardware models would be useful although pretty
much any MMIO device is already protected by the BQL. The ARM_CP_IO
registers where a little special as they updated the GIC which needed
locking for serialisation.

As usual the patches themselves have a revision summary under the ---

A copy of the tree can be found at:

  https://github.com/stsquad/qemu/tree/mttcg/base-patches-v5


Testing
=======

I've tested this boots ARMv7/ARMv8 Debian with a repeating compile
test load (which previously would trigger cputlb races) as well as
both ARMv7 and v8 kvm-unit-tests with both:

  -accel tcg,thread=single

and:

  -accel tcg,thread=multi

Performance
===========

The following was measured with my boot+build benchmark:

 $QEMU_BIN -machine type=virt -display none -m 4096 \
   -cpu $CPU -serial telnet:127.0.0.1:4444 -monitor stdio \
   -netdev user,id=unet,hostfwd=tcp::2222-:22 \
   -device virtio-net-device,netdev=unet \
   -drive file=${JESSIE}.qcow2,id=myblock,index=0,if=none,snapshot=on \
   -device virtio-blk-device,drive=myblock
   -append "console=ttyAMA0 root=/dev/vda1 systemd.unit=benchmark-build.service" \
   -kernel ${KERNEL} -name debug-threads=on \
   -machine gic-version=3 -accel tcg,thread=multi -smp @

My Desktop (i7, 4+4)

| smp | armv7, single | armv7, multi |    x | armv8, single | armv8, multi |    x |
|-----+---------------+--------------+------+---------------+--------------+------|
|   1 |       224.035 |      224.010 | 1.00 |       397.285 |      399.456 | 0.99 |
|   2 |       231.043 |      125.923 | 1.83 |       415.307 |      225.760 | 1.84 |
|   3 |       235.548 |       94.837 | 2.48 |       422.565 |      170.647 | 2.48 |
|   4 |       239.403 |       81.145 | 2.95 |       432.743 |      146.869 | 2.95 |
|   5 |       243.107 |       81.045 | 3.00 |       435.414 |      146.367 | 2.97 |
|   6 |       249.164 |       78.742 | 3.16 |       445.176 |      143.415 | 3.10 |

Alex

Alex Bennée (28):
  cpus: make all_vcpus_paused() return bool
  translate_all: DEBUG_FLUSH -> DEBUG_TB_FLUSH
  translate-all: add DEBUG_LOCKING asserts
  cpu-exec: include cpu_index in CPU_LOG_EXEC messages
  docs: new design document multi-thread-tcg.txt (DRAFTING)
  linux-user/elfload: ensure mmap_lock() held while setting up
  translate-all: Add assert_(memory|tb)_lock annotations
  target-arm/arm-powerctl: wake up sleeping CPUs
  tcg: move tcg_exec_all and helpers above thread fn
  tcg: cpus rm tcg_exec_all()
  tcg: add kick timer for single-threaded vCPU emulation
  tcg: rename tcg_current_cpu to tcg_current_rr_cpu
  cpus: re-factor out handle_icount_deadline
  tcg: remove global exit_request
  tcg: move locking for tb_invalidate_phys_page_range up
  tcg: enable tb_lock() for SoftMMU
  tcg: enable thread-per-vCPU
  atomic: introduce cmpxchg_bool
  *_run_on_cpu: introduce run_on_cpu_data type
  cputlb: add assert_cpu_is_self checks
  cputlb: tweak qemu_ram_addr_from_host_nofail reporting
  cputlb: atomically update tlb fields used by tlb_reset_dirty
  cputlb: make tlb_flush_by_mmuidx safe for MTTCG
  target-arm/powerctl: defer cpu reset work to CPU context
  target-arm/cpu: don't reset TLB structures, use cputlb to do it
  target-arm: ensure BQL taken for ARM_CP_IO register access
  target-arm: helpers which may affect global state need the BQL
  tcg: enable MTTCG by default for ARM on x86 hosts

Jan Kiszka (1):
  tcg: drop global lock during TCG code execution

KONRAD Frederic (3):
  tcg: protect translation related stuff with tb_lock.
  tcg: add options for enabling MTTCG
  cputlb: introduce tlb_flush_* async work.

Paolo Bonzini (1):
  tcg: comment on which functions have to be called with tb_lock held

 bsd-user/mmap.c                 |   5 +
 configure                       |  12 +
 cpu-exec-common.c               |   3 -
 cpu-exec.c                      |  48 ++--
 cpus-common.c                   |   9 +-
 cpus.c                          | 544 ++++++++++++++++++++++++++--------------
 cputlb.c                        | 400 +++++++++++++++++++++++------
 default-configs/arm-softmmu.mak |   2 +
 docs/multi-thread-tcg.txt       | 310 +++++++++++++++++++++++
 exec.c                          |  28 +++
 hw/core/irq.c                   |   1 +
 hw/i386/kvm/apic.c              |  14 +-
 hw/i386/kvmvapic.c              |  17 +-
 hw/intc/arm_gicv3_cpuif.c       |   3 +
 hw/ppc/ppce500_spin.c           |   6 +-
 hw/ppc/spapr.c                  |   7 +-
 hw/ppc/spapr_hcall.c            |  12 +-
 include/exec/cputlb.h           |   2 -
 include/exec/exec-all.h         |   7 +-
 include/qemu/atomic.h           |   9 +
 include/qom/cpu.h               |  51 +++-
 include/sysemu/cpus.h           |   2 +
 kvm-all.c                       |  20 +-
 linux-user/elfload.c            |   4 +
 linux-user/mmap.c               |   5 +
 memory.c                        |   2 +
 qemu-options.hx                 |  20 ++
 qom/cpu.c                       |  10 +
 target-arm/Makefile.objs        |   2 +-
 target-arm/arm-powerctl.c       | 142 ++++++-----
 target-arm/cpu.c                |   6 +
 target-arm/helper.c             |   6 +
 target-arm/op_helper.c          |  43 +++-
 target-i386/helper.c            |   8 +-
 target-i386/kvm.c               |   4 +-
 target-i386/smm_helper.c        |   7 +
 target-s390x/cpu.c              |   4 +-
 target-s390x/cpu.h              |   4 +-
 target-s390x/misc_helper.c      |   9 +-
 tcg/tcg.h                       |   2 +
 translate-all.c                 | 192 +++++++++++---
 translate-common.c              |  21 +-
 vl.c                            |  49 +++-
 43 files changed, 1590 insertions(+), 462 deletions(-)
 create mode 100644 docs/multi-thread-tcg.txt

-- 
2.10.1

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 01/33] cpus: make all_vcpus_paused() return bool
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
@ 2016-10-27 15:09 ` Alex Bennée
  2016-10-27 15:09 ` [Qemu-devel] [PATCH v5 02/33] translate_all: DEBUG_FLUSH -> DEBUG_TB_FLUSH Alex Bennée
                   ` (32 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:09 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Sergey Fedorov <sergey.fedorov@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>

---
v3
  - add r-b tags
---
 cpus.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/cpus.c b/cpus.c
index cfd5cdc..5324ba3 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1207,17 +1207,17 @@ void qemu_mutex_unlock_iothread(void)
     qemu_mutex_unlock(&qemu_global_mutex);
 }
 
-static int all_vcpus_paused(void)
+static bool all_vcpus_paused(void)
 {
     CPUState *cpu;
 
     CPU_FOREACH(cpu) {
         if (!cpu->stopped) {
-            return 0;
+            return false;
         }
     }
 
-    return 1;
+    return true;
 }
 
 void pause_all_vcpus(void)
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 02/33] translate_all: DEBUG_FLUSH -> DEBUG_TB_FLUSH
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
  2016-10-27 15:09 ` [Qemu-devel] [PATCH v5 01/33] cpus: make all_vcpus_paused() return bool Alex Bennée
@ 2016-10-27 15:09 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 03/33] translate-all: add DEBUG_LOCKING asserts Alex Bennée
                   ` (31 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:09 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

Make the debug define consistent with the others. The flush operation is
all about invalidating TranslationBlocks on flush events.

Also fix up the commenting on the other DEBUG for the benefit of
checkpatch.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 translate-all.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/translate-all.c b/translate-all.c
index 4200869..8907302 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -56,10 +56,10 @@
 #include "qemu/timer.h"
 #include "exec/log.h"
 
-//#define DEBUG_TB_INVALIDATE
-//#define DEBUG_FLUSH
+/* #define DEBUG_TB_INVALIDATE */
+/* #define DEBUG_TB_FLUSH */
 /* make various TB consistency checks */
-//#define DEBUG_TB_CHECK
+/* #define DEBUG_TB_CHECK */
 
 #if !defined(CONFIG_USER_ONLY)
 /* TB consistency checks only implemented for usermode emulation.  */
@@ -848,7 +848,7 @@ static void do_tb_flush(CPUState *cpu, void *data)
         goto done;
     }
 
-#if defined(DEBUG_FLUSH)
+#if defined(DEBUG_TB_FLUSH)
     printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
            (unsigned long)(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer),
            tcg_ctx.tb_ctx.nb_tbs, tcg_ctx.tb_ctx.nb_tbs > 0 ?
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 03/33] translate-all: add DEBUG_LOCKING asserts
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
  2016-10-27 15:09 ` [Qemu-devel] [PATCH v5 01/33] cpus: make all_vcpus_paused() return bool Alex Bennée
  2016-10-27 15:09 ` [Qemu-devel] [PATCH v5 02/33] translate_all: DEBUG_FLUSH -> DEBUG_TB_FLUSH Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 04/33] cpu-exec: include cpu_index in CPU_LOG_EXEC messages Alex Bennée
                   ` (30 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite,
	Riku Voipio

This adds asserts to check the locking on the various translation
engines structures. There are two sets of structures that are protected
by locks.

The first the l1map and PageDesc structures used to track which
translation blocks are associated with which physical addresses. In
user-mode this is covered by the mmap_lock.

The second case are TB context related structures which are protected by
tb_lock which is also user-mode only.

Currently the asserts do nothing in SoftMMU mode but this will change
for MTTCG.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 bsd-user/mmap.c         |  5 +++++
 include/exec/exec-all.h |  1 +
 linux-user/mmap.c       |  5 +++++
 translate-all.c         | 41 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 52 insertions(+)

diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
index 610f91b..ee59073 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -42,6 +42,11 @@ void mmap_unlock(void)
     }
 }
 
+bool have_mmap_lock(void)
+{
+    return mmap_lock_count > 0 ? true : false;
+}
+
 /* Grab lock to make sure things are in a consistent state after fork().  */
 void mmap_fork_start(void)
 {
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 13633a2..84fecc8 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -370,6 +370,7 @@ void tlb_fill(CPUState *cpu, target_ulong addr, MMUAccessType access_type,
 #if defined(CONFIG_USER_ONLY)
 void mmap_lock(void);
 void mmap_unlock(void);
+bool have_mmap_lock(void);
 
 static inline tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
 {
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index c4371d9..19aeec5 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -43,6 +43,11 @@ void mmap_unlock(void)
     }
 }
 
+bool have_mmap_lock(void)
+{
+    return mmap_lock_count > 0 ? true : false;
+}
+
 /* Grab lock to make sure things are in a consistent state after fork().  */
 void mmap_fork_start(void)
 {
diff --git a/translate-all.c b/translate-all.c
index 8907302..758f654 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -31,6 +31,7 @@
 #include "tcg.h"
 #if defined(CONFIG_USER_ONLY)
 #include "qemu.h"
+#include "exec/exec-all.h"
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 #include <sys/param.h>
 #if __FreeBSD_version >= 700104
@@ -58,6 +59,7 @@
 
 /* #define DEBUG_TB_INVALIDATE */
 /* #define DEBUG_TB_FLUSH */
+/* #define DEBUG_LOCKING */
 /* make various TB consistency checks */
 /* #define DEBUG_TB_CHECK */
 
@@ -66,6 +68,28 @@
 #undef DEBUG_TB_CHECK
 #endif
 
+/* Access to the various translations structures need to be serialised via locks
+ * for consistency. This is automatic for SoftMMU based system
+ * emulation due to its single threaded nature. In user-mode emulation
+ * access to the memory related structures are protected with the
+ * mmap_lock.
+ */
+#ifdef DEBUG_LOCKING
+#define DEBUG_MEM_LOCKS 1
+#else
+#define DEBUG_MEM_LOCKS 0
+#endif
+
+#ifdef CONFIG_SOFTMMU
+#define assert_memory_lock() do { /* nothing */ } while (0)
+#else
+#define assert_memory_lock() do {               \
+        if (DEBUG_MEM_LOCKS) {                  \
+            g_assert(have_mmap_lock());         \
+        }                                       \
+    } while (0)
+#endif
+
 #define SMC_BITMAP_USE_THRESHOLD 10
 
 typedef struct PageDesc {
@@ -154,6 +178,23 @@ void tb_lock_reset(void)
 #endif
 }
 
+#ifdef DEBUG_LOCKING
+#define DEBUG_TB_LOCKS 1
+#else
+#define DEBUG_TB_LOCKS 0
+#endif
+
+#ifdef CONFIG_SOFTMMU
+#define assert_tb_lock() do { /* nothing */ } while (0)
+#else
+#define assert_tb_lock() do {               \
+        if (DEBUG_TB_LOCKS) {               \
+            g_assert(have_tb_lock);         \
+        }                                   \
+    } while (0)
+#endif
+
+
 static TranslationBlock *tb_find_pc(uintptr_t tc_ptr);
 
 void cpu_gen_init(void)
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 04/33] cpu-exec: include cpu_index in CPU_LOG_EXEC messages
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (2 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 03/33] translate-all: add DEBUG_LOCKING asserts Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 05/33] docs: new design document multi-thread-tcg.txt (DRAFTING) Alex Bennée
                   ` (29 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

Even more important when debugging MTTCG is seeing which vCPU is
currently executing.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 cpu-exec.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/cpu-exec.c b/cpu-exec.c
index c999793..4879c7d 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -143,8 +143,9 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
     uint8_t *tb_ptr = itb->tc_ptr;
 
     qemu_log_mask_and_addr(CPU_LOG_EXEC, itb->pc,
-                           "Trace %p [" TARGET_FMT_lx "] %s\n",
-                           itb->tc_ptr, itb->pc, lookup_symbol(itb->pc));
+                           "Trace %p [%d: " TARGET_FMT_lx "] %s\n",
+                           itb->tc_ptr, cpu->cpu_index, itb->pc,
+                           lookup_symbol(itb->pc));
 
 #if defined(DEBUG_DISAS)
     if (qemu_loglevel_mask(CPU_LOG_TB_CPU)
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 05/33] docs: new design document multi-thread-tcg.txt (DRAFTING)
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (3 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 04/33] cpu-exec: include cpu_index in CPU_LOG_EXEC messages Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 06/33] tcg: comment on which functions have to be called with tb_lock held Alex Bennée
                   ` (28 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée

This is a current DRAFT of a design proposal for upgrading TCG emulation
to take advantage of modern CPUs by running a thread-per-CPU. The
document goes through the various areas of the code affected by such a
change and proposes design requirements for each part of the solution.

Where solutions have been merged upstream the approach is described
underneath the design requirements. Where the solutions are still under
discussion they are marked with (Current solution[s]) to document what
the current approaches being used are. Currently there are several
proposed solutions for modelling atomic operations.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v1
  - initial version
v2
  - update discussion on locks
  - bit more detail on vCPU scheduling
  - explicitly mention Translation Blocks
  - emulated hardware state already covered by iomutex
  - a few minor rewords
v3
  - mention this covers system-mode
  - describe main main-loop and lookup hot-path
  - mention multi-concurrent-reader lookups
  - enumerate reasons for invalidation
  - add more details on lookup structures
  - describe the softmmu hot-path better
  - mention store-after-load barrier problem
v4
  - mention some cross-over between linux-user/system emulation
  - various minor grammar and scanning fixes
  - fix reference to tb_ctx.htbale
  - describe the solution for hot-path
  - more detail on TB flushing and invalidation
  - add (Current solution) following design requirements
  - more detail on iothread/BQL mutex
  - mention implicit memory barriers
  - add links to current LL/SC and cmpxchg patch sets
  - add TLB flag setting as an additional requirement
---
 docs/multi-thread-tcg.txt | 310 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 310 insertions(+)
 create mode 100644 docs/multi-thread-tcg.txt

diff --git a/docs/multi-thread-tcg.txt b/docs/multi-thread-tcg.txt
new file mode 100644
index 0000000..9f676c0
--- /dev/null
+++ b/docs/multi-thread-tcg.txt
@@ -0,0 +1,310 @@
+Copyright (c) 2015 Linaro Ltd.
+
+This work is licensed under the terms of the GNU GPL, version 2 or later.  See
+the COPYING file in the top-level directory.
+
+STATUS: DRAFTING
+
+Introduction
+============
+
+This document outlines the design for multi-threaded TCG system-mode
+emulation. The current user-mode emulation mirrors the thread
+structure of the translated executable. Some of the work will be
+applicable to both system and linux-user emulation.
+
+The original system-mode TCG implementation was single threaded and
+dealt with multiple CPUs with simple round-robin scheduling. This
+simplified a lot of things but became increasingly limited as systems
+being emulated gained additional cores and per-core performance gains
+for host systems started to level off.
+
+vCPU Scheduling
+===============
+
+We introduce a new running mode where each vCPU will run on its own
+user-space thread. This will be enabled by default for all FE/BE
+combinations that have had the required work done to support this
+safely.
+
+In the general case of running translated code there should be no
+inter-vCPU dependencies and all vCPUs should be able to run at full
+speed. Synchronisation will only be required while accessing internal
+shared data structures or when the emulated architecture requires a
+coherent representation of the emulated machine state.
+
+Shared Data Structures
+======================
+
+Main Run Loop
+-------------
+
+Even when there is no code being generated there are a number of
+structures associated with the hot-path through the main run-loop.
+These are associated with looking up the next translation block to
+execute. These include:
+
+    tb_jmp_cache (per-vCPU, cache of recent jumps)
+    tb_ctx.htable (global hash table, phys address->tb lookup)
+
+As TB linking only occurs when blocks are in the same page this code
+is critical to performance as looking up the next TB to execute is the
+most common reason to exit the generated code.
+
+DESIGN REQUIREMENT: Make access to lookup structures safe with
+multiple reader/writer threads. Minimise any lock contention to do it.
+
+The hot-path avoids using locks where possible. The tb_jmp_cache is
+updated with atomic accesses to ensure consistent results. The fall
+back QHT based hash table is also designed for lockless lookups. Locks
+are only taken when code generation is required or TranslationBlocks
+have their block-to-block jumps patched.
+
+Global TCG State
+----------------
+
+We need to protect the entire code generation cycle including any post
+generation patching of the translated code. This also implies a shared
+translation buffer which contains code running on all cores. Any
+execution path that comes to the main run loop will need to hold a
+mutex for code generation. This also includes times when we need flush
+code or entries from any shared lookups/caches. Structures held on a
+per-vCPU basis won't need locking unless other vCPUs will need to
+modify them.
+
+DESIGN REQUIREMENT: Add locking around all code generation and TB
+patching.
+
+Translation Blocks
+------------------
+
+Currently the whole system shares a single code generation buffer
+which when full will force a flush of all translations and start from
+scratch again. Some operations also force a full flush of translations
+including:
+
+  - debugging operations (breakpoint insertion/removal)
+  - some CPU helper functions
+
+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
+structures.
+
+More granular translation invalidation events are typically due
+to a change of the state of a physical page:
+
+  - code modification (self modify code, patching code)
+  - page changes (new page mapping in linux-user mode)
+
+While setting the invalid flag in a TranslationBlock will stop it
+being used when looked up in the hot-path there are a number of other
+book-keeping structures that need to be safely cleared.
+
+Any TranslationBlocks which have been patched to jump directly to the
+now invalid blocks need the jump patches reversing so they will return
+to the C code.
+
+There are a number of look-up caches that need to be properly updated
+including the:
+
+  - jump lookup cache
+  - the physical-to-tb lookup hash table
+  - the global page table
+
+The global page table (l1_map) which provides a multi-level look-up
+for PageDesc structures which contain pointers to the start of a
+linked list of all Translation Blocks in that page (see page_next).
+
+Both the jump patching and the page cache involve linked lists that
+the invalidated TranslationBlock needs to be removed from.
+
+DESIGN REQUIREMENT: Safely handle invalidation of TBs
+                      - safely patch/revert direct jumps
+                      - remove central PageDesc lookup entries
+                      - ensure lookup caches/hashes are safely updated
+
+(Current solution)
+
+The direct jump themselves are updated atomically by the TCG
+tb_set_jmp_target() code. Modification to the linked lists that allow
+searching for linked pages are done under the protect of the
+tb_lock().
+
+The global page table is protected by the tb_lock() in system-mode and
+mmap_lock() in linux-user mode.
+
+The lookup caches are updated atomically and the lookup hash uses QHT
+which is designed for concurrent safe lookup.
+
+
+Memory maps and TLBs
+--------------------
+
+The memory handling code is fairly critical to the speed of memory
+access in the emulated system. The SoftMMU code is designed so the
+hot-path can be handled entirely within translated code. This is
+handled with a per-vCPU TLB structure which once populated will allow
+a series of accesses to the page to occur without exiting the
+translated code. It is possible to set flags in the TLB address which
+will ensure the slow-path is taken for each access. This can be done
+to support:
+
+  - Memory regions (dividing up access to PIO, MMIO and RAM)
+  - Dirty page tracking (for code gen, SMC detection, migration and display)
+  - Virtual TLB (for translating guest address->real address)
+
+When the TLB tables are updated by a vCPU thread other than their own
+we need to ensure it is done in a safe way so no inconsistent state is
+seen by the vCPU thread.
+
+Some operations require updating a number of vCPUs TLBs at the same
+time in a synchronised manner.
+
+DESIGN REQUIREMENTS:
+
+  - TLB Flush All/Page
+    - can be across-vCPUs
+    - cross vCPU TLB flush may need other vCPU brought to halt
+    - change may need to be visible to the calling vCPU immediately
+  - TLB Flag Update
+    - usually cross-vCPU
+    - want change to be visible as soon as possible
+  - TLB Update (update a CPUTLBEntry, via tlb_set_page_with_attrs)
+    - This is a per-vCPU table - by definition can't race
+    - updated by its own thread when the slow-path is forced
+
+(Current solution)
+
+When we detect a cross-vCPU operation we use the
+async_safe_run_on_cpu() to defer running the operations until all
+vCPUs are quiescent. We can jump to the top of the run loop if we want
+the change to be visible to that vCPU straight away.
+
+Emulated hardware state
+-----------------------
+
+Currently thanks to KVM work any access to IO memory is automatically
+protected by the global iothread mutex, also known as the BQL (Big
+Qemu Lock). Any IO region that doesn't use global mutex is expected to
+do its own locking.
+
+As the global iothread mutex is shared across the system we push the
+use of the lock as far down into the TCG code as possible to minimise
+contention.
+
+Memory Consistency
+==================
+
+Between emulated guests and host systems there are a range of memory
+consistency models. Even emulating weakly ordered systems on strongly
+ordered hosts needs to ensure things like store-after-load re-ordering
+can be prevented when the guest wants to.
+
+Memory Barriers
+---------------
+
+Barriers (sometimes known as fences) provide a mechanism for software
+to enforce a particular ordering of memory operations from the point
+of view of external observers (e.g. another processor core). They can
+apply to any memory operations as well as just loads or stores.
+
+The Linux kernel has an excellent write-up on the various forms of
+memory barrier and the guarantees they can provide [1].
+
+Barriers are often wrapped around synchronisation primitives to
+provide explicit memory ordering semantics. However they can be used
+by themselves to provide safe lockless access by ensuring for example
+a change to a signal flag will only be visible once the changes to
+payload are.
+
+DESIGN REQUIREMENT: Add a new tcg_memory_barrier op
+
+This would enforce a strong load/store ordering so all loads/stores
+complete at the memory barrier. On single-core non-SMP strongly
+ordered backends this could become a NOP.
+
+Aside from explicit standalone memory barrier instructions there are
+also implicit memory ordering semantics which comes with each guest
+memory access instruction. For example all x86 load/stores come with
+fairly strong guarantees of sequential consistency where as ARM has
+special variants of load/store instructions that imply acquire/release
+semantics.
+
+In the case of a strongly ordered guest architecture being emulated on
+a weakly ordered host the scope for a heavy performance impact is
+quite high.
+
+DESIGN REQUIREMENTS: Be efficient with use of memory barriers
+       - host systems with stronger implied guarantees can skip some barriers
+       - merge consecutive barriers to the strongest one
+
+(Current solution)
+
+As the emulation of barriers is also a problem for linux-user
+emulation the current patch set is being developed separately from the
+MTTCG effort and will hopefully be merged before the rest of MTTCG.
+The latest iterations can be found at:
+
+    http://lists.nongnu.org/archive/html/qemu-devel/2016-07/msg03283.html
+    http://lists.nongnu.org/archive/html/qemu-devel/2016-07/msg03283.html
+
+Memory Control and Maintenance
+------------------------------
+
+This includes a class of instructions for controlling system cache
+behaviour. While QEMU doesn't model cache behaviour these instructions
+are often seen when code modification has taken place to ensure the
+changes take effect.
+
+Synchronisation Primitives
+--------------------------
+
+There are two broad types of synchronisation primitives found in
+modern ISAs: atomic instructions and exclusive regions.
+
+The first type offer a simple atomic instruction which will guarantee
+some sort of test and conditional store will be truly atomic w.r.t.
+other cores sharing access to the memory. The classic example is the
+x86 cmpxchg instruction.
+
+The second type offer a pair of load/store instructions which offer a
+guarantee that an region of memory has not been touched between the
+load and store instructions. An example of this is ARM's ldrex/strex
+pair where the strex instruction will return a flag indicating a
+successful store only if no other CPU has accessed the memory region
+since the ldrex.
+
+Traditionally TCG has generated a series of operations that work
+because they are within the context of a single translation block so
+will have completed before another CPU is scheduled. However with
+the ability to have multiple threads running to emulate multiple CPUs
+we will need to explicitly expose these semantics.
+
+DESIGN REQUIREMENTS:
+  - Support classic atomic instructions
+  - Support load/store exclusive (or load link/store conditional) pairs
+  - Generic enough infrastructure to support all guest architectures
+CURRENT OPEN QUESTIONS:
+  - How problematic is the ABA problem in general
+  - How do we solve atomic problems where the host's largest atomic
+  operation is smaller than the guests (64bit on 32bit).
+
+(Current solutions)
+
+There a number of solutions currently being proposed. The eventual
+solution will likely involve a trade off between performance and
+completeness. For example in practice most guest synchronisation
+sequences are unlikely to trigger the ABA problem.
+
+The current patch series are:
+
+  - Alvise Rigo's Slow-path for atomic instruction translation
+    http://lists.nongnu.org/archive/html/qemu-devel/2016-04/msg02913.html
+    http://lists.nongnu.org/archive/html/qemu-devel/2016-05/msg04789.html
+
+  - Emilio G. Cota's cmpxchg-based emulation of atomics
+    http://lists.nongnu.org/archive/html/qemu-devel/2016-07/msg00152.html
+
+==========
+
+[1] https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/Documentation/memory-barriers.txt
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 06/33] tcg: comment on which functions have to be called with tb_lock held
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (4 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 05/33] docs: new design document multi-thread-tcg.txt (DRAFTING) Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 07/33] linux-user/elfload: ensure mmap_lock() held while setting up Alex Bennée
                   ` (27 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

From: Paolo Bonzini <pbonzini@redhat.com>

softmmu requires more functions to be thread-safe, because translation
blocks can be invalidated from e.g. notdirty callbacks.  Probably the
same holds for user-mode emulation, it's just that no one has ever
tried to produce a coherent locking there.

This patch will guide the introduction of more tb_lock and tb_unlock
calls for system emulation.

Note that after this patch some (most) of the mentioned functions are
still called outside tb_lock/tb_unlock.  The next one will rectify this.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
v1(ajb):
  - just s-o-b
v2
  - clarify write lock on tb_jump_cache
v3
  - drop RCU comment for debug stuff (separate commit now)
v5
  - fix merge failure that broke DEBUG_TB_CHECK
---
 include/exec/exec-all.h |  1 +
 include/qom/cpu.h       |  3 +++
 tcg/tcg.h               |  2 ++
 translate-all.c         | 28 +++++++++++++++++++++++-----
 4 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 84fecc8..189deb8 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -317,6 +317,7 @@ static inline void tb_set_jmp_target(TranslationBlock *tb,
 
 #endif
 
+/* Called with tb_lock held.  */
 static inline void tb_add_jump(TranslationBlock *tb, int n,
                                TranslationBlock *tb_next)
 {
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 6d481a1..44571da 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -319,7 +319,10 @@ struct CPUState {
     MemoryRegion *memory;
 
     void *env_ptr; /* CPUArchState */
+
+    /* Writes protected by tb_lock, reads not thread-safe  */
     struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE];
+
     struct GDBRegisterState *gdb_regs;
     int gdb_num_regs;
     int gdb_num_g_regs;
diff --git a/tcg/tcg.h b/tcg/tcg.h
index b34b5fb..dc1281f 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -726,6 +726,7 @@ static inline bool tcg_op_buf_full(void)
 
 /* pool based memory allocation */
 
+/* tb_lock must be held for tcg_malloc_internal. */
 void *tcg_malloc_internal(TCGContext *s, int size);
 void tcg_pool_reset(TCGContext *s);
 
@@ -733,6 +734,7 @@ void tb_lock(void);
 void tb_unlock(void);
 void tb_lock_reset(void);
 
+/* Called with tb_lock held.  */
 static inline void *tcg_malloc(int size)
 {
     TCGContext *s = &tcg_ctx;
diff --git a/translate-all.c b/translate-all.c
index 758f654..f6da7bd 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -289,7 +289,9 @@ static int encode_search(TranslationBlock *tb, uint8_t *block)
     return p - block;
 }
 
-/* The cpu state corresponding to 'searched_pc' is restored.  */
+/* The cpu state corresponding to 'searched_pc' is restored.
+ * Called with tb_lock held.
+ */
 static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
                                      uintptr_t searched_pc)
 {
@@ -441,6 +443,7 @@ static void page_init(void)
 }
 
 /* If alloc=1:
+ * Called with tb_lock held for system emulation.
  * Called with mmap_lock held for user-mode emulation.
  */
 static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc)
@@ -805,8 +808,12 @@ bool tcg_enabled(void)
     return tcg_ctx.code_gen_buffer != NULL;
 }
 
-/* Allocate a new translation block. Flush the translation buffer if
-   too many translation blocks or too much generated code. */
+/*
+ * Allocate a new translation block. Flush the translation buffer if
+ * too many translation blocks or too much generated code.
+ *
+ * Called with tb_lock held.
+ */
 static TranslationBlock *tb_alloc(target_ulong pc)
 {
     TranslationBlock *tb;
@@ -821,6 +828,7 @@ static TranslationBlock *tb_alloc(target_ulong pc)
     return tb;
 }
 
+/* Called with tb_lock held.  */
 void tb_free(TranslationBlock *tb)
 {
     /* In practice this is mostly used for single use temporary TB
@@ -945,6 +953,10 @@ do_tb_invalidate_check(struct qht *ht, void *p, uint32_t hash, void *userp)
     }
 }
 
+/* verify that all the pages have correct rights for code
+ *
+ * Called with tb_lock held.
+ */
 static void tb_invalidate_check(target_ulong address)
 {
     address &= TARGET_PAGE_MASK;
@@ -1049,7 +1061,10 @@ static inline void tb_jmp_unlink(TranslationBlock *tb)
     }
 }
 
-/* invalidate one TB */
+/* invalidate one TB
+ *
+ * Called with tb_lock held.
+ */
 void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr)
 {
     CPUState *cpu;
@@ -1483,7 +1498,9 @@ void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len)
     }
     if (!p->code_bitmap &&
         ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD) {
-        /* build code bitmap */
+        /* build code bitmap.  FIXME: writes should be protected by
+         * tb_lock, reads by tb_lock or RCU.
+         */
         build_page_bitmap(p);
     }
     if (p->code_bitmap) {
@@ -1624,6 +1641,7 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
 }
 #endif /* !defined(CONFIG_USER_ONLY) */
 
+/* Called with tb_lock held.  */
 void tb_check_watchpoint(CPUState *cpu)
 {
     TranslationBlock *tb;
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 07/33] linux-user/elfload: ensure mmap_lock() held while setting up
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (5 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 06/33] tcg: comment on which functions have to be called with tb_lock held Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 08/33] translate-all: Add assert_(memory|tb)_lock annotations Alex Bennée
                   ` (26 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Riku Voipio

Future patches will enforce the holding of mmap_lock() when we are
manipulating internal memory structures. Technically it doesn't matter
in the case of elfload as we haven't started executing yet. However it
is easier to grab the lock when required than special case the
translate-all API.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
v4
  - split from assert patch
---
 linux-user/elfload.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 816272a..547053c 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1842,6 +1842,8 @@ static void load_elf_image(const char *image_name, int image_fd,
     info->pt_dynamic_addr = 0;
 #endif
 
+    mmap_lock();
+
     /* Find the maximum size of the image and allocate an appropriate
        amount of memory to handle that.  */
     loaddr = -1, hiaddr = 0;
@@ -2002,6 +2004,8 @@ static void load_elf_image(const char *image_name, int image_fd,
         load_symbols(ehdr, image_fd, load_bias);
     }
 
+    mmap_unlock();
+
     close(image_fd);
     return;
 
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 08/33] translate-all: Add assert_(memory|tb)_lock annotations
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (6 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 07/33] linux-user/elfload: ensure mmap_lock() held while setting up Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 09/33] tcg: protect translation related stuff with tb_lock Alex Bennée
                   ` (25 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

This adds calls to the assert_(memory|tb)_lock for all public APIs which
are documented as needing them held for linux-user mode. The asserts are
NOPs for system-mode although these will be converted when MTTCG is
enabled.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
v4
  - mention tb_locks as well
  - tweak commit message
---
 translate-all.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/translate-all.c b/translate-all.c
index f6da7bd..5460cf2 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -452,6 +452,10 @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc)
     void **lp;
     int i;
 
+    if (alloc) {
+        assert_memory_lock();
+    }
+
     /* Level 1.  Always allocated.  */
     lp = l1_map + ((index >> V_L1_SHIFT) & (V_L1_SIZE - 1));
 
@@ -818,6 +822,8 @@ static TranslationBlock *tb_alloc(target_ulong pc)
 {
     TranslationBlock *tb;
 
+    assert_tb_lock();
+
     if (tcg_ctx.tb_ctx.nb_tbs >= tcg_ctx.code_gen_max_blocks) {
         return NULL;
     }
@@ -831,6 +837,8 @@ static TranslationBlock *tb_alloc(target_ulong pc)
 /* Called with tb_lock held.  */
 void tb_free(TranslationBlock *tb)
 {
+    assert_tb_lock();
+
     /* In practice this is mostly used for single use temporary TB
        Ignore the hard cases and just back up if this TB happens to
        be the last one generated.  */
@@ -1072,6 +1080,8 @@ void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr)
     uint32_t h;
     tb_page_addr_t phys_pc;
 
+    assert_tb_lock();
+
     atomic_set(&tb->invalid, true);
 
     /* remove the TB from the hash list */
@@ -1129,7 +1139,7 @@ static void build_page_bitmap(PageDesc *p)
             tb_end = tb_start + tb->size;
             if (tb_end > TARGET_PAGE_SIZE) {
                 tb_end = TARGET_PAGE_SIZE;
-            }
+             }
         } else {
             tb_start = 0;
             tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
@@ -1152,6 +1162,8 @@ static inline void tb_alloc_page(TranslationBlock *tb,
     bool page_already_protected;
 #endif
 
+    assert_memory_lock();
+
     tb->page_addr[n] = page_addr;
     p = page_find_alloc(page_addr >> TARGET_PAGE_BITS, 1);
     tb->page_next[n] = p->first_tb;
@@ -1208,6 +1220,8 @@ static void tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
 {
     uint32_t h;
 
+    assert_memory_lock();
+
     /* add in the page list */
     tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
     if (phys_page2 != -1) {
@@ -1239,6 +1253,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
 #ifdef CONFIG_PROFILER
     int64_t ti;
 #endif
+    assert_memory_lock();
 
     phys_pc = get_page_addr_code(env, pc);
     if (use_icount && !(cflags & CF_IGNORE_ICOUNT)) {
@@ -1367,6 +1382,8 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
  */
 void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
 {
+    assert_memory_lock();
+
     while (start < end) {
         tb_invalidate_phys_page_range(start, end, 0);
         start &= TARGET_PAGE_MASK;
@@ -1403,6 +1420,8 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
     uint32_t current_flags = 0;
 #endif /* TARGET_HAS_PRECISE_SMC */
 
+    assert_memory_lock();
+
     p = page_find(start >> TARGET_PAGE_BITS);
     if (!p) {
         return;
@@ -2010,6 +2029,7 @@ void page_set_flags(target_ulong start, target_ulong end, int flags)
     assert(end < ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS));
 #endif
     assert(start < end);
+    assert_memory_lock();
 
     start = start & TARGET_PAGE_MASK;
     end = TARGET_PAGE_ALIGN(end);
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 09/33] tcg: protect translation related stuff with tb_lock.
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (7 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 08/33] translate-all: Add assert_(memory|tb)_lock annotations Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 10/33] target-arm/arm-powerctl: wake up sleeping CPUs Alex Bennée
                   ` (24 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite,
	Michael S. Tsirkin, Eduardo Habkost

From: KONRAD Frederic <fred.konrad@greensocs.com>

This protects all translation related work with tb_lock() too ensure
thread safety. This effectively serialises all code generation. In
addition to the code generation we also take the lock for TB
invalidation. This has a knock on effect of meaning tb_lock() is held
for modification of the SoftMMU TLB by non-self threads which will be
used in later patches.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
Message-Id: <1439220437-23957-8-git-send-email-fred.konrad@greensocs.com>
Signed-off-by: Emilio G. Cota <cota@braap.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
[AJB: moved into tree, clean-up history]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
v5 (base-patches, ajb):
  - widen lock on cpu_restore_state to tb_find_pc doesn't race
  - expanded commit message
v4 (base-patches, ajb):
  - protect tb_phys_invalidate with tb_lock
  - drop mention of tb_flush, thread safe flushing in earlier patch series
v3 (base-patches, ajb):
  - more explicit comments on resetting tb_lock
  - more explicit comments about thread safety of user-mode tb_flush
v2 (base-patches, ajb):
  - re-base fixes
v7 (FK, MTTCG):
  - Drop a tb_lock in already locked restore_state_to_opc.
v6 (FK, MTTCG):
  - Drop a tb_lock arround tb_find_fast in cpu-exec.c.
---
 cpu-exec.c         |  6 ++++++
 exec.c             |  6 ++++++
 hw/i386/kvmvapic.c |  4 ++++
 translate-all.c    | 34 ++++++++++++++++++++++++++++------
 4 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/cpu-exec.c b/cpu-exec.c
index 4879c7d..e9b50a6 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -211,15 +211,21 @@ static void cpu_exec_nocache(CPUState *cpu, int max_cycles,
     if (max_cycles > CF_COUNT_MASK)
         max_cycles = CF_COUNT_MASK;
 
+    tb_lock();
     tb = tb_gen_code(cpu, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
                      max_cycles | CF_NOCACHE
                          | (ignore_icount ? CF_IGNORE_ICOUNT : 0));
     tb->orig_tb = orig_tb;
+    tb_unlock();
+
     /* execute the generated code */
     trace_exec_tb_nocache(tb, tb->pc);
     cpu_tb_exec(cpu, tb);
+
+    tb_lock();
     tb_phys_invalidate(tb, -1);
     tb_free(tb);
+    tb_unlock();
 }
 #endif
 
diff --git a/exec.c b/exec.c
index 0096a54..30ae278 100644
--- a/exec.c
+++ b/exec.c
@@ -2023,6 +2023,12 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
                     continue;
                 }
                 cpu->watchpoint_hit = wp;
+
+                /* The tb_lock will be reset when cpu_loop_exit or
+                 * cpu_loop_exit_noexc longjmp back into the cpu_exec
+                 * main loop.
+                 */
+                tb_lock();
                 tb_check_watchpoint(cpu);
                 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
                     cpu->exception_index = EXCP_DEBUG;
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index 74a549b..4448253 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -17,6 +17,7 @@
 #include "sysemu/kvm.h"
 #include "hw/i386/apic_internal.h"
 #include "hw/sysbus.h"
+#include "tcg/tcg.h"
 
 #define VAPIC_IO_PORT           0x7e
 
@@ -449,6 +450,9 @@ static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip)
     resume_all_vcpus();
 
     if (!kvm_enabled()) {
+        /* tb_lock will be reset when cpu_loop_exit_noexc longjmps
+         * back into the cpu_exec loop. */
+        tb_lock();
         tb_gen_code(cs, current_pc, current_cs_base, current_flags, 1);
         cpu_loop_exit_noexc(cs);
     }
diff --git a/translate-all.c b/translate-all.c
index 5460cf2..1237f3c 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -344,7 +344,9 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
 bool cpu_restore_state(CPUState *cpu, uintptr_t retaddr)
 {
     TranslationBlock *tb;
+    bool r = false;
 
+    tb_lock();
     tb = tb_find_pc(retaddr);
     if (tb) {
         cpu_restore_state_from_tb(cpu, tb, retaddr);
@@ -353,9 +355,11 @@ bool cpu_restore_state(CPUState *cpu, uintptr_t retaddr)
             tb_phys_invalidate(tb, -1);
             tb_free(tb);
         }
-        return true;
+        r = true;
     }
-    return false;
+    tb_unlock();
+
+    return r;
 }
 
 void page_size_init(void)
@@ -1435,6 +1439,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
     /* we remove all the TBs in the range [start, end[ */
     /* XXX: see if in some cases it could be faster to invalidate all
        the code */
+    tb_lock();
     tb = p->first_tb;
     while (tb != NULL) {
         n = (uintptr_t)tb & 3;
@@ -1494,6 +1499,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
         cpu_loop_exit_noexc(cpu);
     }
 #endif
+    tb_unlock();
 }
 
 #ifdef CONFIG_SOFTMMU
@@ -1563,6 +1569,8 @@ static bool tb_invalidate_phys_page(tb_page_addr_t addr, uintptr_t pc)
     if (!p) {
         return false;
     }
+
+    tb_lock();
     tb = p->first_tb;
 #ifdef TARGET_HAS_PRECISE_SMC
     if (tb && pc != 0) {
@@ -1600,9 +1608,13 @@ static bool tb_invalidate_phys_page(tb_page_addr_t addr, uintptr_t pc)
            modifying the memory. It will ensure that it cannot modify
            itself */
         tb_gen_code(cpu, current_pc, current_cs_base, current_flags, 1);
+        /* tb_lock will be reset after cpu_loop_exit_noexc longjmps
+         * back into the cpu_exec loop. */
         return true;
     }
 #endif
+    tb_unlock();
+
     return false;
 }
 #endif
@@ -1697,6 +1709,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
     target_ulong pc, cs_base;
     uint32_t flags;
 
+    tb_lock();
     tb = tb_find_pc(retaddr);
     if (!tb) {
         cpu_abort(cpu, "cpu_io_recompile: could not find TB for pc=%p",
@@ -1748,11 +1761,16 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
     /* FIXME: In theory this could raise an exception.  In practice
        we have already translated the block once so it's probably ok.  */
     tb_gen_code(cpu, pc, cs_base, flags, cflags);
+
     /* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
-       the first in the TB) then we end up generating a whole new TB and
-       repeating the fault, which is horribly inefficient.
-       Better would be to execute just this insn uncached, or generate a
-       second new TB.  */
+     * the first in the TB) then we end up generating a whole new TB and
+     *  repeating the fault, which is horribly inefficient.
+     *  Better would be to execute just this insn uncached, or generate a
+     *  second new TB.
+     *
+     * cpu_loop_exit_noexc will longjmp back to cpu_exec where the
+     * tb_lock gets reset.
+     */
     cpu_loop_exit_noexc(cpu);
 }
 
@@ -1816,6 +1834,8 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
     TranslationBlock *tb;
     struct qht_stats hst;
 
+    tb_lock();
+
     target_code_size = 0;
     max_target_code_size = 0;
     cross_page = 0;
@@ -1877,6 +1897,8 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
             tcg_ctx.tb_ctx.tb_phys_invalidate_count);
     cpu_fprintf(f, "TLB flush count     %d\n", tlb_flush_count);
     tcg_dump_info(f, cpu_fprintf);
+
+    tb_unlock();
 }
 
 void dump_opcount_info(FILE *f, fprintf_function cpu_fprintf)
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 10/33] target-arm/arm-powerctl: wake up sleeping CPUs
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (8 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 09/33] tcg: protect translation related stuff with tb_lock Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 11/33] tcg: move tcg_exec_all and helpers above thread fn Alex Bennée
                   ` (23 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Alexander Spyridakis,
	open list:ARM

Testing with Alexander's bare metal syncronisation tests fails in MTTCG
leaving one CPU spinning forever waiting for the second CPU to wake up.
We simply need to kick the vCPU once we have processed the PSCI power on
call.

As the power control API is for system emulation only as is the
qemu_kick_cpu function we also ensure we only build arm-powerctl for
SoftMMU builds.

Tested-by: Alex Bennée <alex.bennee@linaro.org>
CC: Alexander Spyridakis <a.spyridakis@virtualopensystems.com>
Message-Id: <1439220437-23957-20-git-send-email-fred.konrad@greensocs.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

---
v3
  - re-base caught arm_powerctl re-factor
  - include cpu.h header for kick definition
  - fix Makefile.objs to only build for softmmu
---
 target-arm/Makefile.objs  | 2 +-
 target-arm/arm-powerctl.c | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs
index f206411..847fb52 100644
--- a/target-arm/Makefile.objs
+++ b/target-arm/Makefile.objs
@@ -9,4 +9,4 @@ obj-y += neon_helper.o iwmmxt_helper.o
 obj-y += gdbstub.o
 obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o
 obj-y += crypto_helper.o
-obj-y += arm-powerctl.o
+obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
diff --git a/target-arm/arm-powerctl.c b/target-arm/arm-powerctl.c
index 6519d52..fbb7a15 100644
--- a/target-arm/arm-powerctl.c
+++ b/target-arm/arm-powerctl.c
@@ -166,6 +166,8 @@ int arm_set_cpu_on(uint64_t cpuid, uint64_t entry, uint64_t context_id,
     /* Start the new CPU at the requested address */
     cpu_set_pc(target_cpu_state, entry);
 
+    qemu_cpu_kick(target_cpu_state);
+
     /* We are good to go */
     return QEMU_ARM_POWERCTL_RET_SUCCESS;
 }
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 11/33] tcg: move tcg_exec_all and helpers above thread fn
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (9 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 10/33] target-arm/arm-powerctl: wake up sleeping CPUs Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 12/33] tcg: cpus rm tcg_exec_all() Alex Bennée
                   ` (22 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

This is a pure mechanical change in preparation for up-coming
re-factoring. Instead of a forward declaration for tcg_exec_all it and
the associated helper functions are moved in front of the call from
qemu_tcg_cpu_thread_fn.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
v4
  - split from tcg: cpus rm tcg_exec_all() patch
---
 cpus.c | 200 ++++++++++++++++++++++++++++++++---------------------------------
 1 file changed, 99 insertions(+), 101 deletions(-)

diff --git a/cpus.c b/cpus.c
index 5324ba3..77cc24b 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1055,7 +1055,105 @@ static void *qemu_dummy_cpu_thread_fn(void *arg)
 #endif
 }
 
-static void tcg_exec_all(void);
+static int64_t tcg_get_icount_limit(void)
+{
+    int64_t deadline;
+
+    if (replay_mode != REPLAY_MODE_PLAY) {
+        deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
+
+        /* Maintain prior (possibly buggy) behaviour where if no deadline
+         * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than
+         * INT32_MAX nanoseconds ahead, we still use INT32_MAX
+         * nanoseconds.
+         */
+        if ((deadline < 0) || (deadline > INT32_MAX)) {
+            deadline = INT32_MAX;
+        }
+
+        return qemu_icount_round(deadline);
+    } else {
+        return replay_get_instructions();
+    }
+}
+
+static int tcg_cpu_exec(CPUState *cpu)
+{
+    int ret;
+#ifdef CONFIG_PROFILER
+    int64_t ti;
+#endif
+
+#ifdef CONFIG_PROFILER
+    ti = profile_getclock();
+#endif
+    if (use_icount) {
+        int64_t count;
+        int decr;
+        timers_state.qemu_icount -= (cpu->icount_decr.u16.low
+                                    + cpu->icount_extra);
+        cpu->icount_decr.u16.low = 0;
+        cpu->icount_extra = 0;
+        count = tcg_get_icount_limit();
+        timers_state.qemu_icount += count;
+        decr = (count > 0xffff) ? 0xffff : count;
+        count -= decr;
+        cpu->icount_decr.u16.low = decr;
+        cpu->icount_extra = count;
+    }
+    cpu_exec_start(cpu);
+    ret = cpu_exec(cpu);
+    cpu_exec_end(cpu);
+#ifdef CONFIG_PROFILER
+    tcg_time += profile_getclock() - ti;
+#endif
+    if (use_icount) {
+        /* Fold pending instructions back into the
+           instruction counter, and clear the interrupt flag.  */
+        timers_state.qemu_icount -= (cpu->icount_decr.u16.low
+                        + cpu->icount_extra);
+        cpu->icount_decr.u32 = 0;
+        cpu->icount_extra = 0;
+        replay_account_executed_instructions();
+    }
+    return ret;
+}
+
+static void tcg_exec_all(void)
+{
+    int r;
+
+    /* Account partial waits to QEMU_CLOCK_VIRTUAL.  */
+    qemu_account_warp_timer();
+
+    if (next_cpu == NULL) {
+        next_cpu = first_cpu;
+    }
+    for (; next_cpu != NULL && !exit_request; next_cpu = CPU_NEXT(next_cpu)) {
+        CPUState *cpu = next_cpu;
+
+        qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
+                          (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
+
+        if (cpu_can_run(cpu)) {
+            r = tcg_cpu_exec(cpu);
+            if (r == EXCP_DEBUG) {
+                cpu_handle_guest_debug(cpu);
+                break;
+            } else if (r == EXCP_ATOMIC) {
+                cpu_exec_step_atomic(cpu);
+            }
+        } else if (cpu->stop || cpu->stopped) {
+            if (cpu->unplug) {
+                next_cpu = CPU_NEXT(cpu);
+            }
+            break;
+        }
+    }
+
+    /* Pairs with smp_wmb in qemu_cpu_kick.  */
+    atomic_mb_set(&exit_request, 0);
+}
 
 static void *qemu_tcg_cpu_thread_fn(void *arg)
 {
@@ -1412,106 +1510,6 @@ int vm_stop_force_state(RunState state)
     }
 }
 
-static int64_t tcg_get_icount_limit(void)
-{
-    int64_t deadline;
-
-    if (replay_mode != REPLAY_MODE_PLAY) {
-        deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
-
-        /* Maintain prior (possibly buggy) behaviour where if no deadline
-         * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than
-         * INT32_MAX nanoseconds ahead, we still use INT32_MAX
-         * nanoseconds.
-         */
-        if ((deadline < 0) || (deadline > INT32_MAX)) {
-            deadline = INT32_MAX;
-        }
-
-        return qemu_icount_round(deadline);
-    } else {
-        return replay_get_instructions();
-    }
-}
-
-static int tcg_cpu_exec(CPUState *cpu)
-{
-    int ret;
-#ifdef CONFIG_PROFILER
-    int64_t ti;
-#endif
-
-#ifdef CONFIG_PROFILER
-    ti = profile_getclock();
-#endif
-    if (use_icount) {
-        int64_t count;
-        int decr;
-        timers_state.qemu_icount -= (cpu->icount_decr.u16.low
-                                    + cpu->icount_extra);
-        cpu->icount_decr.u16.low = 0;
-        cpu->icount_extra = 0;
-        count = tcg_get_icount_limit();
-        timers_state.qemu_icount += count;
-        decr = (count > 0xffff) ? 0xffff : count;
-        count -= decr;
-        cpu->icount_decr.u16.low = decr;
-        cpu->icount_extra = count;
-    }
-    cpu_exec_start(cpu);
-    ret = cpu_exec(cpu);
-    cpu_exec_end(cpu);
-#ifdef CONFIG_PROFILER
-    tcg_time += profile_getclock() - ti;
-#endif
-    if (use_icount) {
-        /* Fold pending instructions back into the
-           instruction counter, and clear the interrupt flag.  */
-        timers_state.qemu_icount -= (cpu->icount_decr.u16.low
-                        + cpu->icount_extra);
-        cpu->icount_decr.u32 = 0;
-        cpu->icount_extra = 0;
-        replay_account_executed_instructions();
-    }
-    return ret;
-}
-
-static void tcg_exec_all(void)
-{
-    int r;
-
-    /* Account partial waits to QEMU_CLOCK_VIRTUAL.  */
-    qemu_account_warp_timer();
-
-    if (next_cpu == NULL) {
-        next_cpu = first_cpu;
-    }
-    for (; next_cpu != NULL && !exit_request; next_cpu = CPU_NEXT(next_cpu)) {
-        CPUState *cpu = next_cpu;
-
-        qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
-                          (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
-
-        if (cpu_can_run(cpu)) {
-            r = tcg_cpu_exec(cpu);
-            if (r == EXCP_DEBUG) {
-                cpu_handle_guest_debug(cpu);
-                break;
-            } else if (r == EXCP_ATOMIC) {
-                cpu_exec_step_atomic(cpu);
-            }
-        } else if (cpu->stop || cpu->stopped) {
-            if (cpu->unplug) {
-                next_cpu = CPU_NEXT(cpu);
-            }
-            break;
-        }
-    }
-
-    /* Pairs with smp_wmb in qemu_cpu_kick.  */
-    atomic_mb_set(&exit_request, 0);
-}
-
 void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
 {
     /* XXX: implement xxx_cpu_list for targets that still miss it */
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 12/33] tcg: cpus rm tcg_exec_all()
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (10 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 11/33] tcg: move tcg_exec_all and helpers above thread fn Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 13/33] tcg: add options for enabling MTTCG Alex Bennée
                   ` (21 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

In preparation for multi-threaded TCG we remove tcg_exec_all and move
all the CPU cycling into the main thread function. When MTTCG is enabled
we shall use a separate thread function which only handles one vCPU.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Sergey Fedorov <sergey.fedorov@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>

---
v2
  - update timer calls to new API on rebase
v3
  - move tcg_cpu_exec above thread function, drop static fwd declaration
v4
  - split mechanical moves into earlier patch
  - moved unplug logic info function, don't break smp boot
---
 cpus.c | 87 +++++++++++++++++++++++++++++++++---------------------------------
 1 file changed, 43 insertions(+), 44 deletions(-)

diff --git a/cpus.c b/cpus.c
index 77cc24b..cc49902 100644
--- a/cpus.c
+++ b/cpus.c
@@ -69,7 +69,6 @@
 
 #endif /* CONFIG_LINUX */
 
-static CPUState *next_cpu;
 int64_t max_delay;
 int64_t max_advance;
 
@@ -1119,46 +1118,26 @@ static int tcg_cpu_exec(CPUState *cpu)
     return ret;
 }
 
-static void tcg_exec_all(void)
+/* Destroy any remaining vCPUs which have been unplugged and have
+ * finished running
+ */
+static void deal_with_unplugged_cpus(void)
 {
-    int r;
-
-    /* Account partial waits to QEMU_CLOCK_VIRTUAL.  */
-    qemu_account_warp_timer();
-
-    if (next_cpu == NULL) {
-        next_cpu = first_cpu;
-    }
-    for (; next_cpu != NULL && !exit_request; next_cpu = CPU_NEXT(next_cpu)) {
-        CPUState *cpu = next_cpu;
-
-        qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
-                          (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
+    CPUState *cpu;
 
-        if (cpu_can_run(cpu)) {
-            r = tcg_cpu_exec(cpu);
-            if (r == EXCP_DEBUG) {
-                cpu_handle_guest_debug(cpu);
-                break;
-            } else if (r == EXCP_ATOMIC) {
-                cpu_exec_step_atomic(cpu);
-            }
-        } else if (cpu->stop || cpu->stopped) {
-            if (cpu->unplug) {
-                next_cpu = CPU_NEXT(cpu);
-            }
+    CPU_FOREACH(cpu) {
+        if (cpu->unplug && !cpu_can_run(cpu)) {
+            qemu_tcg_destroy_vcpu(cpu);
+            cpu->created = false;
+            qemu_cond_signal(&qemu_cpu_cond);
             break;
         }
     }
-
-    /* Pairs with smp_wmb in qemu_cpu_kick.  */
-    atomic_mb_set(&exit_request, 0);
 }
 
 static void *qemu_tcg_cpu_thread_fn(void *arg)
 {
     CPUState *cpu = arg;
-    CPUState *remove_cpu = NULL;
 
     rcu_register_thread();
 
@@ -1185,8 +1164,39 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
     /* process any pending work */
     atomic_mb_set(&exit_request, 1);
 
+    cpu = first_cpu;
+
     while (1) {
-        tcg_exec_all();
+        /* Account partial waits to QEMU_CLOCK_VIRTUAL.  */
+        qemu_account_warp_timer();
+
+        if (!cpu) {
+            cpu = first_cpu;
+        }
+
+        for (; cpu != NULL && !exit_request; cpu = CPU_NEXT(cpu)) {
+
+            qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
+                              (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
+
+            if (cpu_can_run(cpu)) {
+                int r;
+                r = tcg_cpu_exec(cpu);
+                if (r == EXCP_DEBUG) {
+                    cpu_handle_guest_debug(cpu);
+                    break;
+                }
+            } else if (cpu->stop || cpu->stopped) {
+                if (cpu->unplug) {
+                    cpu = CPU_NEXT(cpu);
+                }
+                break;
+            }
+
+        } /* for cpu.. */
+
+        /* Pairs with smp_wmb in qemu_cpu_kick.  */
+        atomic_mb_set(&exit_request, 0);
 
         if (use_icount) {
             int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
@@ -1196,18 +1206,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
             }
         }
         qemu_tcg_wait_io_event(QTAILQ_FIRST(&cpus));
-        CPU_FOREACH(cpu) {
-            if (cpu->unplug && !cpu_can_run(cpu)) {
-                remove_cpu = cpu;
-                break;
-            }
-        }
-        if (remove_cpu) {
-            qemu_tcg_destroy_vcpu(remove_cpu);
-            cpu->created = false;
-            qemu_cond_signal(&qemu_cpu_cond);
-            remove_cpu = NULL;
-        }
+        deal_with_unplugged_cpus();
     }
 
     return NULL;
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 13/33] tcg: add options for enabling MTTCG
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (11 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 12/33] tcg: cpus rm tcg_exec_all() Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 14/33] tcg: add kick timer for single-threaded vCPU emulation Alex Bennée
                   ` (20 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

From: KONRAD Frederic <fred.konrad@greensocs.com>

We know there will be cases where MTTCG won't work until additional work
is done in the front/back ends to support. It will however be useful to
be able to turn it on.

As a result MTTCG will default to off unless the combination is
supported. However the user can turn it on for the sake of testing.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
[AJB: move to -accel tcg,thread=multi|single, defaults]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
v1:
  - merge with add mttcg option.
  - update commit message
v2:
  - machine_init->opts_init
v3:
  - moved from -tcg to -accel tcg,thread=single|multi
  - fix checkpatch warnings
v4:
  - make mttcg_enabled extern, qemu_tcg_mttcg_enabled() now just macro
  - qemu_tcg_configure now propagates Error instead of exiting
  - better error checking of thread=foo
  - use CONFIG flags for default_mttcg_enabled()
  - disable mttcg with icount, error if both forced on
---
 cpus.c                | 43 +++++++++++++++++++++++++++++++++++++++++++
 include/qom/cpu.h     |  9 +++++++++
 include/sysemu/cpus.h |  2 ++
 qemu-options.hx       | 20 ++++++++++++++++++++
 vl.c                  | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 122 insertions(+), 1 deletion(-)

diff --git a/cpus.c b/cpus.c
index cc49902..aedec7c 100644
--- a/cpus.c
+++ b/cpus.c
@@ -25,6 +25,7 @@
 /* Needed early for CONFIG_BSD etc. */
 #include "qemu/osdep.h"
 #include "qemu-common.h"
+#include "qemu/config-file.h"
 #include "cpu.h"
 #include "monitor/monitor.h"
 #include "qapi/qmp/qerror.h"
@@ -148,6 +149,48 @@ typedef struct TimersState {
 } TimersState;
 
 static TimersState timers_state;
+bool mttcg_enabled;
+
+/*
+ * We default to false if we know other options have been enabled
+ * which are currently incompatible with MTTCG. Otherwise when each
+ * guest (target) and host has been updated to support:
+ *   - atomic instructions
+ *   - memory ordering
+ * they can set the appropriate CONFIG flags in ${target}-softmmu.mak
+ * and generated config-host.mak fragments.
+ */
+static bool default_mttcg_enabled(void)
+{
+    QemuOpts *icount_opts = qemu_find_opts_singleton("icount");
+    const char *rr = qemu_opt_get(icount_opts, "rr");
+
+    if (rr) {
+        return false;
+    } else {
+#if defined(CONFIG_MTTCG_TARGET) && defined(CONFIG_MTTCG_HOST)
+        return true;
+#else
+        return false;
+#endif
+    }
+}
+
+void qemu_tcg_configure(QemuOpts *opts, Error **errp)
+{
+    const char *t = qemu_opt_get(opts, "thread");
+    if (t) {
+        if (strcmp(t, "multi") == 0) {
+            mttcg_enabled = true;
+        } else if (strcmp(t, "single") == 0) {
+            mttcg_enabled = false;
+        } else {
+            error_setg(errp, "Invalid 'thread' setting %s", t);
+        }
+    } else {
+        mttcg_enabled = default_mttcg_enabled();
+    }
+}
 
 int64_t cpu_get_icount_raw(void)
 {
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 44571da..d268e20 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -389,6 +389,15 @@ extern struct CPUTailQ cpus;
 extern __thread CPUState *current_cpu;
 
 /**
+ * qemu_tcg_mttcg_enabled:
+ * Check whether we are running MultiThread TCG or not.
+ *
+ * Returns: %true if we are in MTTCG mode %false otherwise.
+ */
+extern bool mttcg_enabled;
+#define qemu_tcg_mttcg_enabled() (mttcg_enabled)
+
+/**
  * cpu_paging_enabled:
  * @cpu: The CPU whose state is to be inspected.
  *
diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h
index 3728a1e..a73b5d4 100644
--- a/include/sysemu/cpus.h
+++ b/include/sysemu/cpus.h
@@ -36,4 +36,6 @@ extern int smp_threads;
 
 void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg);
 
+void qemu_tcg_configure(QemuOpts *opts, Error **errp);
+
 #endif
diff --git a/qemu-options.hx b/qemu-options.hx
index b1fbdb0..0f1b313 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -96,6 +96,26 @@ STEXI
 Select CPU model (@code{-cpu help} for list and additional feature selection)
 ETEXI
 
+DEF("accel", HAS_ARG, QEMU_OPTION_accel,
+    "-accel [accel=]accelerator[,thread=single|multi]\n"
+    "               select accelerator ('-accel help for list')\n"
+    "               thread=single|multi (enable multi-threaded TCG)", QEMU_ARCH_ALL)
+STEXI
+@item -accel @var{name}[,prop=@var{value}[,...]]
+@findex -accel
+This is used to enable an accelerator. Depending on the target architecture,
+kvm, xen, or tcg can be available. By default, tcg is used. If there is more
+than one accelerator specified, the next one is used if the previous one fails
+to initialize.
+@table @option
+@item thread=single|multi
+Controls number of TCG threads. When the TCG is multi-threaded there will be one
+thread per vCPU therefor taking advantage of additional host cores. The default
+is to enable multi-threading where both the back-end and front-ends support it and
+no incompatible TCG features have been enabled (e.g. icount/replay).
+@end table
+ETEXI
+
 DEF("smp", HAS_ARG, QEMU_OPTION_smp,
     "-smp [cpus=]n[,maxcpus=cpus][,cores=cores][,threads=threads][,sockets=sockets]\n"
     "                set the number of CPUs to 'n' [default=1]\n"
diff --git a/vl.c b/vl.c
index 2569ec2..3a483bf 100644
--- a/vl.c
+++ b/vl.c
@@ -295,6 +295,26 @@ static QemuOptsList qemu_machine_opts = {
     },
 };
 
+static QemuOptsList qemu_accel_opts = {
+    .name = "accel",
+    .implied_opt_name = "accel",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_accel_opts.head),
+    .merge_lists = true,
+    .desc = {
+        {
+            .name = "accel",
+            .type = QEMU_OPT_STRING,
+            .help = "Select the type of accelerator",
+        },
+        {
+            .name = "thread",
+            .type = QEMU_OPT_STRING,
+            .help = "Enable/disable multi-threaded TCG",
+        },
+        { /* end of list */ }
+    },
+};
+
 static QemuOptsList qemu_boot_opts = {
     .name = "boot-opts",
     .implied_opt_name = "order",
@@ -2997,7 +3017,8 @@ int main(int argc, char **argv, char **envp)
     const char *boot_once = NULL;
     DisplayState *ds;
     int cyls, heads, secs, translation;
-    QemuOpts *hda_opts = NULL, *opts, *machine_opts, *icount_opts = NULL;
+    QemuOpts *opts, *machine_opts;
+    QemuOpts *hda_opts = NULL, *icount_opts = NULL, *accel_opts = NULL;
     QemuOptsList *olist;
     int optind;
     const char *optarg;
@@ -3052,6 +3073,7 @@ int main(int argc, char **argv, char **envp)
     qemu_add_opts(&qemu_trace_opts);
     qemu_add_opts(&qemu_option_rom_opts);
     qemu_add_opts(&qemu_machine_opts);
+    qemu_add_opts(&qemu_accel_opts);
     qemu_add_opts(&qemu_mem_opts);
     qemu_add_opts(&qemu_smp_opts);
     qemu_add_opts(&qemu_boot_opts);
@@ -3745,6 +3767,26 @@ int main(int argc, char **argv, char **envp)
                 qdev_prop_register_global(&kvm_pit_lost_tick_policy);
                 break;
             }
+            case QEMU_OPTION_accel:
+                accel_opts = qemu_opts_parse_noisily(qemu_find_opts("accel"),
+                                                     optarg, true);
+                optarg = qemu_opt_get(accel_opts, "accel");
+
+                olist = qemu_find_opts("machine");
+                if (strcmp("kvm", optarg) == 0) {
+                    qemu_opts_parse_noisily(olist, "accel=kvm", false);
+                } else if (strcmp("xen", optarg) == 0) {
+                    qemu_opts_parse_noisily(olist, "accel=xen", false);
+                } else if (strcmp("tcg", optarg) == 0) {
+                    qemu_opts_parse_noisily(olist, "accel=tcg", false);
+                } else {
+                    if (!is_help_option(optarg)) {
+                        error_printf("Unknown accelerator: %s", optarg);
+                    }
+                    error_printf("Supported accelerators: kvm, xen, tcg\n");
+                    exit(1);
+                }
+                break;
             case QEMU_OPTION_usb:
                 olist = qemu_find_opts("machine");
                 qemu_opts_parse_noisily(olist, "usb=on", false);
@@ -4050,6 +4092,8 @@ int main(int argc, char **argv, char **envp)
 
     replay_configure(icount_opts);
 
+    qemu_tcg_configure(accel_opts, &error_fatal);
+
     machine_class = select_machine();
 
     set_memory_options(&ram_slots, &maxram_size, machine_class);
@@ -4404,6 +4448,9 @@ int main(int argc, char **argv, char **envp)
         if (kvm_enabled() || xen_enabled()) {
             error_report("-icount is not allowed with kvm or xen");
             exit(1);
+        } else if (qemu_tcg_mttcg_enabled()) {
+            error_report("-icount does not currently work with MTTCG");
+            exit(1);
         }
         configure_icount(icount_opts, &error_abort);
         qemu_opts_del(icount_opts);
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 14/33] tcg: add kick timer for single-threaded vCPU emulation
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (12 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 13/33] tcg: add options for enabling MTTCG Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:30   ` KONRAD Frederic
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 15/33] tcg: rename tcg_current_cpu to tcg_current_rr_cpu Alex Bennée
                   ` (19 subsequent siblings)
  33 siblings, 1 reply; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

Currently we rely on the side effect of the main loop grabbing the
iothread_mutex to give any long running basic block chains a kick to
ensure the next vCPU is scheduled. As this code is being re-factored and
rationalised we now do it explicitly here.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v2
  - re-base fixes
  - get_ticks_per_sec() -> NANOSECONDS_PER_SEC
v3
  - add define for TCG_KICK_FREQ
  - fix checkpatch warning
v4
  - wrap next calc in inline qemu_tcg_next_kick() instead of macro
v5
  - move all kick code into own section
  - use global for timer
  - add helper functions to start/stop timer
  - stop timer when all cores paused
---
 cpus.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/cpus.c b/cpus.c
index aedec7c..ad4ab68 100644
--- a/cpus.c
+++ b/cpus.c
@@ -735,6 +735,52 @@ void configure_icount(QemuOpts *opts, Error **errp)
 }
 
 /***********************************************************/
+/* TCG vCPU kick timer
+ *
+ * The kick timer is responsible for moving single threaded vCPU
+ * emulation on to the next vCPU. If more than one vCPU is running a
+ * timer event with force a cpu->exit so the next vCPU can get
+ * scheduled.
+ *
+ * The timer is removed if all vCPUs are idle and restarted again once
+ * idleness is complete.
+ */
+
+static QEMUTimer *tcg_kick_vcpu_timer;
+
+static void qemu_cpu_kick_no_halt(void);
+
+#define TCG_KICK_PERIOD (NANOSECONDS_PER_SECOND / 10)
+
+static inline int64_t qemu_tcg_next_kick(void)
+{
+    return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + TCG_KICK_PERIOD;
+}
+
+static void kick_tcg_thread(void *opaque)
+{
+    timer_mod(tcg_kick_vcpu_timer, qemu_tcg_next_kick());
+    qemu_cpu_kick_no_halt();
+}
+
+static void start_tcg_kick_timer(void)
+{
+    if (!tcg_kick_vcpu_timer && CPU_NEXT(first_cpu)) {
+        tcg_kick_vcpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,  kick_tcg_thread, NULL);
+        timer_mod(tcg_kick_vcpu_timer, qemu_tcg_next_kick());
+    }
+}
+
+static void stop_tcg_kick_timer(void)
+{
+    if (tcg_kick_vcpu_timer) {
+        timer_del(tcg_kick_vcpu_timer);
+        tcg_kick_vcpu_timer = NULL;
+    }
+}
+
+
+/***********************************************************/
 void hw_error(const char *fmt, ...)
 {
     va_list ap;
@@ -988,9 +1034,12 @@ static void qemu_wait_io_event_common(CPUState *cpu)
 static void qemu_tcg_wait_io_event(CPUState *cpu)
 {
     while (all_cpu_threads_idle()) {
+        stop_tcg_kick_timer();
         qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex);
     }
 
+    start_tcg_kick_timer();
+
     while (iothread_requesting_mutex) {
         qemu_cond_wait(&qemu_io_proceeded_cond, &qemu_global_mutex);
     }
@@ -1178,6 +1227,15 @@ static void deal_with_unplugged_cpus(void)
     }
 }
 
+/* Single-threaded TCG
+ *
+ * In the single-threaded case each vCPU is simulated in turn. If
+ * there is more than a single vCPU we create a simple timer to kick
+ * the vCPU and ensure we don't get stuck in a tight loop in one vCPU.
+ * This is done explicitly rather than relying on side-effects
+ * elsewhere.
+ */
+
 static void *qemu_tcg_cpu_thread_fn(void *arg)
 {
     CPUState *cpu = arg;
@@ -1204,6 +1262,8 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
         }
     }
 
+    start_tcg_kick_timer();
+
     /* process any pending work */
     atomic_mb_set(&exit_request, 1);
 
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 15/33] tcg: rename tcg_current_cpu to tcg_current_rr_cpu
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (13 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 14/33] tcg: add kick timer for single-threaded vCPU emulation Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 16/33] tcg: drop global lock during TCG code execution Alex Bennée
                   ` (18 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

..and make the definition local to cpus. In preparation for MTTCG the
concept of a global tcg_current_cpu will no longer make sense. However
we still need to keep track of it in the single-threaded case to be able
to exit quickly when required.

qemu_cpu_kick_no_halt() moves and becomes qemu_cpu_kick_rr_cpu() to
emphasise its use-case. qemu_cpu_kick now kicks the relevant cpu as
well as qemu_kick_rr_cpu() which will become a no-op in MTTCG.

For the time being the setting of the global exit_request remains.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
v4:
  - keep global exit_request setting for now
  - fix merge conflicts
v5:
  - merge conflicts with kick changes
---
 cpu-exec-common.c       |  1 -
 cpu-exec.c              |  3 ---
 cpus.c                  | 41 ++++++++++++++++++++++-------------------
 include/exec/exec-all.h |  1 -
 4 files changed, 22 insertions(+), 24 deletions(-)

diff --git a/cpu-exec-common.c b/cpu-exec-common.c
index 767d9c6..e2bc053 100644
--- a/cpu-exec-common.c
+++ b/cpu-exec-common.c
@@ -24,7 +24,6 @@
 #include "exec/memory-internal.h"
 
 bool exit_request;
-CPUState *tcg_current_cpu;
 
 /* exit the current TB, but without causing any exception to be raised */
 void cpu_loop_exit_noexc(CPUState *cpu)
diff --git a/cpu-exec.c b/cpu-exec.c
index e9b50a6..6ea5507 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -609,7 +609,6 @@ int cpu_exec(CPUState *cpu)
         return EXCP_HALTED;
     }
 
-    atomic_mb_set(&tcg_current_cpu, cpu);
     rcu_read_lock();
 
     if (unlikely(atomic_mb_read(&exit_request))) {
@@ -668,7 +667,5 @@ int cpu_exec(CPUState *cpu)
     /* fail safe : never use current_cpu outside cpu_exec() */
     current_cpu = NULL;
 
-    /* Does not need atomic_mb_set because a spurious wakeup is okay.  */
-    atomic_set(&tcg_current_cpu, NULL);
     return ret;
 }
diff --git a/cpus.c b/cpus.c
index ad4ab68..c6ff79f 100644
--- a/cpus.c
+++ b/cpus.c
@@ -747,8 +747,7 @@ void configure_icount(QemuOpts *opts, Error **errp)
  */
 
 static QEMUTimer *tcg_kick_vcpu_timer;
-
-static void qemu_cpu_kick_no_halt(void);
+static CPUState *tcg_current_rr_cpu;
 
 #define TCG_KICK_PERIOD (NANOSECONDS_PER_SECOND / 10)
 
@@ -757,10 +756,23 @@ static inline int64_t qemu_tcg_next_kick(void)
     return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + TCG_KICK_PERIOD;
 }
 
+/* Kick the currently round-robin scheduled vCPU */
+static void qemu_cpu_kick_rr_cpu(void)
+{
+    CPUState *cpu;
+    atomic_mb_set(&exit_request, 1);
+    do {
+        cpu = atomic_mb_read(&tcg_current_rr_cpu);
+        if (cpu) {
+            cpu_exit(cpu);
+        }
+    } while (cpu != atomic_mb_read(&tcg_current_rr_cpu));
+}
+
 static void kick_tcg_thread(void *opaque)
 {
     timer_mod(tcg_kick_vcpu_timer, qemu_tcg_next_kick());
-    qemu_cpu_kick_no_halt();
+    qemu_cpu_kick_rr_cpu();
 }
 
 static void start_tcg_kick_timer(void)
@@ -779,7 +791,6 @@ static void stop_tcg_kick_timer(void)
     }
 }
 
-
 /***********************************************************/
 void hw_error(const char *fmt, ...)
 {
@@ -1278,6 +1289,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
         }
 
         for (; cpu != NULL && !exit_request; cpu = CPU_NEXT(cpu)) {
+            atomic_mb_set(&tcg_current_rr_cpu, cpu);
 
             qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
                               (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
@@ -1297,6 +1309,8 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
             }
 
         } /* for cpu.. */
+        /* Does not need atomic_mb_set because a spurious wakeup is okay.  */
+        atomic_set(&tcg_current_rr_cpu, NULL);
 
         /* Pairs with smp_wmb in qemu_cpu_kick.  */
         atomic_mb_set(&exit_request, 0);
@@ -1334,24 +1348,13 @@ static void qemu_cpu_kick_thread(CPUState *cpu)
 #endif
 }
 
-static void qemu_cpu_kick_no_halt(void)
-{
-    CPUState *cpu;
-    /* Ensure whatever caused the exit has reached the CPU threads before
-     * writing exit_request.
-     */
-    atomic_mb_set(&exit_request, 1);
-    cpu = atomic_mb_read(&tcg_current_cpu);
-    if (cpu) {
-        cpu_exit(cpu);
-    }
-}
-
 void qemu_cpu_kick(CPUState *cpu)
 {
     qemu_cond_broadcast(cpu->halt_cond);
     if (tcg_enabled()) {
-        qemu_cpu_kick_no_halt();
+        cpu_exit(cpu);
+        /* Also ensure current RR cpu is kicked */
+        qemu_cpu_kick_rr_cpu();
     } else {
         qemu_cpu_kick_thread(cpu);
     }
@@ -1392,7 +1395,7 @@ void qemu_mutex_lock_iothread(void)
         atomic_dec(&iothread_requesting_mutex);
     } else {
         if (qemu_mutex_trylock(&qemu_global_mutex)) {
-            qemu_cpu_kick_no_halt();
+            qemu_cpu_kick_rr_cpu();
             qemu_mutex_lock(&qemu_global_mutex);
         }
         atomic_dec(&iothread_requesting_mutex);
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 189deb8..b8b9989 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -407,7 +407,6 @@ bool memory_region_is_unassigned(MemoryRegion *mr);
 extern int singlestep;
 
 /* cpu-exec.c, accessed with atomic_mb_read/atomic_mb_set */
-extern CPUState *tcg_current_cpu;
 extern bool exit_request;
 
 #endif
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 16/33] tcg: drop global lock during TCG code execution
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (14 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 15/33] tcg: rename tcg_current_cpu to tcg_current_rr_cpu Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 17/33] cpus: re-factor out handle_icount_deadline Alex Bennée
                   ` (17 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite,
	Michael S. Tsirkin, Eduardo Habkost, David Gibson,
	Alexander Graf, open list:sPAPR

From: Jan Kiszka <jan.kiszka@siemens.com>

This finally allows TCG to benefit from the iothread introduction: Drop
the global mutex while running pure TCG CPU code. Reacquire the lock
when entering MMIO or PIO emulation, or when leaving the TCG loop.

We have to revert a few optimization for the current TCG threading
model, namely kicking the TCG thread in qemu_mutex_lock_iothread and not
kicking it in qemu_cpu_kick. We also need to disable RAM block
reordering until we have a more efficient locking mechanism at hand.

Still, a Linux x86 UP guest and my Musicpal ARM model boot fine here.
These numbers demonstrate where we gain something:

20338 jan       20   0  331m  75m 6904 R   99  0.9   0:50.95 qemu-system-arm
20337 jan       20   0  331m  75m 6904 S   20  0.9   0:26.50 qemu-system-arm

The guest CPU was fully loaded, but the iothread could still run mostly
independent on a second core. Without the patch we don't get beyond

32206 jan       20   0  330m  73m 7036 R   82  0.9   1:06.00 qemu-system-arm
32204 jan       20   0  330m  73m 7036 S   21  0.9   0:17.03 qemu-system-arm

We don't benefit significantly, though, when the guest is not fully
loading a host CPU.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Message-Id: <1439220437-23957-10-git-send-email-fred.konrad@greensocs.com>
[FK: Rebase, fix qemu_devices_reset deadlock, rm address_space_* mutex]
Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
[EGC: fixed iothread lock for cpu-exec IRQ handling]
Signed-off-by: Emilio G. Cota <cota@braap.org>
[AJB: -smp single-threaded fix, rm old info from commit msg, review updates]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v5 (ajb, base patches):
 - added an assert to BQL unlock/lock functions instead of hanging
 - ensure all cpu->interrupt_requests *modifications* protected by BQL
 - add a re-read on cpu->interrupt_request for correctness
 - BQL fixes for:
   - assert BQL held for PPC hypercalls (emulate_spar_hypercall)
   - SCLP service calls on s390x
 - merge conflict with kick timer patch
v4 (ajb, base patches):
 - protect cpu->interrupt updates with BQL
 - fix wording io_mem_notdirty calls
 - s/we/with/
v3 (ajb, base-patches):
  - stale iothread_unlocks removed (cpu_exit/resume_from_signal deals
  with it in the longjmp).
  - fix re-base conflicts
v2 (ajb):
  - merge with tcg: grab iothread lock in cpu-exec interrupt handling
  - use existing fns for tracking lock state
  - lock iothread for mem_region
    - add assert on mem region modification
    - ensure smm_helper holds iothread
  - Add JK s-o-b
  - Fix-up FK s-o-b annotation
v1 (ajb, base-patches):
  - SMP failure now fixed by previous commit

Changes from Fred Konrad (mttcg-v7 via paolo):
  * Rebase on the current HEAD.
  * Fixes a deadlock in qemu_devices_reset().
  * Remove the mutex in address_space_*
---
 cpu-exec.c                 | 20 ++++++++++++++++++--
 cpus.c                     | 28 +++++-----------------------
 cputlb.c                   | 21 ++++++++++++++++++++-
 exec.c                     | 12 +++++++++---
 hw/core/irq.c              |  1 +
 hw/i386/kvmvapic.c         |  4 ++--
 hw/ppc/spapr.c             |  3 +++
 include/qom/cpu.h          |  1 +
 memory.c                   |  2 ++
 qom/cpu.c                  | 10 ++++++++++
 target-i386/smm_helper.c   |  7 +++++++
 target-s390x/misc_helper.c |  5 ++++-
 translate-all.c            | 11 +++++++++--
 translate-common.c         | 21 +++++++++++----------
 14 files changed, 102 insertions(+), 44 deletions(-)

diff --git a/cpu-exec.c b/cpu-exec.c
index 6ea5507..3ca44bd 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -29,6 +29,7 @@
 #include "qemu/rcu.h"
 #include "exec/tb-hash.h"
 #include "exec/log.h"
+#include "qemu/main-loop.h"
 #if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
 #include "hw/i386/apic.h"
 #endif
@@ -388,8 +389,10 @@ static inline bool cpu_handle_halt(CPUState *cpu)
         if ((cpu->interrupt_request & CPU_INTERRUPT_POLL)
             && replay_interrupt()) {
             X86CPU *x86_cpu = X86_CPU(cpu);
+            qemu_mutex_lock_iothread();
             apic_poll_irq(x86_cpu->apic_state);
             cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL);
+            qemu_mutex_unlock_iothread();
         }
 #endif
         if (!cpu_has_work(cpu)) {
@@ -443,7 +446,9 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
 #else
             if (replay_exception()) {
                 CPUClass *cc = CPU_GET_CLASS(cpu);
+                qemu_mutex_lock_iothread();
                 cc->do_interrupt(cpu);
+                qemu_mutex_unlock_iothread();
                 cpu->exception_index = -1;
             } else if (!replay_has_interrupt()) {
                 /* give a chance to iothread in replay mode */
@@ -469,9 +474,11 @@ static inline void cpu_handle_interrupt(CPUState *cpu,
                                         TranslationBlock **last_tb)
 {
     CPUClass *cc = CPU_GET_CLASS(cpu);
-    int interrupt_request = cpu->interrupt_request;
 
-    if (unlikely(interrupt_request)) {
+    if (unlikely(atomic_read(&cpu->interrupt_request))) {
+        int interrupt_request;
+        qemu_mutex_lock_iothread();
+        interrupt_request = cpu->interrupt_request;
         if (unlikely(cpu->singlestep_enabled & SSTEP_NOIRQ)) {
             /* Mask out external interrupts for this step. */
             interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
@@ -526,7 +533,12 @@ static inline void cpu_handle_interrupt(CPUState *cpu,
                the program flow was changed */
             *last_tb = NULL;
         }
+
+        /* If we exit via cpu_loop_exit/longjmp it is reset in cpu_exec */
+        qemu_mutex_unlock_iothread();
     }
+
+
     if (unlikely(atomic_read(&cpu->exit_request) || replay_has_interrupt())) {
         atomic_set(&cpu->exit_request, 0);
         cpu->exception_index = EXCP_INTERRUPT;
@@ -656,8 +668,12 @@ int cpu_exec(CPUState *cpu)
             g_assert(cpu == current_cpu);
             g_assert(cc == CPU_GET_CLASS(cpu));
 #endif /* buggy compiler */
+
             cpu->can_do_io = 1;
             tb_lock_reset();
+            if (qemu_mutex_iothread_locked()) {
+                qemu_mutex_unlock_iothread();
+            }
         }
     } /* for(;;) */
 
diff --git a/cpus.c b/cpus.c
index c6ff79f..aca2a2e 100644
--- a/cpus.c
+++ b/cpus.c
@@ -993,8 +993,6 @@ static void qemu_kvm_init_cpu_signals(CPUState *cpu)
 #endif /* _WIN32 */
 
 static QemuMutex qemu_global_mutex;
-static QemuCond qemu_io_proceeded_cond;
-static unsigned iothread_requesting_mutex;
 
 static QemuThread io_thread;
 
@@ -1008,7 +1006,6 @@ void qemu_init_cpu_loop(void)
     qemu_init_sigbus();
     qemu_cond_init(&qemu_cpu_cond);
     qemu_cond_init(&qemu_pause_cond);
-    qemu_cond_init(&qemu_io_proceeded_cond);
     qemu_mutex_init(&qemu_global_mutex);
 
     qemu_thread_get_self(&io_thread);
@@ -1051,10 +1048,6 @@ static void qemu_tcg_wait_io_event(CPUState *cpu)
 
     start_tcg_kick_timer();
 
-    while (iothread_requesting_mutex) {
-        qemu_cond_wait(&qemu_io_proceeded_cond, &qemu_global_mutex);
-    }
-
     CPU_FOREACH(cpu) {
         qemu_wait_io_event_common(cpu);
     }
@@ -1203,9 +1196,11 @@ static int tcg_cpu_exec(CPUState *cpu)
         cpu->icount_decr.u16.low = decr;
         cpu->icount_extra = count;
     }
+    qemu_mutex_unlock_iothread();
     cpu_exec_start(cpu);
     ret = cpu_exec(cpu);
     cpu_exec_end(cpu);
+    qemu_mutex_lock_iothread();
 #ifdef CONFIG_PROFILER
     tcg_time += profile_getclock() - ti;
 #endif
@@ -1385,27 +1380,14 @@ bool qemu_mutex_iothread_locked(void)
 
 void qemu_mutex_lock_iothread(void)
 {
-    atomic_inc(&iothread_requesting_mutex);
-    /* In the simple case there is no need to bump the VCPU thread out of
-     * TCG code execution.
-     */
-    if (!tcg_enabled() || qemu_in_vcpu_thread() ||
-        !first_cpu || !first_cpu->created) {
-        qemu_mutex_lock(&qemu_global_mutex);
-        atomic_dec(&iothread_requesting_mutex);
-    } else {
-        if (qemu_mutex_trylock(&qemu_global_mutex)) {
-            qemu_cpu_kick_rr_cpu();
-            qemu_mutex_lock(&qemu_global_mutex);
-        }
-        atomic_dec(&iothread_requesting_mutex);
-        qemu_cond_broadcast(&qemu_io_proceeded_cond);
-    }
+    g_assert(!qemu_mutex_iothread_locked());
+    qemu_mutex_lock(&qemu_global_mutex);
     iothread_locked = true;
 }
 
 void qemu_mutex_unlock_iothread(void)
 {
+    g_assert(qemu_mutex_iothread_locked());
     iothread_locked = false;
     qemu_mutex_unlock(&qemu_global_mutex);
 }
diff --git a/cputlb.c b/cputlb.c
index cc4da4d..986efaa 100644
--- a/cputlb.c
+++ b/cputlb.c
@@ -18,6 +18,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/main-loop.h"
 #include "cpu.h"
 #include "exec/exec-all.h"
 #include "exec/memory.h"
@@ -505,6 +506,7 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
     hwaddr physaddr = iotlbentry->addr;
     MemoryRegion *mr = iotlb_to_region(cpu, physaddr, iotlbentry->attrs);
     uint64_t val;
+    bool locked = false;
 
     physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
     cpu->mem_io_pc = retaddr;
@@ -513,7 +515,16 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
     }
 
     cpu->mem_io_vaddr = addr;
+
+    if (mr->global_locking) {
+        qemu_mutex_lock_iothread();
+        locked = true;
+    }
     memory_region_dispatch_read(mr, physaddr, &val, size, iotlbentry->attrs);
+    if (locked) {
+        qemu_mutex_unlock_iothread();
+    }
+
     return val;
 }
 
@@ -524,15 +535,23 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
     CPUState *cpu = ENV_GET_CPU(env);
     hwaddr physaddr = iotlbentry->addr;
     MemoryRegion *mr = iotlb_to_region(cpu, physaddr, iotlbentry->attrs);
+    bool locked = false;
 
     physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
     if (mr != &io_mem_rom && mr != &io_mem_notdirty && !cpu->can_do_io) {
         cpu_io_recompile(cpu, retaddr);
     }
-
     cpu->mem_io_vaddr = addr;
     cpu->mem_io_pc = retaddr;
+
+    if (mr->global_locking) {
+        qemu_mutex_lock_iothread();
+        locked = true;
+    }
     memory_region_dispatch_write(mr, physaddr, val, size, iotlbentry->attrs);
+    if (locked) {
+        qemu_mutex_unlock_iothread();
+    }
 }
 
 /* Return true if ADDR is present in the victim tlb, and has been copied
diff --git a/exec.c b/exec.c
index 30ae278..8db5545 100644
--- a/exec.c
+++ b/exec.c
@@ -2024,9 +2024,9 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
                 }
                 cpu->watchpoint_hit = wp;
 
-                /* The tb_lock will be reset when cpu_loop_exit or
-                 * cpu_loop_exit_noexc longjmp back into the cpu_exec
-                 * main loop.
+                /* Both tb_lock and iothread_mutex will be reset when
+                 * cpu_loop_exit or cpu_loop_exit_noexc longjmp
+                 * back into the cpu_exec main loop.
                  */
                 tb_lock();
                 tb_check_watchpoint(cpu);
@@ -2262,8 +2262,14 @@ static void io_mem_init(void)
     memory_region_init_io(&io_mem_rom, NULL, &unassigned_mem_ops, NULL, NULL, UINT64_MAX);
     memory_region_init_io(&io_mem_unassigned, NULL, &unassigned_mem_ops, NULL,
                           NULL, UINT64_MAX);
+
+    /* io_mem_notdirty calls tb_invalidate_phys_page_fast,
+     * which can be called without the iothread mutex.
+     */
     memory_region_init_io(&io_mem_notdirty, NULL, &notdirty_mem_ops, NULL,
                           NULL, UINT64_MAX);
+    memory_region_clear_global_locking(&io_mem_notdirty);
+
     memory_region_init_io(&io_mem_watch, NULL, &watch_mem_ops, NULL,
                           NULL, UINT64_MAX);
 }
diff --git a/hw/core/irq.c b/hw/core/irq.c
index 49ff2e6..b98d1d6 100644
--- a/hw/core/irq.c
+++ b/hw/core/irq.c
@@ -22,6 +22,7 @@
  * THE SOFTWARE.
  */
 #include "qemu/osdep.h"
+#include "qemu/main-loop.h"
 #include "qemu-common.h"
 #include "hw/irq.h"
 #include "qom/object.h"
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index 4448253..3be6b96 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -450,8 +450,8 @@ static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip)
     resume_all_vcpus();
 
     if (!kvm_enabled()) {
-        /* tb_lock will be reset when cpu_loop_exit_noexc longjmps
-         * back into the cpu_exec loop. */
+        /* Both tb_lock and iothread_mutex will be reset when
+         *  longjmps back into the cpu_exec loop. */
         tb_lock();
         tb_gen_code(cs, current_pc, current_cs_base, current_flags, 1);
         cpu_loop_exit_noexc(cs);
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index ddb7438..63df95b 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1023,6 +1023,9 @@ static void emulate_spapr_hypercall(PowerPCCPU *cpu)
 {
     CPUPPCState *env = &cpu->env;
 
+    /* The TCG path should also be holding the BQL at this point */
+    g_assert(qemu_mutex_iothread_locked());
+
     if (msr_pr) {
         hcall_dprintf("Hypercall made with MSR[PR]=1\n");
         env->gpr[3] = H_PRIVILEGE;
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index d268e20..0c44b3c 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -305,6 +305,7 @@ struct CPUState {
     bool unplug;
     bool crash_occurred;
     bool exit_request;
+    /* updates protected by BQL */
     uint32_t interrupt_request;
     int singlestep_enabled;
     int64_t icount_extra;
diff --git a/memory.c b/memory.c
index 58f9269..7a67c05 100644
--- a/memory.c
+++ b/memory.c
@@ -925,6 +925,8 @@ void memory_region_transaction_commit(void)
     AddressSpace *as;
 
     assert(memory_region_transaction_depth);
+    assert(qemu_mutex_iothread_locked());
+
     --memory_region_transaction_depth;
     if (!memory_region_transaction_depth) {
         if (memory_region_update_pending) {
diff --git a/qom/cpu.c b/qom/cpu.c
index c40f774..4817cd4 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -113,9 +113,19 @@ static void cpu_common_get_memory_mapping(CPUState *cpu,
     error_setg(errp, "Obtaining memory mappings is unsupported on this CPU.");
 }
 
+/* Resetting the IRQ comes from across the code base so we take the
+ * BQL here if we need to.  cpu_interrupt assumes it is held.*/
 void cpu_reset_interrupt(CPUState *cpu, int mask)
 {
+    bool need_lock = !qemu_mutex_iothread_locked();
+
+    if (need_lock) {
+        qemu_mutex_lock_iothread();
+    }
     cpu->interrupt_request &= ~mask;
+    if (need_lock) {
+        qemu_mutex_unlock_iothread();
+    }
 }
 
 void cpu_exit(CPUState *cpu)
diff --git a/target-i386/smm_helper.c b/target-i386/smm_helper.c
index 4dd6a2c..f051a77 100644
--- a/target-i386/smm_helper.c
+++ b/target-i386/smm_helper.c
@@ -18,6 +18,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/main-loop.h"
 #include "cpu.h"
 #include "exec/helper-proto.h"
 #include "exec/log.h"
@@ -42,11 +43,14 @@ void helper_rsm(CPUX86State *env)
 #define SMM_REVISION_ID 0x00020000
 #endif
 
+/* Called with iothread lock taken */
 void cpu_smm_update(X86CPU *cpu)
 {
     CPUX86State *env = &cpu->env;
     bool smm_enabled = (env->hflags & HF_SMM_MASK);
 
+    g_assert(qemu_mutex_iothread_locked());
+
     if (cpu->smram) {
         memory_region_set_enabled(cpu->smram, smm_enabled);
     }
@@ -333,7 +337,10 @@ void helper_rsm(CPUX86State *env)
     }
     env->hflags2 &= ~HF2_SMM_INSIDE_NMI_MASK;
     env->hflags &= ~HF_SMM_MASK;
+
+    qemu_mutex_lock_iothread();
     cpu_smm_update(cpu);
+    qemu_mutex_unlock_iothread();
 
     qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n");
     log_cpu_state_mask(CPU_LOG_INT, CPU(cpu), CPU_DUMP_CCOP);
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index 4df2ec6..5851e4d 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -25,6 +25,7 @@
 #include "exec/helper-proto.h"
 #include "sysemu/kvm.h"
 #include "qemu/timer.h"
+#include "qemu/main-loop.h"
 #include "exec/address-spaces.h"
 #ifdef CONFIG_KVM
 #include <linux/kvm.h>
@@ -109,11 +110,13 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
 /* SCLP service call */
 uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
 {
+    qemu_mutex_lock_iothread();
     int r = sclp_service_call(env, r1, r2);
     if (r < 0) {
         program_interrupt(env, -r, 4);
-        return 0;
+        r = 0;
     }
+    qemu_mutex_unlock_iothread();
     return r;
 }
 
diff --git a/translate-all.c b/translate-all.c
index 1237f3c..23a2170 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -55,6 +55,7 @@
 #include "translate-all.h"
 #include "qemu/bitmap.h"
 #include "qemu/timer.h"
+#include "qemu/main-loop.h"
 #include "exec/log.h"
 
 /* #define DEBUG_TB_INVALIDATE */
@@ -1503,7 +1504,9 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
 }
 
 #ifdef CONFIG_SOFTMMU
-/* len must be <= 8 and start must be a multiple of len */
+/* len must be <= 8 and start must be a multiple of len.
+ * Called via softmmu_template.h, with iothread mutex not held.
+ */
 void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len)
 {
     PageDesc *p;
@@ -1698,7 +1701,10 @@ void tb_check_watchpoint(CPUState *cpu)
 
 #ifndef CONFIG_USER_ONLY
 /* in deterministic execution mode, instructions doing device I/Os
-   must be at the end of the TB */
+ * must be at the end of the TB.
+ *
+ * Called by softmmu_template.h, with iothread mutex not held.
+ */
 void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
 {
 #if defined(TARGET_MIPS) || defined(TARGET_SH4)
@@ -1910,6 +1916,7 @@ void dump_opcount_info(FILE *f, fprintf_function cpu_fprintf)
 
 void cpu_interrupt(CPUState *cpu, int mask)
 {
+    g_assert(qemu_mutex_iothread_locked());
     cpu->interrupt_request |= mask;
     cpu->tcg_exit_req = 1;
 }
diff --git a/translate-common.c b/translate-common.c
index 5e989cd..d504dd0 100644
--- a/translate-common.c
+++ b/translate-common.c
@@ -21,6 +21,7 @@
 #include "qemu-common.h"
 #include "qom/cpu.h"
 #include "sysemu/cpus.h"
+#include "qemu/main-loop.h"
 
 uintptr_t qemu_real_host_page_size;
 intptr_t qemu_real_host_page_mask;
@@ -30,6 +31,7 @@ intptr_t qemu_real_host_page_mask;
 static void tcg_handle_interrupt(CPUState *cpu, int mask)
 {
     int old_mask;
+    g_assert(qemu_mutex_iothread_locked());
 
     old_mask = cpu->interrupt_request;
     cpu->interrupt_request |= mask;
@@ -40,17 +42,16 @@ static void tcg_handle_interrupt(CPUState *cpu, int mask)
      */
     if (!qemu_cpu_is_self(cpu)) {
         qemu_cpu_kick(cpu);
-        return;
-    }
-
-    if (use_icount) {
-        cpu->icount_decr.u16.high = 0xffff;
-        if (!cpu->can_do_io
-            && (mask & ~old_mask) != 0) {
-            cpu_abort(cpu, "Raised interrupt while not in I/O function");
-        }
     } else {
-        cpu->tcg_exit_req = 1;
+        if (use_icount) {
+            cpu->icount_decr.u16.high = 0xffff;
+            if (!cpu->can_do_io
+                && (mask & ~old_mask) != 0) {
+                cpu_abort(cpu, "Raised interrupt while not in I/O function");
+            }
+        } else {
+            cpu->tcg_exit_req = 1;
+        }
     }
 }
 
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 17/33] cpus: re-factor out handle_icount_deadline
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (15 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 16/33] tcg: drop global lock during TCG code execution Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 18/33] tcg: remove global exit_request Alex Bennée
                   ` (16 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

In preparation for adding a MTTCG thread we re-factor out a bit of what
will be common code to handle the QEMU_CLOCK_VIRTUAL expiration.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
v4
  - split from exit_request patch
---
 cpus.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/cpus.c b/cpus.c
index aca2a2e..6367772 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1172,6 +1172,18 @@ static int64_t tcg_get_icount_limit(void)
     }
 }
 
+static void handle_icount_deadline(void)
+{
+    if (use_icount) {
+        int64_t deadline =
+            qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
+
+        if (deadline == 0) {
+            qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
+        }
+    }
+}
+
 static int tcg_cpu_exec(CPUState *cpu)
 {
     int ret;
@@ -1310,13 +1322,8 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
         /* Pairs with smp_wmb in qemu_cpu_kick.  */
         atomic_mb_set(&exit_request, 0);
 
-        if (use_icount) {
-            int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
+        handle_icount_deadline();
 
-            if (deadline == 0) {
-                qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
-            }
-        }
         qemu_tcg_wait_io_event(QTAILQ_FIRST(&cpus));
         deal_with_unplugged_cpus();
     }
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 18/33] tcg: remove global exit_request
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (16 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 17/33] cpus: re-factor out handle_icount_deadline Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 19/33] tcg: move locking for tb_invalidate_phys_page_range up Alex Bennée
                   ` (15 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

There are now only two uses of the global exit_request left.

The first ensures we exit the run_loop when we first start to process
pending work and in the kick handler. This is just as easily done by
setting the first_cpu->exit_request flag.

The second use is in the round robin kick routine. The global
exit_request ensured every vCPU would set its local exit_request and
cause a full exit of the loop. Now the iothread isn't being held while
running we can just rely on the kick handler to push us out as intended.

We lightly re-factor the main vCPU thread to ensure cpu->exit_requests
cause us to exit the main loop and process any IO requests that might
come along.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
v5
  - minor merge conflict with kick patch
v4
  - moved to after iothread unlocking patch
  - needed to remove kick exit_request as well.
  - remove extraneous cpu->exit_request check
  - remove stray exit_request setting
  - remove needless atomic operation
---
 cpu-exec-common.c       |  2 --
 cpu-exec.c              |  9 ++-------
 cpus.c                  | 18 ++++++++++--------
 include/exec/exec-all.h |  3 ---
 4 files changed, 12 insertions(+), 20 deletions(-)

diff --git a/cpu-exec-common.c b/cpu-exec-common.c
index e2bc053..0504a94 100644
--- a/cpu-exec-common.c
+++ b/cpu-exec-common.c
@@ -23,8 +23,6 @@
 #include "exec/exec-all.h"
 #include "exec/memory-internal.h"
 
-bool exit_request;
-
 /* exit the current TB, but without causing any exception to be raised */
 void cpu_loop_exit_noexc(CPUState *cpu)
 {
diff --git a/cpu-exec.c b/cpu-exec.c
index 3ca44bd..3458dd6 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -565,9 +565,8 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
         /* Something asked us to stop executing
          * chained TBs; just continue round the main
          * loop. Whatever requested the exit will also
-         * have set something else (eg exit_request or
-         * interrupt_request) which we will handle
-         * next time around the loop.  But we need to
+         * have set something else (eg interrupt_request) which we
+         * will handle next time around the loop.  But we need to
          * ensure the tcg_exit_req read in generated code
          * comes before the next read of cpu->exit_request
          * or cpu->interrupt_request.
@@ -623,10 +622,6 @@ int cpu_exec(CPUState *cpu)
 
     rcu_read_lock();
 
-    if (unlikely(atomic_mb_read(&exit_request))) {
-        cpu->exit_request = 1;
-    }
-
     cc->cpu_exec_enter(cpu);
 
     /* Calculate difference between guest clock and host clock.
diff --git a/cpus.c b/cpus.c
index 6367772..bba71af 100644
--- a/cpus.c
+++ b/cpus.c
@@ -760,7 +760,6 @@ static inline int64_t qemu_tcg_next_kick(void)
 static void qemu_cpu_kick_rr_cpu(void)
 {
     CPUState *cpu;
-    atomic_mb_set(&exit_request, 1);
     do {
         cpu = atomic_mb_read(&tcg_current_rr_cpu);
         if (cpu) {
@@ -1282,11 +1281,11 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
 
     start_tcg_kick_timer();
 
-    /* process any pending work */
-    atomic_mb_set(&exit_request, 1);
-
     cpu = first_cpu;
 
+    /* process any pending work */
+    cpu->exit_request = 1;
+
     while (1) {
         /* Account partial waits to QEMU_CLOCK_VIRTUAL.  */
         qemu_account_warp_timer();
@@ -1295,7 +1294,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
             cpu = first_cpu;
         }
 
-        for (; cpu != NULL && !exit_request; cpu = CPU_NEXT(cpu)) {
+        while (cpu && !cpu->exit_request) {
             atomic_mb_set(&tcg_current_rr_cpu, cpu);
 
             qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
@@ -1315,12 +1314,15 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
                 break;
             }
 
-        } /* for cpu.. */
+            cpu = CPU_NEXT(cpu);
+        } /* while (cpu && !cpu->exit_request).. */
+
         /* Does not need atomic_mb_set because a spurious wakeup is okay.  */
         atomic_set(&tcg_current_rr_cpu, NULL);
 
-        /* Pairs with smp_wmb in qemu_cpu_kick.  */
-        atomic_mb_set(&exit_request, 0);
+        if (cpu && cpu->exit_request) {
+            atomic_mb_set(&cpu->exit_request, 0);
+        }
 
         handle_icount_deadline();
 
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index b8b9989..d097515 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -406,7 +406,4 @@ bool memory_region_is_unassigned(MemoryRegion *mr);
 /* vl.c */
 extern int singlestep;
 
-/* cpu-exec.c, accessed with atomic_mb_read/atomic_mb_set */
-extern bool exit_request;
-
 #endif
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 19/33] tcg: move locking for tb_invalidate_phys_page_range up
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (17 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 18/33] tcg: remove global exit_request Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 20/33] tcg: enable tb_lock() for SoftMMU Alex Bennée
                   ` (14 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

In the linux-user case all things that involve ''l1_map' and PageDesc
tweaks are protected by the memory lock (mmpa_lock). For SoftMMU mode
we previously relied on single threaded behaviour, with MTTCG we now use
the tb_lock().

As a result we need to do a little re-factoring  and push the taking of
this lock up the call tree. This requires a slightly different entry for
the SoftMMU and user-mode cases from tb_invalidate_phys_range.

This also means user-mode breakpoint insertion needs to take two locks
but it hadn't taken any previously so this is an improvement.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 exec.c          | 16 ++++++++++++++++
 translate-all.c | 37 +++++++++++++++++++++++++++++--------
 2 files changed, 45 insertions(+), 8 deletions(-)

diff --git a/exec.c b/exec.c
index 8db5545..738e8ba 100644
--- a/exec.c
+++ b/exec.c
@@ -651,7 +651,11 @@ void cpu_exec_init(CPUState *cpu, Error **errp)
 #if defined(CONFIG_USER_ONLY)
 static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
 {
+    mmap_lock();
+    tb_lock();
     tb_invalidate_phys_page_range(pc, pc + 1, 0);
+    tb_unlock();
+    mmap_unlock();
 }
 #else
 static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
@@ -660,6 +664,7 @@ static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
     hwaddr phys = cpu_get_phys_page_attrs_debug(cpu, pc, &attrs);
     int asidx = cpu_asidx_from_attrs(cpu, attrs);
     if (phys != -1) {
+        /* Locks grabbed by tb_invalidate_phys_addr */
         tb_invalidate_phys_addr(cpu->cpu_ases[asidx].as,
                                 phys | (pc & ~TARGET_PAGE_MASK));
     }
@@ -1947,7 +1952,11 @@ ram_addr_t qemu_ram_addr_from_host(void *ptr)
 static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
                                uint64_t val, unsigned size)
 {
+    bool locked = false;
+
     if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) {
+        locked = true;
+        tb_lock();
         tb_invalidate_phys_page_fast(ram_addr, size);
     }
     switch (size) {
@@ -1963,6 +1972,11 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
     default:
         abort();
     }
+
+    if (locked) {
+        tb_unlock();
+    }
+
     /* Set both VGA and migration bits for simplicity and to remove
      * the notdirty callback faster.
      */
@@ -2443,7 +2457,9 @@ static void invalidate_and_set_dirty(MemoryRegion *mr, hwaddr addr,
             cpu_physical_memory_range_includes_clean(addr, length, dirty_log_mask);
     }
     if (dirty_log_mask & (1 << DIRTY_MEMORY_CODE)) {
+        tb_lock();
         tb_invalidate_phys_range(addr, addr + length);
+        tb_unlock();
         dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
     }
     cpu_physical_memory_set_dirty_range(addr, length, dirty_log_mask);
diff --git a/translate-all.c b/translate-all.c
index 23a2170..2dd240a 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -1383,12 +1383,11 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
  * access: the virtual CPU will exit the current TB if code is modified inside
  * this TB.
  *
- * Called with mmap_lock held for user-mode emulation
+ * Called with mmap_lock held for user-mode emulation, grabs tb_lock
+ * Called with tb_lock held for system-mode emulation
  */
-void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
+static void tb_invalidate_phys_range_1(tb_page_addr_t start, tb_page_addr_t end)
 {
-    assert_memory_lock();
-
     while (start < end) {
         tb_invalidate_phys_page_range(start, end, 0);
         start &= TARGET_PAGE_MASK;
@@ -1396,6 +1395,21 @@ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
     }
 }
 
+#ifdef CONFIG_SOFTMMU
+void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
+{
+    assert_tb_lock();
+    tb_invalidate_phys_range_1(start, end);
+}
+#else
+void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
+{
+    assert_memory_lock();
+    tb_lock();
+    tb_invalidate_phys_range_1(start, end);
+    tb_unlock();
+}
+#endif
 /*
  * Invalidate all TBs which intersect with the target physical address range
  * [start;end[. NOTE: start and end must refer to the *same* physical page.
@@ -1403,7 +1417,8 @@ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
  * access: the virtual CPU will exit the current TB if code is modified inside
  * this TB.
  *
- * Called with mmap_lock held for user-mode emulation
+ * Called with tb_lock/mmap_lock held for user-mode emulation
+ * Called with tb_lock held for system-mode emulation
  */
 void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
                                    int is_cpu_write_access)
@@ -1426,6 +1441,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
 #endif /* TARGET_HAS_PRECISE_SMC */
 
     assert_memory_lock();
+    assert_tb_lock();
 
     p = page_find(start >> TARGET_PAGE_BITS);
     if (!p) {
@@ -1440,7 +1456,6 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
     /* we remove all the TBs in the range [start, end[ */
     /* XXX: see if in some cases it could be faster to invalidate all
        the code */
-    tb_lock();
     tb = p->first_tb;
     while (tb != NULL) {
         n = (uintptr_t)tb & 3;
@@ -1500,12 +1515,12 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
         cpu_loop_exit_noexc(cpu);
     }
 #endif
-    tb_unlock();
 }
 
 #ifdef CONFIG_SOFTMMU
 /* len must be <= 8 and start must be a multiple of len.
- * Called via softmmu_template.h, with iothread mutex not held.
+ * Called via softmmu_template.h when code areas are written to with
+ * tb_lock held.
  */
 void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len)
 {
@@ -1520,6 +1535,8 @@ void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len)
                   (intptr_t)cpu_single_env->segs[R_CS].base);
     }
 #endif
+    assert_memory_lock();
+
     p = page_find(start >> TARGET_PAGE_BITS);
     if (!p) {
         return;
@@ -1567,6 +1584,8 @@ static bool tb_invalidate_phys_page(tb_page_addr_t addr, uintptr_t pc)
     uint32_t current_flags = 0;
 #endif
 
+    assert_memory_lock();
+
     addr &= TARGET_PAGE_MASK;
     p = page_find(addr >> TARGET_PAGE_BITS);
     if (!p) {
@@ -1670,7 +1689,9 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
         return;
     }
     ram_addr = memory_region_get_ram_addr(mr) + addr;
+    tb_lock();
     tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
+    tb_unlock();
     rcu_read_unlock();
 }
 #endif /* !defined(CONFIG_USER_ONLY) */
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 20/33] tcg: enable tb_lock() for SoftMMU
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (18 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 19/33] tcg: move locking for tb_invalidate_phys_page_range up Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 21/33] tcg: enable thread-per-vCPU Alex Bennée
                   ` (13 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

tb_lock() has long been used for linux-user mode to protect code
generation. By enabling it now we prepare for MTTCG and ensure all code
generation is serialised by this lock. The other major structure that
needs protecting is the l1_map and its PageDesc structures. For the
SoftMMU case we also use tb_lock() to protect these structures instead
of linux-user mmap_lock() which as the name suggests serialises updates
to the structure as a result of guest mmap operations.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
v4
  - split from main tcg: enable thread-per-vCPU patch
---
 translate-all.c | 18 +++++-------------
 1 file changed, 5 insertions(+), 13 deletions(-)

diff --git a/translate-all.c b/translate-all.c
index 2dd240a..79b763d 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -82,7 +82,11 @@
 #endif
 
 #ifdef CONFIG_SOFTMMU
-#define assert_memory_lock() do { /* nothing */ } while (0)
+#define assert_memory_lock() do {           \
+        if (DEBUG_MEM_LOCKS) {              \
+            g_assert(have_tb_lock);         \
+        }                                   \
+    } while (0)
 #else
 #define assert_memory_lock() do {               \
         if (DEBUG_MEM_LOCKS) {                  \
@@ -147,36 +151,28 @@ TCGContext tcg_ctx;
 bool parallel_cpus;
 
 /* translation block context */
-#ifdef CONFIG_USER_ONLY
 __thread int have_tb_lock;
-#endif
 
 void tb_lock(void)
 {
-#ifdef CONFIG_USER_ONLY
     assert(!have_tb_lock);
     qemu_mutex_lock(&tcg_ctx.tb_ctx.tb_lock);
     have_tb_lock++;
-#endif
 }
 
 void tb_unlock(void)
 {
-#ifdef CONFIG_USER_ONLY
     assert(have_tb_lock);
     have_tb_lock--;
     qemu_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock);
-#endif
 }
 
 void tb_lock_reset(void)
 {
-#ifdef CONFIG_USER_ONLY
     if (have_tb_lock) {
         qemu_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock);
         have_tb_lock = 0;
     }
-#endif
 }
 
 #ifdef DEBUG_LOCKING
@@ -185,15 +181,11 @@ void tb_lock_reset(void)
 #define DEBUG_TB_LOCKS 0
 #endif
 
-#ifdef CONFIG_SOFTMMU
-#define assert_tb_lock() do { /* nothing */ } while (0)
-#else
 #define assert_tb_lock() do {               \
         if (DEBUG_TB_LOCKS) {               \
             g_assert(have_tb_lock);         \
         }                                   \
     } while (0)
-#endif
 
 
 static TranslationBlock *tb_find_pc(uintptr_t tc_ptr);
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 21/33] tcg: enable thread-per-vCPU
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (19 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 20/33] tcg: enable tb_lock() for SoftMMU Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 22/33] atomic: introduce cmpxchg_bool Alex Bennée
                   ` (12 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

There are a couple of changes that occur at the same time here:

  - introduce a single vCPU qemu_tcg_cpu_thread_fn

  One of these is spawned per vCPU with its own Thread and Condition
  variables. qemu_tcg_rr_cpu_thread_fn is the new name for the old
  single threaded function.

  - the TLS current_cpu variable is now live for the lifetime of MTTCG
    vCPU threads. This is for future work where async jobs need to know
    the vCPU context they are operating in.

The user to switch on multi-thread behaviour and spawn a thread
per-vCPU. For a simple test kvm-unit-test like:

  ./arm/run ./arm/locking-test.flat -smp 4 -accel tcg,thread=multi

Will now use 4 vCPU threads and have an expected FAIL (instead of the
unexpected PASS) as the default mode of the test has no protection when
incrementing a shared variable.

We enable the parallel_cpus flag to ensure we generate correct barrier
and atomic code if supported by the front and backends. As each back end
and front end is updated they can add CONFIG_MTTCG_TARGET and
CONFIG_MTTCG_HOST to their respective make configurations so
default_mttcg_enabled does the right thing.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
[AJB: Some fixes, conditionally, commit rewording]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v1 (ajb):
  - fix merge conflicts
  - maintain single-thread approach
v2
  - re-base fixes (no longer has tb_find_fast lock tweak ahead)
  - remove bogus break condition on cpu->stop/stopped
  - only process exiting cpus exit_request
  - handle all cpus idle case (fixes shutdown issues)
  - sleep on EXCP_HALTED in mttcg mode (prevent crash on start-up)
  - move icount timer into helper
v3
  - update the commit message
  - rm kick_timer tweaks (move to earlier tcg_current_cpu tweaks)
  - ensure linux-user clears cpu->exit_request in loop
  - purging of global exit_request and tcg_current_cpu in earlier patches
  - fix checkpatch warnings
v4
  - don't break loop on stopped, we may never schedule next in RR mode
  - make sure we flush iorequests of current cpu if we exited on one
  - add tcg_cpu_exec_start/end wraps for async work functions
  - stop killing of current_cpu on loop exit
  - set current_cpu in the single thread function
  - remove sleep special case, add qemu_tcg_should_sleep() for mttcg
  - no need to atomic set cpu->exit_request going into the loop
  - removed extraneous setting of exit_request
  - split tb_lock() part of patch
  - rename single thread fn to qemu_tcg_rr_cpu_thread_fn
v5
  - enable parallel_cpus for MTTCG (for barriers/atomics)
  - expand on CONFIG_ flags in commit message
---
 cpu-exec.c |   5 ---
 cpus.c     | 135 +++++++++++++++++++++++++++++++++++++++++++++++--------------
 2 files changed, 104 insertions(+), 36 deletions(-)

diff --git a/cpu-exec.c b/cpu-exec.c
index 3458dd6..1887a3d 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -396,7 +396,6 @@ static inline bool cpu_handle_halt(CPUState *cpu)
         }
 #endif
         if (!cpu_has_work(cpu)) {
-            current_cpu = NULL;
             return true;
         }
 
@@ -540,7 +539,6 @@ static inline void cpu_handle_interrupt(CPUState *cpu,
 
 
     if (unlikely(atomic_read(&cpu->exit_request) || replay_has_interrupt())) {
-        atomic_set(&cpu->exit_request, 0);
         cpu->exception_index = EXCP_INTERRUPT;
         cpu_loop_exit(cpu);
     }
@@ -675,8 +673,5 @@ int cpu_exec(CPUState *cpu)
     cc->cpu_exec_exit(cpu);
     rcu_read_unlock();
 
-    /* fail safe : never use current_cpu outside cpu_exec() */
-    current_cpu = NULL;
-
     return ret;
 }
diff --git a/cpus.c b/cpus.c
index bba71af..0c046e3 100644
--- a/cpus.c
+++ b/cpus.c
@@ -44,6 +44,7 @@
 #include "qemu/main-loop.h"
 #include "qemu/bitmap.h"
 #include "qemu/seqlock.h"
+#include "tcg.h"
 #include "qapi-event.h"
 #include "hw/nmi.h"
 #include "sysemu/replay.h"
@@ -776,7 +777,7 @@ static void kick_tcg_thread(void *opaque)
 
 static void start_tcg_kick_timer(void)
 {
-    if (!tcg_kick_vcpu_timer && CPU_NEXT(first_cpu)) {
+    if (!mttcg_enabled && !tcg_kick_vcpu_timer && CPU_NEXT(first_cpu)) {
         tcg_kick_vcpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,  kick_tcg_thread, NULL);
         timer_mod(tcg_kick_vcpu_timer, qemu_tcg_next_kick());
     }
@@ -1029,27 +1030,34 @@ static void qemu_tcg_destroy_vcpu(CPUState *cpu)
 
 static void qemu_wait_io_event_common(CPUState *cpu)
 {
+    atomic_mb_set(&cpu->thread_kicked, false);
     if (cpu->stop) {
         cpu->stop = false;
         cpu->stopped = true;
         qemu_cond_broadcast(&qemu_pause_cond);
     }
     process_queued_cpu_work(cpu);
-    cpu->thread_kicked = false;
+}
+
+static bool qemu_tcg_should_sleep(CPUState *cpu)
+{
+    if (mttcg_enabled) {
+        return cpu_thread_is_idle(cpu);
+    } else {
+        return all_cpu_threads_idle();
+    }
 }
 
 static void qemu_tcg_wait_io_event(CPUState *cpu)
 {
-    while (all_cpu_threads_idle()) {
+    while (qemu_tcg_should_sleep(cpu)) {
         stop_tcg_kick_timer();
         qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex);
     }
 
     start_tcg_kick_timer();
 
-    CPU_FOREACH(cpu) {
-        qemu_wait_io_event_common(cpu);
-    }
+    qemu_wait_io_event_common(cpu);
 }
 
 static void qemu_kvm_wait_io_event(CPUState *cpu)
@@ -1120,6 +1128,7 @@ static void *qemu_dummy_cpu_thread_fn(void *arg)
     qemu_thread_get_self(cpu->thread);
     cpu->thread_id = qemu_get_thread_id();
     cpu->can_do_io = 1;
+    current_cpu = cpu;
 
     sigemptyset(&waitset);
     sigaddset(&waitset, SIG_IPI);
@@ -1128,9 +1137,7 @@ static void *qemu_dummy_cpu_thread_fn(void *arg)
     cpu->created = true;
     qemu_cond_signal(&qemu_cpu_cond);
 
-    current_cpu = cpu;
     while (1) {
-        current_cpu = NULL;
         qemu_mutex_unlock_iothread();
         do {
             int sig;
@@ -1141,7 +1148,6 @@ static void *qemu_dummy_cpu_thread_fn(void *arg)
             exit(1);
         }
         qemu_mutex_lock_iothread();
-        current_cpu = cpu;
         qemu_wait_io_event_common(cpu);
     }
 
@@ -1253,7 +1259,7 @@ static void deal_with_unplugged_cpus(void)
  * elsewhere.
  */
 
-static void *qemu_tcg_cpu_thread_fn(void *arg)
+static void *qemu_tcg_rr_cpu_thread_fn(void *arg)
 {
     CPUState *cpu = arg;
 
@@ -1275,6 +1281,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
 
         /* process any pending work */
         CPU_FOREACH(cpu) {
+            current_cpu = cpu;
             qemu_wait_io_event_common(cpu);
         }
     }
@@ -1296,6 +1303,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
 
         while (cpu && !cpu->exit_request) {
             atomic_mb_set(&tcg_current_rr_cpu, cpu);
+            current_cpu = cpu;
 
             qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
                               (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
@@ -1307,7 +1315,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
                     cpu_handle_guest_debug(cpu);
                     break;
                 }
-            } else if (cpu->stop || cpu->stopped) {
+            } else if (cpu->stop) {
                 if (cpu->unplug) {
                     cpu = CPU_NEXT(cpu);
                 }
@@ -1326,13 +1334,71 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
 
         handle_icount_deadline();
 
-        qemu_tcg_wait_io_event(QTAILQ_FIRST(&cpus));
+        qemu_tcg_wait_io_event(cpu ? cpu : QTAILQ_FIRST(&cpus));
         deal_with_unplugged_cpus();
     }
 
     return NULL;
 }
 
+/* Multi-threaded TCG
+ *
+ * In the multi-threaded case each vCPU has its own thread. The TLS
+ * variable current_cpu can be used deep in the code to find the
+ * current CPUState for a given thread.
+ */
+
+static void *qemu_tcg_cpu_thread_fn(void *arg)
+{
+    CPUState *cpu = arg;
+
+    rcu_register_thread();
+
+    qemu_mutex_lock_iothread();
+    qemu_thread_get_self(cpu->thread);
+
+    cpu->thread_id = qemu_get_thread_id();
+    cpu->created = true;
+    cpu->can_do_io = 1;
+    current_cpu = cpu;
+    qemu_cond_signal(&qemu_cpu_cond);
+
+    /* process any pending work */
+    cpu->exit_request = 1;
+
+    while (1) {
+        if (cpu_can_run(cpu)) {
+            int r;
+            r = tcg_cpu_exec(cpu);
+            switch (r) {
+            case EXCP_DEBUG:
+                cpu_handle_guest_debug(cpu);
+                break;
+            case EXCP_HALTED:
+                /* during start-up the vCPU is reset and the thread is
+                 * kicked several times. If we don't ensure we go back
+                 * to sleep in the halted state we won't cleanly
+                 * start-up when the vCPU is enabled.
+                 *
+                 * cpu->halted should ensure we sleep in wait_io_event
+                 */
+                g_assert(cpu->halted);
+                break;
+            default:
+                /* Ignore everything else? */
+                break;
+            }
+        }
+
+        handle_icount_deadline();
+
+        atomic_mb_set(&cpu->exit_request, 0);
+        qemu_tcg_wait_io_event(cpu);
+    }
+
+    return NULL;
+}
+
 static void qemu_cpu_kick_thread(CPUState *cpu)
 {
 #ifndef _WIN32
@@ -1357,7 +1423,7 @@ void qemu_cpu_kick(CPUState *cpu)
     qemu_cond_broadcast(cpu->halt_cond);
     if (tcg_enabled()) {
         cpu_exit(cpu);
-        /* Also ensure current RR cpu is kicked */
+        /* NOP unless doing single-thread RR */
         qemu_cpu_kick_rr_cpu();
     } else {
         qemu_cpu_kick_thread(cpu);
@@ -1426,13 +1492,6 @@ void pause_all_vcpus(void)
 
     if (qemu_in_vcpu_thread()) {
         cpu_stop_current();
-        if (!kvm_enabled()) {
-            CPU_FOREACH(cpu) {
-                cpu->stop = false;
-                cpu->stopped = true;
-            }
-            return;
-        }
     }
 
     while (!all_vcpus_paused()) {
@@ -1481,29 +1540,43 @@ void cpu_remove_sync(CPUState *cpu)
 static void qemu_tcg_init_vcpu(CPUState *cpu)
 {
     char thread_name[VCPU_THREAD_NAME_SIZE];
-    static QemuCond *tcg_halt_cond;
-    static QemuThread *tcg_cpu_thread;
+    static QemuCond *single_tcg_halt_cond;
+    static QemuThread *single_tcg_cpu_thread;
 
-    /* share a single thread for all cpus with TCG */
-    if (!tcg_cpu_thread) {
+    if (qemu_tcg_mttcg_enabled() || !single_tcg_cpu_thread) {
+        parallel_cpus = true;
         cpu->thread = g_malloc0(sizeof(QemuThread));
         cpu->halt_cond = g_malloc0(sizeof(QemuCond));
         qemu_cond_init(cpu->halt_cond);
-        tcg_halt_cond = cpu->halt_cond;
-        snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG",
+
+        if (qemu_tcg_mttcg_enabled()) {
+            /* create a thread per vCPU with TCG (MTTCG) */
+            snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG",
                  cpu->cpu_index);
-        qemu_thread_create(cpu->thread, thread_name, qemu_tcg_cpu_thread_fn,
-                           cpu, QEMU_THREAD_JOINABLE);
+
+            qemu_thread_create(cpu->thread, thread_name, qemu_tcg_cpu_thread_fn,
+                               cpu, QEMU_THREAD_JOINABLE);
+
+        } else {
+            /* share a single thread for all cpus with TCG */
+            snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "ALL CPUs/TCG");
+            qemu_thread_create(cpu->thread, thread_name,
+                               qemu_tcg_rr_cpu_thread_fn,
+                               cpu, QEMU_THREAD_JOINABLE);
+
+            single_tcg_halt_cond = cpu->halt_cond;
+            single_tcg_cpu_thread = cpu->thread;
+        }
 #ifdef _WIN32
         cpu->hThread = qemu_thread_get_handle(cpu->thread);
 #endif
         while (!cpu->created) {
             qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
         }
-        tcg_cpu_thread = cpu->thread;
     } else {
-        cpu->thread = tcg_cpu_thread;
-        cpu->halt_cond = tcg_halt_cond;
+        /* For non-MTTCG cases we share the thread */
+        cpu->thread = single_tcg_cpu_thread;
+        cpu->halt_cond = single_tcg_halt_cond;
     }
 }
 
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 22/33] atomic: introduce cmpxchg_bool
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (20 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 21/33] tcg: enable thread-per-vCPU Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10   ` [Qemu-devel] " Alex Bennée
                   ` (11 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée

This allows for slightly neater code when checking for success of a
cmpxchg operation.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v4 (base-patches)
   - brought forward from ARM enabling patches
   - remove the un-needed extra temps
---
 include/qemu/atomic.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h
index 49cf55f..bd74b75 100644
--- a/include/qemu/atomic.h
+++ b/include/qemu/atomic.h
@@ -205,6 +205,14 @@
     atomic_cmpxchg__nocheck(ptr, old, new);                             \
 })
 
+#define atomic_bool_cmpxchg(ptr, old, new)                              \
+    ({                                                                  \
+    typeof(*ptr) _old = (old), _new = (new);                            \
+    __atomic_compare_exchange(ptr, &_old, &_new, false,                 \
+                                  __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);  \
+    })
+
+
 /* Provide shorter names for GCC atomic builtins, return old value */
 #define atomic_fetch_inc(ptr)  __atomic_fetch_add(ptr, 1, __ATOMIC_SEQ_CST)
 #define atomic_fetch_dec(ptr)  __atomic_fetch_sub(ptr, 1, __ATOMIC_SEQ_CST)
@@ -432,6 +440,7 @@
 
 #define atomic_cmpxchg(ptr, old, new) __sync_val_compare_and_swap(ptr, old, new)
 #define atomic_cmpxchg__nocheck(ptr, old, new)  atomic_cmpxchg(ptr, old, new)
+#define atomic_bool_cmpxchg(ptr, old, new)    __sync_bool_compare_and_swap(ptr, old, new)
 
 /* And even shorter names that return void.  */
 #define atomic_inc(ptr)        ((void) __sync_fetch_and_add(ptr, 1))
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v5 23/33] *_run_on_cpu: introduce run_on_cpu_data type
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
@ 2016-10-27 15:10   ` Alex Bennée
  2016-10-27 15:09 ` [Qemu-devel] [PATCH v5 02/33] translate_all: DEBUG_FLUSH -> DEBUG_TB_FLUSH Alex Bennée
                     ` (32 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite,
	Eduardo Habkost, Michael S. Tsirkin, David Gibson,
	Alexander Graf, Marcelo Tosatti, open list:PowerPC,
	open list:Overall

This changes the *_run_on_cpu APIs (and helpers) to pass data in a
run_on_cpu_data type instead of a plain void *. This is because we
sometimes want to pass a target address (target_ulong) and this fails on
32 bit hosts emulating 64 bit guests.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 cpus-common.c              |  9 +++++----
 cpus.c                     |  7 ++++---
 hw/i386/kvm/apic.c         | 14 +++++++-------
 hw/i386/kvmvapic.c         | 13 ++++++-------
 hw/ppc/ppce500_spin.c      |  6 +++---
 hw/ppc/spapr.c             |  4 ++--
 hw/ppc/spapr_hcall.c       | 12 ++++++------
 include/qom/cpu.h          | 31 ++++++++++++++++++++++++++-----
 kvm-all.c                  | 20 +++++++++++---------
 target-i386/helper.c       |  8 ++++----
 target-i386/kvm.c          |  4 ++--
 target-s390x/cpu.c         |  4 ++--
 target-s390x/cpu.h         |  4 ++--
 target-s390x/misc_helper.c |  4 ++--
 translate-all.c            | 13 ++++++-------
 15 files changed, 88 insertions(+), 65 deletions(-)

diff --git a/cpus-common.c b/cpus-common.c
index 3e11452..59f751e 100644
--- a/cpus-common.c
+++ b/cpus-common.c
@@ -109,7 +109,7 @@ void cpu_list_remove(CPUState *cpu)
 struct qemu_work_item {
     struct qemu_work_item *next;
     run_on_cpu_func func;
-    void *data;
+    run_on_cpu_data data;
     bool free, exclusive, done;
 };
 
@@ -129,7 +129,7 @@ static void queue_work_on_cpu(CPUState *cpu, struct qemu_work_item *wi)
     qemu_cpu_kick(cpu);
 }
 
-void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data,
+void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data,
                    QemuMutex *mutex)
 {
     struct qemu_work_item wi;
@@ -154,7 +154,7 @@ void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data,
     }
 }
 
-void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data)
+void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data)
 {
     struct qemu_work_item *wi;
 
@@ -296,7 +296,8 @@ void cpu_exec_end(CPUState *cpu)
     }
 }
 
-void async_safe_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data)
+void async_safe_run_on_cpu(CPUState *cpu, run_on_cpu_func func,
+                           run_on_cpu_data data)
 {
     struct qemu_work_item *wi;
 
diff --git a/cpus.c b/cpus.c
index 0c046e3..8f98060 100644
--- a/cpus.c
+++ b/cpus.c
@@ -600,7 +600,7 @@ static const VMStateDescription vmstate_timers = {
     }
 };
 
-static void cpu_throttle_thread(CPUState *cpu, void *opaque)
+static void cpu_throttle_thread(CPUState *cpu, run_on_cpu_data opaque)
 {
     double pct;
     double throttle_ratio;
@@ -630,8 +630,9 @@ static void cpu_throttle_timer_tick(void *opaque)
         return;
     }
     CPU_FOREACH(cpu) {
+        run_on_cpu_data data = { .host_ptr = (uintptr_t) NULL };
         if (!atomic_xchg(&cpu->throttle_thread_scheduled, 1)) {
-            async_run_on_cpu(cpu, cpu_throttle_thread, NULL);
+            async_run_on_cpu(cpu, cpu_throttle_thread, data);
         }
     }
 
@@ -1011,7 +1012,7 @@ void qemu_init_cpu_loop(void)
     qemu_thread_get_self(&io_thread);
 }
 
-void run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data)
+void run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data)
 {
     do_run_on_cpu(cpu, func, data, &qemu_global_mutex);
 }
diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c
index c016e63..45e370a 100644
--- a/hw/i386/kvm/apic.c
+++ b/hw/i386/kvm/apic.c
@@ -125,9 +125,9 @@ static void kvm_apic_vapic_base_update(APICCommonState *s)
     }
 }
 
-static void kvm_apic_put(CPUState *cs, void *data)
+static void kvm_apic_put(CPUState *cs, run_on_cpu_data data)
 {
-    APICCommonState *s = data;
+    APICCommonState *s = (APICCommonState *) data.host_ptr;
     struct kvm_lapic_state kapic;
     int ret;
 
@@ -143,12 +143,12 @@ static void kvm_apic_put(CPUState *cs, void *data)
 
 static void kvm_apic_post_load(APICCommonState *s)
 {
-    run_on_cpu(CPU(s->cpu), kvm_apic_put, s);
+    run_on_cpu(CPU(s->cpu), kvm_apic_put, RUN_ON_CPU_HOST_PTR(s));
 }
 
-static void do_inject_external_nmi(CPUState *cpu, void *data)
+static void do_inject_external_nmi(CPUState *cpu, run_on_cpu_data data)
 {
-    APICCommonState *s = data;
+    APICCommonState *s = (APICCommonState *) data.host_ptr;
     uint32_t lvt;
     int ret;
 
@@ -166,7 +166,7 @@ static void do_inject_external_nmi(CPUState *cpu, void *data)
 
 static void kvm_apic_external_nmi(APICCommonState *s)
 {
-    run_on_cpu(CPU(s->cpu), do_inject_external_nmi, s);
+    run_on_cpu(CPU(s->cpu), do_inject_external_nmi, RUN_ON_CPU_HOST_PTR(s));
 }
 
 static uint64_t kvm_apic_mem_read(void *opaque, hwaddr addr,
@@ -199,7 +199,7 @@ static void kvm_apic_reset(APICCommonState *s)
     /* Not used by KVM, which uses the CPU mp_state instead.  */
     s->wait_for_sipi = 0;
 
-    run_on_cpu(CPU(s->cpu), kvm_apic_put, s);
+    run_on_cpu(CPU(s->cpu), kvm_apic_put, RUN_ON_CPU_HOST_PTR(s));
 }
 
 static void kvm_apic_realize(DeviceState *dev, Error **errp)
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index 3be6b96..2b71295 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -487,10 +487,9 @@ typedef struct VAPICEnableTPRReporting {
     bool enable;
 } VAPICEnableTPRReporting;
 
-static void vapic_do_enable_tpr_reporting(CPUState *cpu, void *data)
+static void vapic_do_enable_tpr_reporting(CPUState *cpu, run_on_cpu_data data)
 {
-    VAPICEnableTPRReporting *info = data;
-
+    VAPICEnableTPRReporting *info = (VAPICEnableTPRReporting *) data.host_ptr;
     apic_enable_tpr_access_reporting(info->apic, info->enable);
 }
 
@@ -505,7 +504,7 @@ static void vapic_enable_tpr_reporting(bool enable)
     CPU_FOREACH(cs) {
         cpu = X86_CPU(cs);
         info.apic = cpu->apic_state;
-        run_on_cpu(cs, vapic_do_enable_tpr_reporting, &info);
+        run_on_cpu(cs, vapic_do_enable_tpr_reporting, RUN_ON_CPU_HOST_PTR(&info));
     }
 }
 
@@ -738,9 +737,9 @@ static void vapic_realize(DeviceState *dev, Error **errp)
     nb_option_roms++;
 }
 
-static void do_vapic_enable(CPUState *cs, void *data)
+static void do_vapic_enable(CPUState *cs, run_on_cpu_data data)
 {
-    VAPICROMState *s = data;
+    VAPICROMState *s = (VAPICROMState *) data.host_ptr;
     X86CPU *cpu = X86_CPU(cs);
 
     static const uint8_t enabled = 1;
@@ -762,7 +761,7 @@ static void kvmvapic_vm_state_change(void *opaque, int running,
 
     if (s->state == VAPIC_ACTIVE) {
         if (smp_cpus == 1) {
-            run_on_cpu(first_cpu, do_vapic_enable, s);
+            run_on_cpu(first_cpu, do_vapic_enable, RUN_ON_CPU_HOST_PTR(s));
         } else {
             zero = g_malloc0(s->rom_state.vapic_size);
             cpu_physical_memory_write(s->vapic_paddr, zero,
diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c
index 8e16f65..2383cd0 100644
--- a/hw/ppc/ppce500_spin.c
+++ b/hw/ppc/ppce500_spin.c
@@ -84,11 +84,11 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env,
     env->tlb_dirty = true;
 }
 
-static void spin_kick(CPUState *cs, void *data)
+static void spin_kick(CPUState *cs, run_on_cpu_data data)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
-    SpinInfo *curspin = data;
+    SpinInfo *curspin = (SpinInfo *) data.host_ptr;
     hwaddr map_size = 64 * 1024 * 1024;
     hwaddr map_start;
 
@@ -147,7 +147,7 @@ static void spin_write(void *opaque, hwaddr addr, uint64_t value,
 
     if (!(ldq_p(&curspin->addr) & 1)) {
         /* run CPU */
-        run_on_cpu(cpu, spin_kick, curspin);
+        run_on_cpu(cpu, spin_kick, RUN_ON_CPU_HOST_PTR(curspin));
     }
 }
 
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 63df95b..538cd93 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -2151,7 +2151,7 @@ static void spapr_machine_finalizefn(Object *obj)
     g_free(spapr->kvm_type);
 }
 
-static void ppc_cpu_do_nmi_on_cpu(CPUState *cs, void *arg)
+static void ppc_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg)
 {
     cpu_synchronize_state(cs);
     ppc_cpu_do_system_reset(cs);
@@ -2162,7 +2162,7 @@ static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
     CPUState *cs;
 
     CPU_FOREACH(cs) {
-        async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, NULL);
+        async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, (run_on_cpu_data) NULL);
     }
 }
 
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index c5e7e8c..d8ffd1e 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -18,9 +18,9 @@ struct SPRSyncState {
     target_ulong mask;
 };
 
-static void do_spr_sync(CPUState *cs, void *arg)
+static void do_spr_sync(CPUState *cs, run_on_cpu_data arg)
 {
-    struct SPRSyncState *s = arg;
+    struct SPRSyncState *s = (struct SPRSyncState *) arg.host_ptr;
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
 
@@ -37,7 +37,7 @@ static void set_spr(CPUState *cs, int spr, target_ulong value,
         .value = value,
         .mask = mask
     };
-    run_on_cpu(cs, do_spr_sync, &s);
+    run_on_cpu(cs, do_spr_sync, RUN_ON_CPU_HOST_PTR(&s));
 }
 
 static bool has_spr(PowerPCCPU *cpu, int spr)
@@ -911,10 +911,10 @@ typedef struct {
     Error *err;
 } SetCompatState;
 
-static void do_set_compat(CPUState *cs, void *arg)
+static void do_set_compat(CPUState *cs, run_on_cpu_data arg)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
-    SetCompatState *s = arg;
+    SetCompatState *s = (SetCompatState *) arg.host_ptr;
 
     cpu_synchronize_state(cs);
     ppc_set_compat(cpu, s->cpu_version, &s->err);
@@ -1017,7 +1017,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
                 .err = NULL,
             };
 
-            run_on_cpu(cs, do_set_compat, &s);
+            run_on_cpu(cs, do_set_compat, RUN_ON_CPU_HOST_PTR(&s));
 
             if (s.err) {
                 error_report_err(s.err);
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 0c44b3c..d8e6702 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -231,7 +231,28 @@ struct kvm_run;
 #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
 
 /* work queue */
-typedef void (*run_on_cpu_func)(CPUState *cpu, void *data);
+
+/* The union type allows passing of 64 bit target pointers on 32 bit
+ * hosts in a single parameter
+ */
+typedef union {
+    int       host_int;
+    unsigned  host_unsigned;
+    uintptr_t host_ptr;
+    void      *void_ptr;  /* for (run_on_cpu_data) NULL casts */
+    vaddr     target_ptr;
+} run_on_cpu_data;
+
+static inline run_on_cpu_data roc_host_ptr(void * p) {
+    run_on_cpu_data d = { .host_ptr = (uintptr_t) p};
+    return d;
+}
+
+/* #define RUN_ON_CPU_HOST_PTR(p) ((run_on_cpu_data) (uintptr_t) p) */
+#define RUN_ON_CPU_HOST_PTR(p) roc_host_ptr(p)
+
+typedef void (*run_on_cpu_func)(CPUState *cpu, run_on_cpu_data data);
+
 struct qemu_work_item;
 
 /**
@@ -647,7 +668,7 @@ bool cpu_is_stopped(CPUState *cpu);
  *
  * Used internally in the implementation of run_on_cpu.
  */
-void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data,
+void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data,
                    QemuMutex *mutex);
 
 /**
@@ -658,7 +679,7 @@ void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data,
  *
  * Schedules the function @func for execution on the vCPU @cpu.
  */
-void run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data);
+void run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data);
 
 /**
  * async_run_on_cpu:
@@ -668,7 +689,7 @@ void run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data);
  *
  * Schedules the function @func for execution on the vCPU @cpu asynchronously.
  */
-void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data);
+void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data);
 
 /**
  * async_safe_run_on_cpu:
@@ -682,7 +703,7 @@ void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data);
  * Unlike run_on_cpu and async_run_on_cpu, the function is run outside the
  * BQL.
  */
-void async_safe_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data);
+void async_safe_run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data);
 
 /**
  * qemu_get_cpu:
diff --git a/kvm-all.c b/kvm-all.c
index efb5fe3..831189b 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1856,7 +1856,7 @@ void kvm_flush_coalesced_mmio_buffer(void)
     s->coalesced_flush_in_progress = false;
 }
 
-static void do_kvm_cpu_synchronize_state(CPUState *cpu, void *arg)
+static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
 {
     if (!cpu->kvm_vcpu_dirty) {
         kvm_arch_get_registers(cpu);
@@ -1867,11 +1867,11 @@ static void do_kvm_cpu_synchronize_state(CPUState *cpu, void *arg)
 void kvm_cpu_synchronize_state(CPUState *cpu)
 {
     if (!cpu->kvm_vcpu_dirty) {
-        run_on_cpu(cpu, do_kvm_cpu_synchronize_state, NULL);
+        run_on_cpu(cpu, do_kvm_cpu_synchronize_state, (run_on_cpu_data) NULL);
     }
 }
 
-static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, void *arg)
+static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg)
 {
     kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE);
     cpu->kvm_vcpu_dirty = false;
@@ -1879,10 +1879,10 @@ static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, void *arg)
 
 void kvm_cpu_synchronize_post_reset(CPUState *cpu)
 {
-    run_on_cpu(cpu, do_kvm_cpu_synchronize_post_reset, NULL);
+    run_on_cpu(cpu, do_kvm_cpu_synchronize_post_reset, (run_on_cpu_data) NULL);
 }
 
-static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, void *arg)
+static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg)
 {
     kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE);
     cpu->kvm_vcpu_dirty = false;
@@ -1890,7 +1890,7 @@ static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, void *arg)
 
 void kvm_cpu_synchronize_post_init(CPUState *cpu)
 {
-    run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, NULL);
+    run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, (run_on_cpu_data) NULL);
 }
 
 int kvm_cpu_exec(CPUState *cpu)
@@ -2219,9 +2219,10 @@ struct kvm_set_guest_debug_data {
     int err;
 };
 
-static void kvm_invoke_set_guest_debug(CPUState *unused_cpu, void *data)
+static void kvm_invoke_set_guest_debug(CPUState *unused_cpu, run_on_cpu_data data)
 {
-    struct kvm_set_guest_debug_data *dbg_data = data;
+    struct kvm_set_guest_debug_data *dbg_data =
+        (struct kvm_set_guest_debug_data *) data.host_ptr;
 
     dbg_data->err = kvm_vcpu_ioctl(dbg_data->cpu, KVM_SET_GUEST_DEBUG,
                                    &dbg_data->dbg);
@@ -2238,7 +2239,8 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
     }
     kvm_arch_update_guest_debug(cpu, &data.dbg);
 
-    run_on_cpu(cpu, kvm_invoke_set_guest_debug, &data);
+    run_on_cpu(cpu, kvm_invoke_set_guest_debug,
+               (run_on_cpu_data) (uintptr_t) &data);
     return data.err;
 }
 
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 9bc961b..e2bade4 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -1121,9 +1121,9 @@ typedef struct MCEInjectionParams {
     int flags;
 } MCEInjectionParams;
 
-static void do_inject_x86_mce(CPUState *cs, void *data)
+static void do_inject_x86_mce(CPUState *cs, run_on_cpu_data data)
 {
-    MCEInjectionParams *params = data;
+    MCEInjectionParams *params = (MCEInjectionParams *) data.host_ptr;
     X86CPU *cpu = X86_CPU(cs);
     CPUX86State *cenv = &cpu->env;
     uint64_t *banks = cenv->mce_banks + 4 * params->bank;
@@ -1230,7 +1230,7 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank,
         return;
     }
 
-    run_on_cpu(cs, do_inject_x86_mce, &params);
+    run_on_cpu(cs, do_inject_x86_mce, RUN_ON_CPU_HOST_PTR(&params));
     if (flags & MCE_INJECT_BROADCAST) {
         CPUState *other_cs;
 
@@ -1243,7 +1243,7 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank,
             if (other_cs == cs) {
                 continue;
             }
-            run_on_cpu(other_cs, do_inject_x86_mce, &params);
+            run_on_cpu(other_cs, do_inject_x86_mce, RUN_ON_CPU_HOST_PTR(&params));
         }
     }
 }
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index ee1f53e..f125d3f 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -150,7 +150,7 @@ static int kvm_get_tsc(CPUState *cs)
     return 0;
 }
 
-static inline void do_kvm_synchronize_tsc(CPUState *cpu, void *arg)
+static inline void do_kvm_synchronize_tsc(CPUState *cpu, run_on_cpu_data arg)
 {
     kvm_get_tsc(cpu);
 }
@@ -161,7 +161,7 @@ void kvm_synchronize_all_tsc(void)
 
     if (kvm_enabled()) {
         CPU_FOREACH(cpu) {
-            run_on_cpu(cpu, do_kvm_synchronize_tsc, NULL);
+            run_on_cpu(cpu, do_kvm_synchronize_tsc, (run_on_cpu_data) NULL);
         }
     }
 }
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index 35ae2ce..20b4692 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -164,7 +164,7 @@ static void s390_cpu_machine_reset_cb(void *opaque)
 {
     S390CPU *cpu = opaque;
 
-    run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, NULL);
+    run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, (run_on_cpu_data) NULL);
 }
 #endif
 
@@ -220,7 +220,7 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
     s390_cpu_gdb_init(cs);
     qemu_init_vcpu(cs);
 #if !defined(CONFIG_USER_ONLY)
-    run_on_cpu(cs, s390_do_cpu_full_reset, NULL);
+    run_on_cpu(cs, s390_do_cpu_full_reset, (run_on_cpu_data) NULL);
 #else
     cpu_reset(cs);
 #endif
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 4e58cde..fd36a25 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -502,13 +502,13 @@ static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb,
 #define decode_basedisp_rs decode_basedisp_s
 
 /* helper functions for run_on_cpu() */
-static inline void s390_do_cpu_reset(CPUState *cs, void *arg)
+static inline void s390_do_cpu_reset(CPUState *cs, run_on_cpu_data arg)
 {
     S390CPUClass *scc = S390_CPU_GET_CLASS(cs);
 
     scc->cpu_reset(cs);
 }
-static inline void s390_do_cpu_full_reset(CPUState *cs, void *arg)
+static inline void s390_do_cpu_full_reset(CPUState *cs, run_on_cpu_data arg)
 {
     cpu_reset(cs);
 }
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index 5851e4d..53d3491 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -129,7 +129,7 @@ static int modified_clear_reset(S390CPU *cpu)
     pause_all_vcpus();
     cpu_synchronize_all_states();
     CPU_FOREACH(t) {
-        run_on_cpu(t, s390_do_cpu_full_reset, NULL);
+        run_on_cpu(t, s390_do_cpu_full_reset, (run_on_cpu_data) NULL);
     }
     s390_cmma_reset();
     subsystem_reset();
@@ -148,7 +148,7 @@ static int load_normal_reset(S390CPU *cpu)
     pause_all_vcpus();
     cpu_synchronize_all_states();
     CPU_FOREACH(t) {
-        run_on_cpu(t, s390_do_cpu_reset, NULL);
+        run_on_cpu(t, s390_do_cpu_reset, (run_on_cpu_data) NULL);
     }
     s390_cmma_reset();
     subsystem_reset();
diff --git a/translate-all.c b/translate-all.c
index 79b763d..0b0631e 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -889,16 +889,14 @@ static void page_flush_tb(void)
 }
 
 /* flush all the translation blocks */
-static void do_tb_flush(CPUState *cpu, void *data)
+static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count)
 {
-    unsigned tb_flush_req = (unsigned) (uintptr_t) data;
-
     tb_lock();
 
-    /* If it's already been done on request of another CPU,
+    /* If it is already been done on request of another CPU,
      * just retry.
      */
-    if (tcg_ctx.tb_ctx.tb_flush_count != tb_flush_req) {
+    if (tcg_ctx.tb_ctx.tb_flush_count != tb_flush_count.host_int) {
         goto done;
     }
 
@@ -939,8 +937,9 @@ done:
 void tb_flush(CPUState *cpu)
 {
     if (tcg_enabled()) {
-        uintptr_t tb_flush_req = atomic_mb_read(&tcg_ctx.tb_ctx.tb_flush_count);
-        async_safe_run_on_cpu(cpu, do_tb_flush, (void *) tb_flush_req);
+        run_on_cpu_data tb_flush_count;
+        tb_flush_count.host_int = atomic_mb_read(&tcg_ctx.tb_ctx.tb_flush_count);
+        async_safe_run_on_cpu(cpu, do_tb_flush, tb_flush_count);
     }
 }
 
-- 
2.10.1


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 23/33] *_run_on_cpu: introduce run_on_cpu_data type
@ 2016-10-27 15:10   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite,
	Eduardo Habkost, Michael S. Tsirkin, David Gibson,
	Alexander Graf, Marcelo Tosatti, open list:PowerPC,
	open list:Overall

This changes the *_run_on_cpu APIs (and helpers) to pass data in a
run_on_cpu_data type instead of a plain void *. This is because we
sometimes want to pass a target address (target_ulong) and this fails on
32 bit hosts emulating 64 bit guests.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 cpus-common.c              |  9 +++++----
 cpus.c                     |  7 ++++---
 hw/i386/kvm/apic.c         | 14 +++++++-------
 hw/i386/kvmvapic.c         | 13 ++++++-------
 hw/ppc/ppce500_spin.c      |  6 +++---
 hw/ppc/spapr.c             |  4 ++--
 hw/ppc/spapr_hcall.c       | 12 ++++++------
 include/qom/cpu.h          | 31 ++++++++++++++++++++++++++-----
 kvm-all.c                  | 20 +++++++++++---------
 target-i386/helper.c       |  8 ++++----
 target-i386/kvm.c          |  4 ++--
 target-s390x/cpu.c         |  4 ++--
 target-s390x/cpu.h         |  4 ++--
 target-s390x/misc_helper.c |  4 ++--
 translate-all.c            | 13 ++++++-------
 15 files changed, 88 insertions(+), 65 deletions(-)

diff --git a/cpus-common.c b/cpus-common.c
index 3e11452..59f751e 100644
--- a/cpus-common.c
+++ b/cpus-common.c
@@ -109,7 +109,7 @@ void cpu_list_remove(CPUState *cpu)
 struct qemu_work_item {
     struct qemu_work_item *next;
     run_on_cpu_func func;
-    void *data;
+    run_on_cpu_data data;
     bool free, exclusive, done;
 };
 
@@ -129,7 +129,7 @@ static void queue_work_on_cpu(CPUState *cpu, struct qemu_work_item *wi)
     qemu_cpu_kick(cpu);
 }
 
-void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data,
+void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data,
                    QemuMutex *mutex)
 {
     struct qemu_work_item wi;
@@ -154,7 +154,7 @@ void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data,
     }
 }
 
-void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data)
+void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data)
 {
     struct qemu_work_item *wi;
 
@@ -296,7 +296,8 @@ void cpu_exec_end(CPUState *cpu)
     }
 }
 
-void async_safe_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data)
+void async_safe_run_on_cpu(CPUState *cpu, run_on_cpu_func func,
+                           run_on_cpu_data data)
 {
     struct qemu_work_item *wi;
 
diff --git a/cpus.c b/cpus.c
index 0c046e3..8f98060 100644
--- a/cpus.c
+++ b/cpus.c
@@ -600,7 +600,7 @@ static const VMStateDescription vmstate_timers = {
     }
 };
 
-static void cpu_throttle_thread(CPUState *cpu, void *opaque)
+static void cpu_throttle_thread(CPUState *cpu, run_on_cpu_data opaque)
 {
     double pct;
     double throttle_ratio;
@@ -630,8 +630,9 @@ static void cpu_throttle_timer_tick(void *opaque)
         return;
     }
     CPU_FOREACH(cpu) {
+        run_on_cpu_data data = { .host_ptr = (uintptr_t) NULL };
         if (!atomic_xchg(&cpu->throttle_thread_scheduled, 1)) {
-            async_run_on_cpu(cpu, cpu_throttle_thread, NULL);
+            async_run_on_cpu(cpu, cpu_throttle_thread, data);
         }
     }
 
@@ -1011,7 +1012,7 @@ void qemu_init_cpu_loop(void)
     qemu_thread_get_self(&io_thread);
 }
 
-void run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data)
+void run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data)
 {
     do_run_on_cpu(cpu, func, data, &qemu_global_mutex);
 }
diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c
index c016e63..45e370a 100644
--- a/hw/i386/kvm/apic.c
+++ b/hw/i386/kvm/apic.c
@@ -125,9 +125,9 @@ static void kvm_apic_vapic_base_update(APICCommonState *s)
     }
 }
 
-static void kvm_apic_put(CPUState *cs, void *data)
+static void kvm_apic_put(CPUState *cs, run_on_cpu_data data)
 {
-    APICCommonState *s = data;
+    APICCommonState *s = (APICCommonState *) data.host_ptr;
     struct kvm_lapic_state kapic;
     int ret;
 
@@ -143,12 +143,12 @@ static void kvm_apic_put(CPUState *cs, void *data)
 
 static void kvm_apic_post_load(APICCommonState *s)
 {
-    run_on_cpu(CPU(s->cpu), kvm_apic_put, s);
+    run_on_cpu(CPU(s->cpu), kvm_apic_put, RUN_ON_CPU_HOST_PTR(s));
 }
 
-static void do_inject_external_nmi(CPUState *cpu, void *data)
+static void do_inject_external_nmi(CPUState *cpu, run_on_cpu_data data)
 {
-    APICCommonState *s = data;
+    APICCommonState *s = (APICCommonState *) data.host_ptr;
     uint32_t lvt;
     int ret;
 
@@ -166,7 +166,7 @@ static void do_inject_external_nmi(CPUState *cpu, void *data)
 
 static void kvm_apic_external_nmi(APICCommonState *s)
 {
-    run_on_cpu(CPU(s->cpu), do_inject_external_nmi, s);
+    run_on_cpu(CPU(s->cpu), do_inject_external_nmi, RUN_ON_CPU_HOST_PTR(s));
 }
 
 static uint64_t kvm_apic_mem_read(void *opaque, hwaddr addr,
@@ -199,7 +199,7 @@ static void kvm_apic_reset(APICCommonState *s)
     /* Not used by KVM, which uses the CPU mp_state instead.  */
     s->wait_for_sipi = 0;
 
-    run_on_cpu(CPU(s->cpu), kvm_apic_put, s);
+    run_on_cpu(CPU(s->cpu), kvm_apic_put, RUN_ON_CPU_HOST_PTR(s));
 }
 
 static void kvm_apic_realize(DeviceState *dev, Error **errp)
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index 3be6b96..2b71295 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -487,10 +487,9 @@ typedef struct VAPICEnableTPRReporting {
     bool enable;
 } VAPICEnableTPRReporting;
 
-static void vapic_do_enable_tpr_reporting(CPUState *cpu, void *data)
+static void vapic_do_enable_tpr_reporting(CPUState *cpu, run_on_cpu_data data)
 {
-    VAPICEnableTPRReporting *info = data;
-
+    VAPICEnableTPRReporting *info = (VAPICEnableTPRReporting *) data.host_ptr;
     apic_enable_tpr_access_reporting(info->apic, info->enable);
 }
 
@@ -505,7 +504,7 @@ static void vapic_enable_tpr_reporting(bool enable)
     CPU_FOREACH(cs) {
         cpu = X86_CPU(cs);
         info.apic = cpu->apic_state;
-        run_on_cpu(cs, vapic_do_enable_tpr_reporting, &info);
+        run_on_cpu(cs, vapic_do_enable_tpr_reporting, RUN_ON_CPU_HOST_PTR(&info));
     }
 }
 
@@ -738,9 +737,9 @@ static void vapic_realize(DeviceState *dev, Error **errp)
     nb_option_roms++;
 }
 
-static void do_vapic_enable(CPUState *cs, void *data)
+static void do_vapic_enable(CPUState *cs, run_on_cpu_data data)
 {
-    VAPICROMState *s = data;
+    VAPICROMState *s = (VAPICROMState *) data.host_ptr;
     X86CPU *cpu = X86_CPU(cs);
 
     static const uint8_t enabled = 1;
@@ -762,7 +761,7 @@ static void kvmvapic_vm_state_change(void *opaque, int running,
 
     if (s->state == VAPIC_ACTIVE) {
         if (smp_cpus == 1) {
-            run_on_cpu(first_cpu, do_vapic_enable, s);
+            run_on_cpu(first_cpu, do_vapic_enable, RUN_ON_CPU_HOST_PTR(s));
         } else {
             zero = g_malloc0(s->rom_state.vapic_size);
             cpu_physical_memory_write(s->vapic_paddr, zero,
diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c
index 8e16f65..2383cd0 100644
--- a/hw/ppc/ppce500_spin.c
+++ b/hw/ppc/ppce500_spin.c
@@ -84,11 +84,11 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env,
     env->tlb_dirty = true;
 }
 
-static void spin_kick(CPUState *cs, void *data)
+static void spin_kick(CPUState *cs, run_on_cpu_data data)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
-    SpinInfo *curspin = data;
+    SpinInfo *curspin = (SpinInfo *) data.host_ptr;
     hwaddr map_size = 64 * 1024 * 1024;
     hwaddr map_start;
 
@@ -147,7 +147,7 @@ static void spin_write(void *opaque, hwaddr addr, uint64_t value,
 
     if (!(ldq_p(&curspin->addr) & 1)) {
         /* run CPU */
-        run_on_cpu(cpu, spin_kick, curspin);
+        run_on_cpu(cpu, spin_kick, RUN_ON_CPU_HOST_PTR(curspin));
     }
 }
 
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 63df95b..538cd93 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -2151,7 +2151,7 @@ static void spapr_machine_finalizefn(Object *obj)
     g_free(spapr->kvm_type);
 }
 
-static void ppc_cpu_do_nmi_on_cpu(CPUState *cs, void *arg)
+static void ppc_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg)
 {
     cpu_synchronize_state(cs);
     ppc_cpu_do_system_reset(cs);
@@ -2162,7 +2162,7 @@ static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
     CPUState *cs;
 
     CPU_FOREACH(cs) {
-        async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, NULL);
+        async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, (run_on_cpu_data) NULL);
     }
 }
 
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index c5e7e8c..d8ffd1e 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -18,9 +18,9 @@ struct SPRSyncState {
     target_ulong mask;
 };
 
-static void do_spr_sync(CPUState *cs, void *arg)
+static void do_spr_sync(CPUState *cs, run_on_cpu_data arg)
 {
-    struct SPRSyncState *s = arg;
+    struct SPRSyncState *s = (struct SPRSyncState *) arg.host_ptr;
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
 
@@ -37,7 +37,7 @@ static void set_spr(CPUState *cs, int spr, target_ulong value,
         .value = value,
         .mask = mask
     };
-    run_on_cpu(cs, do_spr_sync, &s);
+    run_on_cpu(cs, do_spr_sync, RUN_ON_CPU_HOST_PTR(&s));
 }
 
 static bool has_spr(PowerPCCPU *cpu, int spr)
@@ -911,10 +911,10 @@ typedef struct {
     Error *err;
 } SetCompatState;
 
-static void do_set_compat(CPUState *cs, void *arg)
+static void do_set_compat(CPUState *cs, run_on_cpu_data arg)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
-    SetCompatState *s = arg;
+    SetCompatState *s = (SetCompatState *) arg.host_ptr;
 
     cpu_synchronize_state(cs);
     ppc_set_compat(cpu, s->cpu_version, &s->err);
@@ -1017,7 +1017,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
                 .err = NULL,
             };
 
-            run_on_cpu(cs, do_set_compat, &s);
+            run_on_cpu(cs, do_set_compat, RUN_ON_CPU_HOST_PTR(&s));
 
             if (s.err) {
                 error_report_err(s.err);
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 0c44b3c..d8e6702 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -231,7 +231,28 @@ struct kvm_run;
 #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
 
 /* work queue */
-typedef void (*run_on_cpu_func)(CPUState *cpu, void *data);
+
+/* The union type allows passing of 64 bit target pointers on 32 bit
+ * hosts in a single parameter
+ */
+typedef union {
+    int       host_int;
+    unsigned  host_unsigned;
+    uintptr_t host_ptr;
+    void      *void_ptr;  /* for (run_on_cpu_data) NULL casts */
+    vaddr     target_ptr;
+} run_on_cpu_data;
+
+static inline run_on_cpu_data roc_host_ptr(void * p) {
+    run_on_cpu_data d = { .host_ptr = (uintptr_t) p};
+    return d;
+}
+
+/* #define RUN_ON_CPU_HOST_PTR(p) ((run_on_cpu_data) (uintptr_t) p) */
+#define RUN_ON_CPU_HOST_PTR(p) roc_host_ptr(p)
+
+typedef void (*run_on_cpu_func)(CPUState *cpu, run_on_cpu_data data);
+
 struct qemu_work_item;
 
 /**
@@ -647,7 +668,7 @@ bool cpu_is_stopped(CPUState *cpu);
  *
  * Used internally in the implementation of run_on_cpu.
  */
-void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data,
+void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data,
                    QemuMutex *mutex);
 
 /**
@@ -658,7 +679,7 @@ void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data,
  *
  * Schedules the function @func for execution on the vCPU @cpu.
  */
-void run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data);
+void run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data);
 
 /**
  * async_run_on_cpu:
@@ -668,7 +689,7 @@ void run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data);
  *
  * Schedules the function @func for execution on the vCPU @cpu asynchronously.
  */
-void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data);
+void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data);
 
 /**
  * async_safe_run_on_cpu:
@@ -682,7 +703,7 @@ void async_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data);
  * Unlike run_on_cpu and async_run_on_cpu, the function is run outside the
  * BQL.
  */
-void async_safe_run_on_cpu(CPUState *cpu, run_on_cpu_func func, void *data);
+void async_safe_run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data);
 
 /**
  * qemu_get_cpu:
diff --git a/kvm-all.c b/kvm-all.c
index efb5fe3..831189b 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1856,7 +1856,7 @@ void kvm_flush_coalesced_mmio_buffer(void)
     s->coalesced_flush_in_progress = false;
 }
 
-static void do_kvm_cpu_synchronize_state(CPUState *cpu, void *arg)
+static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
 {
     if (!cpu->kvm_vcpu_dirty) {
         kvm_arch_get_registers(cpu);
@@ -1867,11 +1867,11 @@ static void do_kvm_cpu_synchronize_state(CPUState *cpu, void *arg)
 void kvm_cpu_synchronize_state(CPUState *cpu)
 {
     if (!cpu->kvm_vcpu_dirty) {
-        run_on_cpu(cpu, do_kvm_cpu_synchronize_state, NULL);
+        run_on_cpu(cpu, do_kvm_cpu_synchronize_state, (run_on_cpu_data) NULL);
     }
 }
 
-static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, void *arg)
+static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg)
 {
     kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE);
     cpu->kvm_vcpu_dirty = false;
@@ -1879,10 +1879,10 @@ static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, void *arg)
 
 void kvm_cpu_synchronize_post_reset(CPUState *cpu)
 {
-    run_on_cpu(cpu, do_kvm_cpu_synchronize_post_reset, NULL);
+    run_on_cpu(cpu, do_kvm_cpu_synchronize_post_reset, (run_on_cpu_data) NULL);
 }
 
-static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, void *arg)
+static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg)
 {
     kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE);
     cpu->kvm_vcpu_dirty = false;
@@ -1890,7 +1890,7 @@ static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, void *arg)
 
 void kvm_cpu_synchronize_post_init(CPUState *cpu)
 {
-    run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, NULL);
+    run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, (run_on_cpu_data) NULL);
 }
 
 int kvm_cpu_exec(CPUState *cpu)
@@ -2219,9 +2219,10 @@ struct kvm_set_guest_debug_data {
     int err;
 };
 
-static void kvm_invoke_set_guest_debug(CPUState *unused_cpu, void *data)
+static void kvm_invoke_set_guest_debug(CPUState *unused_cpu, run_on_cpu_data data)
 {
-    struct kvm_set_guest_debug_data *dbg_data = data;
+    struct kvm_set_guest_debug_data *dbg_data =
+        (struct kvm_set_guest_debug_data *) data.host_ptr;
 
     dbg_data->err = kvm_vcpu_ioctl(dbg_data->cpu, KVM_SET_GUEST_DEBUG,
                                    &dbg_data->dbg);
@@ -2238,7 +2239,8 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
     }
     kvm_arch_update_guest_debug(cpu, &data.dbg);
 
-    run_on_cpu(cpu, kvm_invoke_set_guest_debug, &data);
+    run_on_cpu(cpu, kvm_invoke_set_guest_debug,
+               (run_on_cpu_data) (uintptr_t) &data);
     return data.err;
 }
 
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 9bc961b..e2bade4 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -1121,9 +1121,9 @@ typedef struct MCEInjectionParams {
     int flags;
 } MCEInjectionParams;
 
-static void do_inject_x86_mce(CPUState *cs, void *data)
+static void do_inject_x86_mce(CPUState *cs, run_on_cpu_data data)
 {
-    MCEInjectionParams *params = data;
+    MCEInjectionParams *params = (MCEInjectionParams *) data.host_ptr;
     X86CPU *cpu = X86_CPU(cs);
     CPUX86State *cenv = &cpu->env;
     uint64_t *banks = cenv->mce_banks + 4 * params->bank;
@@ -1230,7 +1230,7 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank,
         return;
     }
 
-    run_on_cpu(cs, do_inject_x86_mce, &params);
+    run_on_cpu(cs, do_inject_x86_mce, RUN_ON_CPU_HOST_PTR(&params));
     if (flags & MCE_INJECT_BROADCAST) {
         CPUState *other_cs;
 
@@ -1243,7 +1243,7 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank,
             if (other_cs == cs) {
                 continue;
             }
-            run_on_cpu(other_cs, do_inject_x86_mce, &params);
+            run_on_cpu(other_cs, do_inject_x86_mce, RUN_ON_CPU_HOST_PTR(&params));
         }
     }
 }
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index ee1f53e..f125d3f 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -150,7 +150,7 @@ static int kvm_get_tsc(CPUState *cs)
     return 0;
 }
 
-static inline void do_kvm_synchronize_tsc(CPUState *cpu, void *arg)
+static inline void do_kvm_synchronize_tsc(CPUState *cpu, run_on_cpu_data arg)
 {
     kvm_get_tsc(cpu);
 }
@@ -161,7 +161,7 @@ void kvm_synchronize_all_tsc(void)
 
     if (kvm_enabled()) {
         CPU_FOREACH(cpu) {
-            run_on_cpu(cpu, do_kvm_synchronize_tsc, NULL);
+            run_on_cpu(cpu, do_kvm_synchronize_tsc, (run_on_cpu_data) NULL);
         }
     }
 }
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index 35ae2ce..20b4692 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -164,7 +164,7 @@ static void s390_cpu_machine_reset_cb(void *opaque)
 {
     S390CPU *cpu = opaque;
 
-    run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, NULL);
+    run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, (run_on_cpu_data) NULL);
 }
 #endif
 
@@ -220,7 +220,7 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
     s390_cpu_gdb_init(cs);
     qemu_init_vcpu(cs);
 #if !defined(CONFIG_USER_ONLY)
-    run_on_cpu(cs, s390_do_cpu_full_reset, NULL);
+    run_on_cpu(cs, s390_do_cpu_full_reset, (run_on_cpu_data) NULL);
 #else
     cpu_reset(cs);
 #endif
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 4e58cde..fd36a25 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -502,13 +502,13 @@ static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb,
 #define decode_basedisp_rs decode_basedisp_s
 
 /* helper functions for run_on_cpu() */
-static inline void s390_do_cpu_reset(CPUState *cs, void *arg)
+static inline void s390_do_cpu_reset(CPUState *cs, run_on_cpu_data arg)
 {
     S390CPUClass *scc = S390_CPU_GET_CLASS(cs);
 
     scc->cpu_reset(cs);
 }
-static inline void s390_do_cpu_full_reset(CPUState *cs, void *arg)
+static inline void s390_do_cpu_full_reset(CPUState *cs, run_on_cpu_data arg)
 {
     cpu_reset(cs);
 }
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index 5851e4d..53d3491 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -129,7 +129,7 @@ static int modified_clear_reset(S390CPU *cpu)
     pause_all_vcpus();
     cpu_synchronize_all_states();
     CPU_FOREACH(t) {
-        run_on_cpu(t, s390_do_cpu_full_reset, NULL);
+        run_on_cpu(t, s390_do_cpu_full_reset, (run_on_cpu_data) NULL);
     }
     s390_cmma_reset();
     subsystem_reset();
@@ -148,7 +148,7 @@ static int load_normal_reset(S390CPU *cpu)
     pause_all_vcpus();
     cpu_synchronize_all_states();
     CPU_FOREACH(t) {
-        run_on_cpu(t, s390_do_cpu_reset, NULL);
+        run_on_cpu(t, s390_do_cpu_reset, (run_on_cpu_data) NULL);
     }
     s390_cmma_reset();
     subsystem_reset();
diff --git a/translate-all.c b/translate-all.c
index 79b763d..0b0631e 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -889,16 +889,14 @@ static void page_flush_tb(void)
 }
 
 /* flush all the translation blocks */
-static void do_tb_flush(CPUState *cpu, void *data)
+static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count)
 {
-    unsigned tb_flush_req = (unsigned) (uintptr_t) data;
-
     tb_lock();
 
-    /* If it's already been done on request of another CPU,
+    /* If it is already been done on request of another CPU,
      * just retry.
      */
-    if (tcg_ctx.tb_ctx.tb_flush_count != tb_flush_req) {
+    if (tcg_ctx.tb_ctx.tb_flush_count != tb_flush_count.host_int) {
         goto done;
     }
 
@@ -939,8 +937,9 @@ done:
 void tb_flush(CPUState *cpu)
 {
     if (tcg_enabled()) {
-        uintptr_t tb_flush_req = atomic_mb_read(&tcg_ctx.tb_ctx.tb_flush_count);
-        async_safe_run_on_cpu(cpu, do_tb_flush, (void *) tb_flush_req);
+        run_on_cpu_data tb_flush_count;
+        tb_flush_count.host_int = atomic_mb_read(&tcg_ctx.tb_ctx.tb_flush_count);
+        async_safe_run_on_cpu(cpu, do_tb_flush, tb_flush_count);
     }
 }
 
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 24/33] cputlb: add assert_cpu_is_self checks
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (22 preceding siblings ...)
  2016-10-27 15:10   ` [Qemu-devel] " Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 25/33] cputlb: introduce tlb_flush_* async work Alex Bennée
                   ` (9 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

For SoftMMU the TLB flushes are an example of a task that can be
triggered on one vCPU by another. To deal with this properly we need to
use safe work to ensure these changes are done safely. The new assert
can be enabled while debugging to catch these cases.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 cputlb.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/cputlb.c b/cputlb.c
index 986efaa..eec1c39 100644
--- a/cputlb.c
+++ b/cputlb.c
@@ -59,6 +59,12 @@
     } \
 } while (0)
 
+#define assert_cpu_is_self(this_cpu) do {                         \
+        if (DEBUG_TLB_GATE) {                                     \
+            g_assert(!cpu->created || qemu_cpu_is_self(cpu));     \
+        }                                                         \
+    } while (0)
+
 /* statistics */
 int tlb_flush_count;
 
@@ -78,6 +84,7 @@ void tlb_flush(CPUState *cpu, int flush_global)
 {
     CPUArchState *env = cpu->env_ptr;
 
+    assert_cpu_is_self(cpu);
     tlb_debug("(%d)\n", flush_global);
 
     memset(env->tlb_table, -1, sizeof(env->tlb_table));
@@ -94,6 +101,7 @@ static inline void v_tlb_flush_by_mmuidx(CPUState *cpu, va_list argp)
 {
     CPUArchState *env = cpu->env_ptr;
 
+    assert_cpu_is_self(cpu);
     tlb_debug("start\n");
 
     for (;;) {
@@ -138,6 +146,7 @@ void tlb_flush_page(CPUState *cpu, target_ulong addr)
     int i;
     int mmu_idx;
 
+    assert_cpu_is_self(cpu);
     tlb_debug("page :" TARGET_FMT_lx "\n", addr);
 
     /* Check if we need to flush due to large pages.  */
@@ -175,6 +184,7 @@ void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, ...)
 
     va_start(argp, addr);
 
+    assert_cpu_is_self(cpu);
     tlb_debug("addr "TARGET_FMT_lx"\n", addr);
 
     /* Check if we need to flush due to large pages.  */
@@ -263,6 +273,8 @@ void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length)
 
     int mmu_idx;
 
+    assert_cpu_is_self(cpu);
+
     env = cpu->env_ptr;
     for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
         unsigned int i;
@@ -294,6 +306,8 @@ void tlb_set_dirty(CPUState *cpu, target_ulong vaddr)
     int i;
     int mmu_idx;
 
+    assert_cpu_is_self(cpu);
+
     vaddr &= TARGET_PAGE_MASK;
     i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
@@ -353,6 +367,7 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
     unsigned vidx = env->vtlb_index++ % CPU_VTLB_SIZE;
     int asidx = cpu_asidx_from_attrs(cpu, attrs);
 
+    assert_cpu_is_self(cpu);
     assert(size >= TARGET_PAGE_SIZE);
     if (size != TARGET_PAGE_SIZE) {
         tlb_add_large_page(env, vaddr, size);
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 25/33] cputlb: introduce tlb_flush_* async work.
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (23 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 24/33] cputlb: add assert_cpu_is_self checks Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 26/33] cputlb: tweak qemu_ram_addr_from_host_nofail reporting Alex Bennée
                   ` (8 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

From: KONRAD Frederic <fred.konrad@greensocs.com>

Some architectures allow to flush the tlb of other VCPUs. This is not a problem
when we have only one thread for all VCPUs but it definitely needs to be an
asynchronous work when we are in true multithreaded work.

We take the tb_lock() when doing this to avoid racing with other threads
which may be invalidating TB's at the same time. The alternative would
be to use proper atomic primitives to clear the tlb entries en-mass.

This patch doesn't do anything to protect other cputlb function being
called in MTTCG mode making cross vCPU changes.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
[AJB: remove need for g_malloc on defer, make check fixes, tb_lock]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v5 (base patches)
  - take tb_lock() for memset
  - ensure tb_flush_page properly asyncs work for other vCPUs
  - use run_on_cpu_data
v4 (base_patches)
  - brought forward from arm enabling series
  - restore pending_tlb_flush flag
v1
  - Remove tlb_flush_all just do the check in tlb_flush.
  - remove the need to g_malloc
  - tlb_flush calls direct if !cpu->created
---
 cputlb.c                | 94 +++++++++++++++++++++++++++++++++++++++++--------
 include/exec/exec-all.h |  1 +
 include/qom/cpu.h       |  6 ++++
 3 files changed, 87 insertions(+), 14 deletions(-)

diff --git a/cputlb.c b/cputlb.c
index eec1c39..4190d9c 100644
--- a/cputlb.c
+++ b/cputlb.c
@@ -65,28 +65,35 @@
         }                                                         \
     } while (0)
 
+/* run_on_cpu_data.target_ptr should always be big enough for a
+ * target_ulong even on 32 bit builds */
+QEMU_BUILD_BUG_ON(sizeof(target_ulong) > sizeof(run_on_cpu_data));
+
+static inline run_on_cpu_data target_ptr(target_ulong tptr)
+{
+    run_on_cpu_data d = { .target_ptr = (vaddr) tptr };
+    return d;
+}
+
+static inline run_on_cpu_data host_int(int hint)
+{
+    run_on_cpu_data d = { .host_int = hint };
+    return d;
+}
+
+
 /* statistics */
 int tlb_flush_count;
 
-/* NOTE:
- * If flush_global is true (the usual case), flush all tlb entries.
- * If flush_global is false, flush (at least) all tlb entries not
- * marked global.
- *
- * Since QEMU doesn't currently implement a global/not-global flag
- * for tlb entries, at the moment tlb_flush() will also flush all
- * tlb entries in the flush_global == false case. This is OK because
- * CPU architectures generally permit an implementation to drop
- * entries from the TLB at any time, so flushing more entries than
- * required is only an efficiency issue, not a correctness issue.
- */
-void tlb_flush(CPUState *cpu, int flush_global)
+static void tlb_flush_nocheck(CPUState *cpu, int flush_global)
 {
     CPUArchState *env = cpu->env_ptr;
 
     assert_cpu_is_self(cpu);
     tlb_debug("(%d)\n", flush_global);
 
+    tb_lock();
+
     memset(env->tlb_table, -1, sizeof(env->tlb_table));
     memset(env->tlb_v_table, -1, sizeof(env->tlb_v_table));
     memset(cpu->tb_jmp_cache, 0, sizeof(cpu->tb_jmp_cache));
@@ -95,6 +102,39 @@ void tlb_flush(CPUState *cpu, int flush_global)
     env->tlb_flush_addr = -1;
     env->tlb_flush_mask = 0;
     tlb_flush_count++;
+
+    tb_unlock();
+
+    atomic_mb_set(&cpu->pending_tlb_flush, false);
+}
+
+static void tlb_flush_global_async_work(CPUState *cpu, run_on_cpu_data data)
+{
+    tlb_flush_nocheck(cpu, data.host_int);
+}
+
+/* NOTE:
+ * If flush_global is true (the usual case), flush all tlb entries.
+ * If flush_global is false, flush (at least) all tlb entries not
+ * marked global.
+ *
+ * Since QEMU doesn't currently implement a global/not-global flag
+ * for tlb entries, at the moment tlb_flush() will also flush all
+ * tlb entries in the flush_global == false case. This is OK because
+ * CPU architectures generally permit an implementation to drop
+ * entries from the TLB at any time, so flushing more entries than
+ * required is only an efficiency issue, not a correctness issue.
+ */
+void tlb_flush(CPUState *cpu, int flush_global)
+{
+    if (cpu->created && !qemu_cpu_is_self(cpu)) {
+        if (atomic_bool_cmpxchg(&cpu->pending_tlb_flush, false, true)) {
+            async_run_on_cpu(cpu, tlb_flush_global_async_work,
+                             host_int(flush_global));
+        }
+    } else {
+        tlb_flush_nocheck(cpu, flush_global);
+    }
 }
 
 static inline void v_tlb_flush_by_mmuidx(CPUState *cpu, va_list argp)
@@ -104,6 +144,8 @@ static inline void v_tlb_flush_by_mmuidx(CPUState *cpu, va_list argp)
     assert_cpu_is_self(cpu);
     tlb_debug("start\n");
 
+    tb_lock();
+
     for (;;) {
         int mmu_idx = va_arg(argp, int);
 
@@ -118,6 +160,8 @@ static inline void v_tlb_flush_by_mmuidx(CPUState *cpu, va_list argp)
     }
 
     memset(cpu->tb_jmp_cache, 0, sizeof(cpu->tb_jmp_cache));
+
+    tb_unlock();
 }
 
 void tlb_flush_by_mmuidx(CPUState *cpu, ...)
@@ -140,13 +184,15 @@ static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
     }
 }
 
-void tlb_flush_page(CPUState *cpu, target_ulong addr)
+static void tlb_flush_page_async_work(CPUState *cpu, run_on_cpu_data data)
 {
     CPUArchState *env = cpu->env_ptr;
+    target_ulong addr = (target_ulong) data.target_ptr;
     int i;
     int mmu_idx;
 
     assert_cpu_is_self(cpu);
+
     tlb_debug("page :" TARGET_FMT_lx "\n", addr);
 
     /* Check if we need to flush due to large pages.  */
@@ -176,6 +222,17 @@ void tlb_flush_page(CPUState *cpu, target_ulong addr)
     tb_flush_jmp_cache(cpu, addr);
 }
 
+void tlb_flush_page(CPUState *cpu, target_ulong addr)
+{
+    tlb_debug("page :" TARGET_FMT_lx "\n", addr);
+
+    if (!qemu_cpu_is_self(cpu)) {
+        async_run_on_cpu(cpu, tlb_flush_page_async_work, target_ptr(addr));
+    } else {
+        tlb_flush_page_async_work(cpu, target_ptr(addr));
+    }
+}
+
 void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, ...)
 {
     CPUArchState *env = cpu->env_ptr;
@@ -222,6 +279,15 @@ void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, ...)
     tb_flush_jmp_cache(cpu, addr);
 }
 
+void tlb_flush_page_all(target_ulong addr)
+{
+    CPUState *cpu;
+
+    CPU_FOREACH(cpu) {
+        async_run_on_cpu(cpu, tlb_flush_page_async_work, target_ptr(addr));
+    }
+}
+
 /* update the TLBs so that writes to code in the virtual page 'addr'
    can be detected */
 void tlb_protect_code(ram_addr_t ram_addr)
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index d097515..5483f5f 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -161,6 +161,7 @@ void tlb_set_page(CPUState *cpu, target_ulong vaddr,
 void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr);
 void probe_write(CPUArchState *env, target_ulong addr, int mmu_idx,
                  uintptr_t retaddr);
+void tlb_flush_page_all(target_ulong addr);
 #else
 static inline void tlb_flush_page(CPUState *cpu, target_ulong addr)
 {
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index d8e6702..1fe5b99 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -396,6 +396,12 @@ struct CPUState {
        (absolute value) offset as small as possible.  This reduces code
        size, especially for hosts without large memory offsets.  */
     uint32_t tcg_exit_req;
+
+    /* The pending_tlb_flush flag is set and cleared atomically to
+     * avoid potential races. The aim of the flag is to avoid
+     * unnecessary flushes.
+     */
+    bool pending_tlb_flush;
 };
 
 QTAILQ_HEAD(CPUTailQ, CPUState);
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 26/33] cputlb: tweak qemu_ram_addr_from_host_nofail reporting
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (24 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 25/33] cputlb: introduce tlb_flush_* async work Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 27/33] cputlb: atomically update tlb fields used by tlb_reset_dirty Alex Bennée
                   ` (7 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

This moves the helper function closer to where it is called and updates
the error message to report via error_report instead of the deprecated
fprintf.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 cputlb.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/cputlb.c b/cputlb.c
index 4190d9c..614c0b3 100644
--- a/cputlb.c
+++ b/cputlb.c
@@ -321,18 +321,6 @@ void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, uintptr_t start,
     }
 }
 
-static inline ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
-{
-    ram_addr_t ram_addr;
-
-    ram_addr = qemu_ram_addr_from_host(ptr);
-    if (ram_addr == RAM_ADDR_INVALID) {
-        fprintf(stderr, "Bad ram pointer %p\n", ptr);
-        abort();
-    }
-    return ram_addr;
-}
-
 void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length)
 {
     CPUArchState *env;
@@ -544,6 +532,18 @@ static void report_bad_exec(CPUState *cpu, target_ulong addr)
     log_cpu_state_mask(LOG_GUEST_ERROR, cpu, CPU_DUMP_FPU | CPU_DUMP_CCOP);
 }
 
+static inline ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
+{
+    ram_addr_t ram_addr;
+
+    ram_addr = qemu_ram_addr_from_host(ptr);
+    if (ram_addr == RAM_ADDR_INVALID) {
+        error_report("Bad ram pointer %p", ptr);
+        abort();
+    }
+    return ram_addr;
+}
+
 /* NOTE: this function can trigger an exception */
 /* NOTE2: the returned address is not exactly the physical address: it
  * is actually a ram_addr_t (in system mode; the user mode emulation
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 27/33] cputlb: atomically update tlb fields used by tlb_reset_dirty
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (25 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 26/33] cputlb: tweak qemu_ram_addr_from_host_nofail reporting Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 28/33] cputlb: make tlb_flush_by_mmuidx safe for MTTCG Alex Bennée
                   ` (6 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

The main use case for tlb_reset_dirty is to set the TLB_NOTDIRTY flags
in TLB entries to force the slow-path on writes. This is used to mark
page ranges containing code which has been translated so it can be
invalidated if written to. To do this safely we need to ensure the TLB
entries in question for all vCPUs are updated before we attempt to run
the code otherwise a race could be introduced.

To achieve this we atomically set the flag in tlb_reset_dirty_range and
take care when setting it when the TLB entry is filled.

The helper function is made static as it isn't used outside of cputlb.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 cputlb.c              | 91 ++++++++++++++++++++++++++++++++++++++-------------
 include/exec/cputlb.h |  2 --
 2 files changed, 68 insertions(+), 25 deletions(-)

diff --git a/cputlb.c b/cputlb.c
index 614c0b3..981cb42 100644
--- a/cputlb.c
+++ b/cputlb.c
@@ -303,32 +303,50 @@ void tlb_unprotect_code(ram_addr_t ram_addr)
     cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_CODE);
 }
 
-static bool tlb_is_dirty_ram(CPUTLBEntry *tlbe)
-{
-    return (tlbe->addr_write & (TLB_INVALID_MASK|TLB_MMIO|TLB_NOTDIRTY)) == 0;
-}
 
-void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, uintptr_t start,
+/*
+ * Dirty write flag handling
+ *
+ * When the TCG code writes to a location it looks up the address in
+ * the TLB and uses that data to compute the final address. If any of
+ * the lower bits of the address are set then the slow path is forced.
+ * There are a number of reasons to do this but for normal RAM the
+ * most usual is detecting writes to code regions which may invalidate
+ * generated code.
+ *
+ * Because we want other vCPUs to respond to changes straight away we
+ * update the te->addr_write field atomically. If the TLB entry has
+ * been changed by the vCPU in the mean time we skip the update.
+ */
+
+static void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, uintptr_t start,
                            uintptr_t length)
 {
-    uintptr_t addr;
+    /* paired with atomic_mb_set in tlb_set_page_with_attrs */
+    uintptr_t orig_addr = atomic_mb_read(&tlb_entry->addr_write);
+    uintptr_t addr = orig_addr;
 
-    if (tlb_is_dirty_ram(tlb_entry)) {
-        addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
+    if ((addr & (TLB_INVALID_MASK | TLB_MMIO | TLB_NOTDIRTY)) == 0) {
+        addr &= TARGET_PAGE_MASK;
+        addr += atomic_read(&tlb_entry->addend);
         if ((addr - start) < length) {
-            tlb_entry->addr_write |= TLB_NOTDIRTY;
+            uintptr_t notdirty_addr = orig_addr | TLB_NOTDIRTY;
+            atomic_cmpxchg(&tlb_entry->addr_write, orig_addr, notdirty_addr);
         }
     }
 }
 
+/* This is a cross vCPU call (i.e. another vCPU resetting the flags of
+ * the target vCPU). As such care needs to be taken that we don't
+ * dangerously race with another vCPU update. The only thing actually
+ * updated is the target TLB entry ->addr_write flags.
+ */
 void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length)
 {
     CPUArchState *env;
 
     int mmu_idx;
 
-    assert_cpu_is_self(cpu);
-
     env = cpu->env_ptr;
     for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
         unsigned int i;
@@ -414,9 +432,9 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
     MemoryRegionSection *section;
     unsigned int index;
     target_ulong address;
-    target_ulong code_address;
+    target_ulong code_address, write_address;
     uintptr_t addend;
-    CPUTLBEntry *te;
+    CPUTLBEntry *te, *tv;
     hwaddr iotlb, xlat, sz;
     unsigned vidx = env->vtlb_index++ % CPU_VTLB_SIZE;
     int asidx = cpu_asidx_from_attrs(cpu, attrs);
@@ -451,15 +469,21 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
 
     index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     te = &env->tlb_table[mmu_idx][index];
-
     /* do not discard the translation in te, evict it into a victim tlb */
-    env->tlb_v_table[mmu_idx][vidx] = *te;
+    tv = &env->tlb_v_table[mmu_idx][vidx];
+
+    /* addr_write can race with tlb_reset_dirty_range_all */
+    tv->addr_read = te->addr_read;
+    atomic_set(&tv->addr_write, atomic_read(&te->addr_write));
+    tv->addr_code = te->addr_code;
+    atomic_set(&tv->addend, atomic_read(&te->addend));
+
     env->iotlb_v[mmu_idx][vidx] = env->iotlb[mmu_idx][index];
 
     /* refill the tlb */
     env->iotlb[mmu_idx][index].addr = iotlb - vaddr;
     env->iotlb[mmu_idx][index].attrs = attrs;
-    te->addend = addend - vaddr;
+    atomic_set(&te->addend, addend - vaddr);
     if (prot & PAGE_READ) {
         te->addr_read = address;
     } else {
@@ -471,21 +495,24 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
     } else {
         te->addr_code = -1;
     }
+
+    write_address = -1;
     if (prot & PAGE_WRITE) {
         if ((memory_region_is_ram(section->mr) && section->readonly)
             || memory_region_is_romd(section->mr)) {
             /* Write access calls the I/O callback.  */
-            te->addr_write = address | TLB_MMIO;
+            write_address = address | TLB_MMIO;
         } else if (memory_region_is_ram(section->mr)
                    && cpu_physical_memory_is_clean(
                         memory_region_get_ram_addr(section->mr) + xlat)) {
-            te->addr_write = address | TLB_NOTDIRTY;
+            write_address = address | TLB_NOTDIRTY;
         } else {
-            te->addr_write = address;
+            write_address = address;
         }
-    } else {
-        te->addr_write = -1;
     }
+
+    /* Pairs with flag setting in tlb_reset_dirty_range */
+    atomic_mb_set(&te->addr_write, write_address);
 }
 
 /* Add a new TLB entry, but without specifying the memory
@@ -648,10 +675,28 @@ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index,
         if (cmp == page) {
             /* Found entry in victim tlb, swap tlb and iotlb.  */
             CPUTLBEntry tmptlb, *tlb = &env->tlb_table[mmu_idx][index];
+
+            /* tmptlb = *tlb; */
+            /* addr_write can race with tlb_reset_dirty_range_all */
+            tmptlb.addr_read = tlb->addr_read;
+            tmptlb.addr_write = atomic_read(&tlb->addr_write);
+            tmptlb.addr_code = tlb->addr_code;
+            tmptlb.addend = atomic_read(&tlb->addend);
+
+            /* *tlb = *vtlb; */
+            tlb->addr_read = vtlb->addr_read;
+            atomic_set(&tlb->addr_write, atomic_read(&vtlb->addr_write));
+            tlb->addr_code = vtlb->addr_code;
+            atomic_set(&tlb->addend, atomic_read(&vtlb->addend));
+
+            /* *vtlb = tmptlb; */
+            vtlb->addr_read = tmptlb.addr_read;
+            atomic_set(&vtlb->addr_write, tmptlb.addr_write);
+            vtlb->addr_code = tmptlb.addr_code;
+            atomic_set(&vtlb->addend, tmptlb.addend);
+
             CPUIOTLBEntry tmpio, *io = &env->iotlb[mmu_idx][index];
             CPUIOTLBEntry *vio = &env->iotlb_v[mmu_idx][vidx];
-
-            tmptlb = *tlb; *tlb = *vtlb; *vtlb = tmptlb;
             tmpio = *io; *io = *vio; *vio = tmpio;
             return true;
         }
diff --git a/include/exec/cputlb.h b/include/exec/cputlb.h
index d454c00..3f94178 100644
--- a/include/exec/cputlb.h
+++ b/include/exec/cputlb.h
@@ -23,8 +23,6 @@
 /* cputlb.c */
 void tlb_protect_code(ram_addr_t ram_addr);
 void tlb_unprotect_code(ram_addr_t ram_addr);
-void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, uintptr_t start,
-                           uintptr_t length);
 extern int tlb_flush_count;
 
 #endif
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 28/33] cputlb: make tlb_flush_by_mmuidx safe for MTTCG
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (26 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 27/33] cputlb: atomically update tlb fields used by tlb_reset_dirty Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-11-01  5:20   ` Pranith Kumar
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 29/33] target-arm/powerctl: defer cpu reset work to CPU context Alex Bennée
                   ` (5 subsequent siblings)
  33 siblings, 1 reply; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, Peter Crosthwaite

These flushes allow a per-mmuidx granularity to the TLB flushing and are
currently only used by the ARM model. As it is possible to hammer the
other vCPU threads with flushes (and build up long queues of identical
flushes) we extend mechanism used for the global tlb_flush and set a
bitmap describing all the pending flushes. The updates are done
atomically to avoid corruption of the bitmap but repeating a flush is
certainly not a problem.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
v5
  - fix tlb_flush_page_by_mmuidx to defer all checks to async work
  - convert to run_on_cpu_data
  - additional tlb_debugs

You can't be checking a cross cpu env-> variable

WARNING: ThreadSanitizer: data race (pid=1962)
  Read of size 8 at 0x7dd00005e998 by thread T2:
    #0 tlb_flush_page_by_mmuidx /home/alex/lsrc/qemu/qemu.git/cputlb.c:285 (qemu-system-aarch64+0x0000004a1732)
    #1 tlbi_aa64_vae1is_write /home/alex/lsrc/qemu/qemu.git/target-arm/helper.c:3023 (qemu-system-aarch64+0x000000672a98)
    #2 helper_set_cp_reg64 /home/alex/lsrc/qemu/qemu.git/target-arm/op_helper.c:744 (qemu-system-aarch64+0x000000668699)
    #3 <null> <null> (0x000040029eb5)
    #4 cpu_loop_exec_tb /home/alex/lsrc/qemu/qemu.git/cpu-exec.c:558 (qemu-system-aarch64+0x000000430d00)
    #5 cpu_exec /home/alex/lsrc/qemu/qemu.git/cpu-exec.c:646 (qemu-system-aarch64+0x0000004310e5)
    #6 tcg_cpu_exec /home/alex/lsrc/qemu/qemu.git/cpus.c:1156 (qemu-system-aarch64+0x000000474d6f)
    #7 qemu_tcg_cpu_thread_fn /home/alex/lsrc/qemu/qemu.git/cpus.c:1345 (qemu-system-aarch64+0x000000475641)
    #8 <null> <null> (libtsan.so.0+0x0000000230d9)

  Previous write of size 8 at 0x7dd00005e998 by thread T4:
    #0 tlb_add_large_page /home/alex/lsrc/qemu/qemu.git/cputlb.c:459 (qemu-system-aarch64+0x0000004a1ebf)
    #1 tlb_set_page_with_attrs /home/alex/lsrc/qemu/qemu.git/cputlb.c:487 (qemu-system-aarch64+0x0000004a2002)
    #2 arm_tlb_fill /home/alex/lsrc/qemu/qemu.git/target-arm/helper.c:8116 (qemu-system-aarch64+0x0000006849de)
    #3 tlb_fill /home/alex/lsrc/qemu/qemu.git/target-arm/op_helper.c:127 (qemu-system-aarch64+0x000000666b4c)
    #4 helper_le_ldul_mmu /home/alex/lsrc/qemu/qemu.git/softmmu_template.h:127 (qemu-system-aarch64+0x0000004a4bba)
    #5 <null> <null> (0x000040017833)
    #6 cpu_loop_exec_tb /home/alex/lsrc/qemu/qemu.git/cpu-exec.c:558 (qemu-system-aarch64+0x000000430d00)
    #7 cpu_exec /home/alex/lsrc/qemu/qemu.git/cpu-exec.c:646 (qemu-system-aarch64+0x0000004310e5)
    #8 tcg_cpu_exec /home/alex/lsrc/qemu/qemu.git/cpus.c:1156 (qemu-system-aarch64+0x000000474d6f)
    #9 qemu_tcg_cpu_thread_fn /home/alex/lsrc/qemu/qemu.git/cpus.c:1345 (qemu-system-aarch64+0x000000475641)
    #10 <null> <null> (libtsan.so.0+0x0000000230d9)

  Location is heap block of size 125904 at 0x7dd000040000 allocated by main thread:
    #0 malloc <null> (libtsan.so.0+0x0000000254a3)
    #1 g_malloc <null> (libglib-2.0.so.0+0x00000004f728)
    #2 object_new qom/object.c:488 (qemu-system-aarch64+0x000000b157c3)
    #3 machvirt_init /home/alex/lsrc/qemu/qemu.git/hw/arm/virt.c:1289 (qemu-system-aarch64+0x0000005d733e)
    #4 main /home/alex/lsrc/qemu/qemu.git/vl.c:4573 (qemu-system-aarch64+0x00000070f2eb)

  Thread T2 'CPU 0/TCG' (tid=1965, running) created by main thread at:
    #0 pthread_create <null> (libtsan.so.0+0x000000027577)
    #1 qemu_thread_create util/qemu-thread-posix.c:471 (qemu-system-aarch64+0x000000c710a6)
    #2 qemu_tcg_init_vcpu /home/alex/lsrc/qemu/qemu.git/cpus.c:1528 (qemu-system-aarch64+0x000000475f09)
    #3 qemu_init_vcpu /home/alex/lsrc/qemu/qemu.git/cpus.c:1605 (qemu-system-aarch64+0x00000047645e)
    #4 arm_cpu_realizefn /home/alex/lsrc/qemu/qemu.git/target-arm/cpu.c:708 (qemu-system-aarch64+0x00000068de38)
    #5 device_set_realized hw/core/qdev.c:918 (qemu-system-aarch64+0x00000080b429)
    #6 property_set_bool qom/object.c:1854 (qemu-system-aarch64+0x000000b19cb9)
    #7 object_property_set qom/object.c:1088 (qemu-system-aarch64+0x000000b177b5)
    #8 object_property_set_qobject qom/qom-qobject.c:27 (qemu-system-aarch64+0x000000b1b77a)
    #9 object_property_set_bool qom/object.c:1157 (qemu-system-aarch64+0x000000b17ac4)
    #10 machvirt_init /home/alex/lsrc/qemu/qemu.git/hw/arm/virt.c:1332 (qemu-system-aarch64+0x0000005d7576)
    #11 main /home/alex/lsrc/qemu/qemu.git/vl.c:4573 (qemu-system-aarch64+0x00000070f2eb)

  Thread T4 'CPU 2/TCG' (tid=1967, running) created by main thread at:
    #0 pthread_create <null> (libtsan.so.0+0x000000027577)
    #1 qemu_thread_create util/qemu-thread-posix.c:471 (qemu-system-aarch64+0x000000c710a6)
    #2 qemu_tcg_init_vcpu /home/alex/lsrc/qemu/qemu.git/cpus.c:1528 (qemu-system-aarch64+0x000000475f09)
    #3 qemu_init_vcpu /home/alex/lsrc/qemu/qemu.git/cpus.c:1605 (qemu-system-aarch64+0x00000047645e)
    #4 arm_cpu_realizefn /home/alex/lsrc/qemu/qemu.git/target-arm/cpu.c:708 (qemu-system-aarch64+0x00000068de38)
    #5 device_set_realized hw/core/qdev.c:918 (qemu-system-aarch64+0x00000080b429)
    #6 property_set_bool qom/object.c:1854 (qemu-system-aarch64+0x000000b19cb9)
    #7 object_property_set qom/object.c:1088 (qemu-system-aarch64+0x000000b177b5)
    #8 object_property_set_qobject qom/qom-qobject.c:27 (qemu-system-aarch64+0x000000b1b77a)
    #9 object_property_set_bool qom/object.c:1157 (qemu-system-aarch64+0x000000b17ac4)
    #10 machvirt_init /home/alex/lsrc/qemu/qemu.git/hw/arm/virt.c:1332 (qemu-system-aarch64+0x0000005d7576)
    #11 main /home/alex/lsrc/qemu/qemu.git/vl.c:4573 (qemu-system-aarch64+0x00000070f2eb)

SUMMARY: ThreadSanitizer: data race /home/alex/lsrc/qemu/qemu.git/cputlb.c:285 tlb_flush_page_by_mmuidx

debug for mmu_idx

mmu_idx debug
---
 cputlb.c          | 169 +++++++++++++++++++++++++++++++++++++++++-------------
 include/qom/cpu.h |  13 +++--
 2 files changed, 137 insertions(+), 45 deletions(-)

diff --git a/cputlb.c b/cputlb.c
index 981cb42..602cbb3 100644
--- a/cputlb.c
+++ b/cputlb.c
@@ -81,6 +81,22 @@ static inline run_on_cpu_data host_int(int hint)
     return d;
 }
 
+static inline run_on_cpu_data host_unsigned(unsigned hun)
+{
+    run_on_cpu_data d = { .host_unsigned = hun };
+    return d;
+}
+
+static inline run_on_cpu_data host_ulong(unsigned long hlong)
+{
+    run_on_cpu_data d = { .host_unsigned_long = hlong };
+    return d;
+}
+
+/* We currently can't handle more than 16 bits in the MMUIDX bitmask.
+ */
+QEMU_BUILD_BUG_ON(NB_MMU_MODES > 16);
+#define ALL_MMUIDX_BITS ((1 << NB_MMU_MODES) - 1)
 
 /* statistics */
 int tlb_flush_count;
@@ -105,7 +121,7 @@ static void tlb_flush_nocheck(CPUState *cpu, int flush_global)
 
     tb_unlock();
 
-    atomic_mb_set(&cpu->pending_tlb_flush, false);
+    atomic_mb_set(&cpu->pending_tlb_flush, 0);
 }
 
 static void tlb_flush_global_async_work(CPUState *cpu, run_on_cpu_data data)
@@ -128,7 +144,8 @@ static void tlb_flush_global_async_work(CPUState *cpu, run_on_cpu_data data)
 void tlb_flush(CPUState *cpu, int flush_global)
 {
     if (cpu->created && !qemu_cpu_is_self(cpu)) {
-        if (atomic_bool_cmpxchg(&cpu->pending_tlb_flush, false, true)) {
+        if (atomic_mb_read(&cpu->pending_tlb_flush) != ALL_MMUIDX_BITS) {
+            atomic_mb_set(&cpu->pending_tlb_flush, ALL_MMUIDX_BITS);
             async_run_on_cpu(cpu, tlb_flush_global_async_work,
                              host_int(flush_global));
         }
@@ -137,39 +154,77 @@ void tlb_flush(CPUState *cpu, int flush_global)
     }
 }
 
-static inline void v_tlb_flush_by_mmuidx(CPUState *cpu, va_list argp)
+static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data)
 {
     CPUArchState *env = cpu->env_ptr;
+    unsigned long mmu_idx_bitmask = data.host_unsigned_long;
+    int mmu_idx;
 
     assert_cpu_is_self(cpu);
-    tlb_debug("start\n");
 
     tb_lock();
 
-    for (;;) {
-        int mmu_idx = va_arg(argp, int);
+    tlb_debug("start: mmu_idx:0x%04lx\n", mmu_idx_bitmask);
 
-        if (mmu_idx < 0) {
-            break;
-        }
+    for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
 
-        tlb_debug("%d\n", mmu_idx);
+        if (test_bit(mmu_idx, &mmu_idx_bitmask)) {
+            tlb_debug("%d\n", mmu_idx);
 
-        memset(env->tlb_table[mmu_idx], -1, sizeof(env->tlb_table[0]));
-        memset(env->tlb_v_table[mmu_idx], -1, sizeof(env->tlb_v_table[0]));
+            memset(env->tlb_table[mmu_idx], -1, sizeof(env->tlb_table[0]));
+            memset(env->tlb_v_table[mmu_idx], -1, sizeof(env->tlb_v_table[0]));
+        }
     }
 
     memset(cpu->tb_jmp_cache, 0, sizeof(cpu->tb_jmp_cache));
 
+    tlb_debug("done\n");
+
     tb_unlock();
 }
 
+/* Helper function to slurp va_args list into a bitmap
+ */
+static inline unsigned long make_mmu_index_bitmap(va_list args)
+{
+    unsigned long bitmap = 0;
+    int mmu_index = va_arg(args, int);
+
+    /* An empty va_list would be a bad call */
+    g_assert(mmu_index > 0);
+
+    do {
+        set_bit(mmu_index, &bitmap);
+        mmu_index = va_arg(args, int);
+    } while (mmu_index >= 0);
+
+    return bitmap;
+}
+
 void tlb_flush_by_mmuidx(CPUState *cpu, ...)
 {
     va_list argp;
+    unsigned long mmu_idx_bitmap;
+
     va_start(argp, cpu);
-    v_tlb_flush_by_mmuidx(cpu, argp);
+    mmu_idx_bitmap = make_mmu_index_bitmap(argp);
     va_end(argp);
+
+    tlb_debug("mmu_idx: 0x%04lx\n", mmu_idx_bitmap);
+
+    if (!qemu_cpu_is_self(cpu)) {
+        uint16_t pending_flushes =
+            mmu_idx_bitmap & ~atomic_mb_read(&cpu->pending_tlb_flush);
+        if (pending_flushes) {
+            tlb_debug("reduced mmu_idx: 0x%" PRIx16 "\n", pending_flushes);
+
+            atomic_or(&cpu->pending_tlb_flush, pending_flushes);
+            async_run_on_cpu(cpu, tlb_flush_by_mmuidx_async_work,
+                             host_int(pending_flushes));
+        }
+    } else {
+        tlb_flush_by_mmuidx_async_work(cpu, host_ulong(mmu_idx_bitmap));
+    }
 }
 
 static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
@@ -233,16 +288,50 @@ void tlb_flush_page(CPUState *cpu, target_ulong addr)
     }
 }
 
-void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, ...)
+/* As we are going to hijack the bottom bits of the page address for a
+ * mmuidx bit mask we need to fail to build if we can't do that
+ */
+QEMU_BUILD_BUG_ON(NB_MMU_MODES > TARGET_PAGE_BITS);
+
+static void tlb_flush_page_by_mmuidx_async_work(CPUState *cpu,
+                                                run_on_cpu_data data)
 {
     CPUArchState *env = cpu->env_ptr;
-    int i, k;
-    va_list argp;
-
-    va_start(argp, addr);
+    target_ulong addr_and_mmuidx = (target_ulong) data.target_ptr;
+    target_ulong addr = addr_and_mmuidx & TARGET_PAGE_MASK;
+    unsigned long mmu_idx_bitmap = addr_and_mmuidx & ALL_MMUIDX_BITS;
+    int page = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+    int mmu_idx;
+    int i;
 
     assert_cpu_is_self(cpu);
-    tlb_debug("addr "TARGET_FMT_lx"\n", addr);
+
+    tlb_debug("page:%d addr:"TARGET_FMT_lx" mmu_idx%" PRIxPTR "\n",
+              page, addr, mmu_idx_bitmap);
+
+    for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
+        if (test_bit(mmu_idx, &mmu_idx_bitmap)) {
+            tlb_flush_entry(&env->tlb_table[mmu_idx][page], addr);
+
+            /* check whether there are vltb entries that need to be flushed */
+            for (i = 0; i < CPU_VTLB_SIZE; i++) {
+                tlb_flush_entry(&env->tlb_v_table[mmu_idx][i], addr);
+            }
+        }
+    }
+
+    tb_flush_jmp_cache(cpu, addr);
+}
+
+static void tlb_check_page_and_flush_by_mmuidx_async_work(CPUState *cpu,
+                                                          run_on_cpu_data data)
+{
+    CPUArchState *env = cpu->env_ptr;
+    target_ulong addr_and_mmuidx = (target_ulong) data.target_ptr;
+    target_ulong addr = addr_and_mmuidx & TARGET_PAGE_MASK;
+    unsigned long mmu_idx_bitmap = addr_and_mmuidx & ALL_MMUIDX_BITS;
+
+    tlb_debug("addr:"TARGET_FMT_lx" mmu_idx: %04lx\n", addr, mmu_idx_bitmap);
 
     /* Check if we need to flush due to large pages.  */
     if ((addr & env->tlb_flush_mask) == env->tlb_flush_addr) {
@@ -250,33 +339,35 @@ void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, ...)
                   TARGET_FMT_lx "/" TARGET_FMT_lx ")\n",
                   env->tlb_flush_addr, env->tlb_flush_mask);
 
-        v_tlb_flush_by_mmuidx(cpu, argp);
-        va_end(argp);
-        return;
+        tlb_flush_by_mmuidx_async_work(cpu, host_ulong(mmu_idx_bitmap));
+    } else {
+        tlb_flush_page_by_mmuidx_async_work(cpu, data);
     }
+}
 
-    addr &= TARGET_PAGE_MASK;
-    i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
-
-    for (;;) {
-        int mmu_idx = va_arg(argp, int);
+void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, ...)
+{
+    unsigned long mmu_idx_bitmap;
+    target_ulong addr_and_mmu_idx;
+    va_list argp;
 
-        if (mmu_idx < 0) {
-            break;
-        }
+    va_start(argp, addr);
+    mmu_idx_bitmap = make_mmu_index_bitmap(argp);
+    va_end(argp);
 
-        tlb_debug("idx %d\n", mmu_idx);
+    tlb_debug("addr: "TARGET_FMT_lx" mmu_idx:%lx\n", addr, mmu_idx_bitmap);
 
-        tlb_flush_entry(&env->tlb_table[mmu_idx][i], addr);
+    /* This should already be page aligned */
+    addr_and_mmu_idx = addr & TARGET_PAGE_MASK;
+    addr_and_mmu_idx |= mmu_idx_bitmap;
 
-        /* check whether there are vltb entries that need to be flushed */
-        for (k = 0; k < CPU_VTLB_SIZE; k++) {
-            tlb_flush_entry(&env->tlb_v_table[mmu_idx][k], addr);
-        }
+    if (!qemu_cpu_is_self(cpu)) {
+        async_run_on_cpu(cpu, tlb_check_page_and_flush_by_mmuidx_async_work,
+                         target_ptr(addr_and_mmu_idx));
+    } else {
+        tlb_check_page_and_flush_by_mmuidx_async_work(
+            cpu, target_ptr(addr_and_mmu_idx));
     }
-    va_end(argp);
-
-    tb_flush_jmp_cache(cpu, addr);
 }
 
 void tlb_flush_page_all(target_ulong addr)
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 1fe5b99..4faf795 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -238,6 +238,7 @@ struct kvm_run;
 typedef union {
     int       host_int;
     unsigned  host_unsigned;
+    unsigned long host_unsigned_long;
     uintptr_t host_ptr;
     void      *void_ptr;  /* for (run_on_cpu_data) NULL casts */
     vaddr     target_ptr;
@@ -391,17 +392,17 @@ struct CPUState {
      */
     bool throttle_thread_scheduled;
 
+    /* The pending_tlb_flush flag is set and cleared atomically to
+     * avoid potential races. The aim of the flag is to avoid
+     * unnecessary flushes.
+     */
+    uint16_t pending_tlb_flush;
+
     /* Note that this is accessed at the start of every TB via a negative
        offset from AREG0.  Leave this field at the end so as to make the
        (absolute value) offset as small as possible.  This reduces code
        size, especially for hosts without large memory offsets.  */
     uint32_t tcg_exit_req;
-
-    /* The pending_tlb_flush flag is set and cleared atomically to
-     * avoid potential races. The aim of the flag is to avoid
-     * unnecessary flushes.
-     */
-    bool pending_tlb_flush;
 };
 
 QTAILQ_HEAD(CPUTailQ, CPUState);
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 29/33] target-arm/powerctl: defer cpu reset work to CPU context
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (27 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 28/33] cputlb: make tlb_flush_by_mmuidx safe for MTTCG Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 30/33] target-arm/cpu: don't reset TLB structures, use cputlb to do it Alex Bennée
                   ` (4 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, open list:ARM

When switching a new vCPU on we want to complete a bunch of the setup
work before we start scheduling the vCPU thread. To do this cleanly we
defer vCPU setup to async work which will run the vCPUs execution
context as the thread is woken up. The scheduling of the work will kick
the vCPU awake.

This avoids potential races in MTTCG system emulation.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target-arm/arm-powerctl.c | 144 +++++++++++++++++++++++++++-------------------
 1 file changed, 86 insertions(+), 58 deletions(-)

diff --git a/target-arm/arm-powerctl.c b/target-arm/arm-powerctl.c
index fbb7a15..0ef4b29 100644
--- a/target-arm/arm-powerctl.c
+++ b/target-arm/arm-powerctl.c
@@ -48,11 +48,85 @@ CPUState *arm_get_cpu_by_id(uint64_t id)
     return NULL;
 }
 
+struct cpu_on_info {
+    uint64_t entry;
+    uint64_t context_id;
+    uint32_t target_el;
+    bool target_aa64;
+};
+
+
+static void arm_set_cpu_on_async_work(CPUState *target_cpu_state,
+                                      run_on_cpu_data data)
+{
+    ARMCPU *target_cpu = ARM_CPU(target_cpu_state);
+    struct cpu_on_info *info = (struct cpu_on_info *) data.host_ptr;
+
+    /* Initialize the cpu we are turning on */
+    cpu_reset(target_cpu_state);
+    target_cpu->powered_off = false;
+    target_cpu_state->halted = 0;
+
+    if (info->target_aa64) {
+        if ((info->target_el < 3) && arm_feature(&target_cpu->env, ARM_FEATURE_EL3)) {
+            /*
+             * As target mode is AArch64, we need to set lower
+             * exception level (the requested level 2) to AArch64
+             */
+            target_cpu->env.cp15.scr_el3 |= SCR_RW;
+        }
+
+        if ((info->target_el < 2) && arm_feature(&target_cpu->env, ARM_FEATURE_EL2)) {
+            /*
+             * As target mode is AArch64, we need to set lower
+             * exception level (the requested level 1) to AArch64
+             */
+            target_cpu->env.cp15.hcr_el2 |= HCR_RW;
+        }
+
+        target_cpu->env.pstate = aarch64_pstate_mode(info->target_el, true);
+    } else {
+        /* We are requested to boot in AArch32 mode */
+        static uint32_t mode_for_el[] = { 0,
+                                          ARM_CPU_MODE_SVC,
+                                          ARM_CPU_MODE_HYP,
+                                          ARM_CPU_MODE_SVC };
+
+        cpsr_write(&target_cpu->env, mode_for_el[info->target_el], CPSR_M,
+                   CPSRWriteRaw);
+    }
+
+    if (info->target_el == 3) {
+        /* Processor is in secure mode */
+        target_cpu->env.cp15.scr_el3 &= ~SCR_NS;
+    } else {
+        /* Processor is not in secure mode */
+        target_cpu->env.cp15.scr_el3 |= SCR_NS;
+    }
+
+    /* We check if the started CPU is now at the correct level */
+    assert(info->target_el == arm_current_el(&target_cpu->env));
+
+    if (info->target_aa64) {
+        target_cpu->env.xregs[0] = info->context_id;
+        target_cpu->env.thumb = false;
+    } else {
+        target_cpu->env.regs[0] = info->context_id;
+        target_cpu->env.thumb = info->entry & 1;
+        info->entry &= 0xfffffffe;
+    }
+
+    /* Start the new CPU at the requested address */
+    cpu_set_pc(target_cpu_state, info->entry);
+    g_free(info);
+}
+
 int arm_set_cpu_on(uint64_t cpuid, uint64_t entry, uint64_t context_id,
                    uint32_t target_el, bool target_aa64)
 {
     CPUState *target_cpu_state;
     ARMCPU *target_cpu;
+    struct cpu_on_info *info;
 
     DPRINTF("cpu %" PRId64 " (EL %d, %s) @ 0x%" PRIx64 " with R0 = 0x%" PRIx64
             "\n", cpuid, target_el, target_aa64 ? "aarch64" : "aarch32", entry,
@@ -109,64 +183,18 @@ int arm_set_cpu_on(uint64_t cpuid, uint64_t entry, uint64_t context_id,
         return QEMU_ARM_POWERCTL_INVALID_PARAM;
     }
 
-    /* Initialize the cpu we are turning on */
-    cpu_reset(target_cpu_state);
-    target_cpu->powered_off = false;
-    target_cpu_state->halted = 0;
-
-    if (target_aa64) {
-        if ((target_el < 3) && arm_feature(&target_cpu->env, ARM_FEATURE_EL3)) {
-            /*
-             * As target mode is AArch64, we need to set lower
-             * exception level (the requested level 2) to AArch64
-             */
-            target_cpu->env.cp15.scr_el3 |= SCR_RW;
-        }
-
-        if ((target_el < 2) && arm_feature(&target_cpu->env, ARM_FEATURE_EL2)) {
-            /*
-             * As target mode is AArch64, we need to set lower
-             * exception level (the requested level 1) to AArch64
-             */
-            target_cpu->env.cp15.hcr_el2 |= HCR_RW;
-        }
-
-        target_cpu->env.pstate = aarch64_pstate_mode(target_el, true);
-    } else {
-        /* We are requested to boot in AArch32 mode */
-        static uint32_t mode_for_el[] = { 0,
-                                          ARM_CPU_MODE_SVC,
-                                          ARM_CPU_MODE_HYP,
-                                          ARM_CPU_MODE_SVC };
-
-        cpsr_write(&target_cpu->env, mode_for_el[target_el], CPSR_M,
-                   CPSRWriteRaw);
-    }
-
-    if (target_el == 3) {
-        /* Processor is in secure mode */
-        target_cpu->env.cp15.scr_el3 &= ~SCR_NS;
-    } else {
-        /* Processor is not in secure mode */
-        target_cpu->env.cp15.scr_el3 |= SCR_NS;
-    }
-
-    /* We check if the started CPU is now at the correct level */
-    assert(target_el == arm_current_el(&target_cpu->env));
-
-    if (target_aa64) {
-        target_cpu->env.xregs[0] = context_id;
-        target_cpu->env.thumb = false;
-    } else {
-        target_cpu->env.regs[0] = context_id;
-        target_cpu->env.thumb = entry & 1;
-        entry &= 0xfffffffe;
-    }
-
-    /* Start the new CPU at the requested address */
-    cpu_set_pc(target_cpu_state, entry);
-
-    qemu_cpu_kick(target_cpu_state);
+    /* To avoid racing with a CPU we are just kicking off we do the
+     * final bit of preparation for the work in the target CPUs
+     * context.
+     */
+    info = g_new(struct cpu_on_info, 1);
+    info->entry = entry;
+    info->context_id = context_id;
+    info->target_el = target_el;
+    info->target_aa64 = target_aa64;
+
+    async_run_on_cpu(target_cpu_state, arm_set_cpu_on_async_work,
+                     RUN_ON_CPU_HOST_PTR(info));
 
     /* We are good to go */
     return QEMU_ARM_POWERCTL_RET_SUCCESS;
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 30/33] target-arm/cpu: don't reset TLB structures, use cputlb to do it
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (28 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 29/33] target-arm/powerctl: defer cpu reset work to CPU context Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 16:10   ` Richard Henderson
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 31/33] target-arm: ensure BQL taken for ARM_CP_IO register access Alex Bennée
                   ` (3 subsequent siblings)
  33 siblings, 1 reply; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, open list:ARM

cputlb owns the TLB entries and knows how to safely update them in
MTTCG.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target-arm/cpu.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 1b9540e..ff8c594 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -121,7 +121,13 @@ static void arm_cpu_reset(CPUState *s)
 
     acc->parent_reset(s);
 
+#ifdef CONFIG_SOFTMMU
+    memset(env, 0, offsetof(CPUARMState, tlb_table));
+    tlb_flush(s, 0);
+#else
     memset(env, 0, offsetof(CPUARMState, features));
+#endif
+
     g_hash_table_foreach(cpu->cp_regs, cp_reg_reset, cpu);
     g_hash_table_foreach(cpu->cp_regs, cp_reg_check_reset, cpu);
 
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 31/33] target-arm: ensure BQL taken for ARM_CP_IO register access
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (29 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 30/33] target-arm/cpu: don't reset TLB structures, use cputlb to do it Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 32/33] target-arm: helpers which may affect global state need the BQL Alex Bennée
                   ` (2 subsequent siblings)
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, open list:ARM cores

Most ARMCPRegInfo structures just allow updating of the CPU field.
However some have more complex operations that *may* be have cross vCPU
effects therefor need to be serialised. The most obvious examples at the
moment are things that affect the GICv3 IRQ controller. To avoid
applying this requirement to all registers with custom access functions
we check for if the type is marked ARM_CP_IO.

By default all MMIO access to devices already takes the BQL to serialise
hardware emulation.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 hw/intc/arm_gicv3_cpuif.c |  3 +++
 target-arm/op_helper.c    | 39 +++++++++++++++++++++++++++++++++++----
 2 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index bca30c4..8ea4b5b 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -13,6 +13,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/main-loop.h"
 #include "trace.h"
 #include "gicv3_internal.h"
 #include "cpu.h"
@@ -128,6 +129,8 @@ void gicv3_cpuif_update(GICv3CPUState *cs)
     ARMCPU *cpu = ARM_CPU(cs->cpu);
     CPUARMState *env = &cpu->env;
 
+    g_assert(qemu_mutex_iothread_locked());
+
     trace_gicv3_cpuif_update(gicv3_redist_affid(cs), cs->hppi.irq,
                              cs->hppi.grp, cs->hppi.prio);
 
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index cd94216..4f0c754 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -17,6 +17,7 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "qemu/osdep.h"
+#include "qemu/main-loop.h"
 #include "cpu.h"
 #include "exec/helper-proto.h"
 #include "internals.h"
@@ -734,28 +735,58 @@ void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value)
 {
     const ARMCPRegInfo *ri = rip;
 
-    ri->writefn(env, ri, value);
+    if (ri->type & ARM_CP_IO) {
+        qemu_mutex_lock_iothread();
+        ri->writefn(env, ri, value);
+        qemu_mutex_unlock_iothread();
+    } else {
+        ri->writefn(env, ri, value);
+    }
 }
 
 uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip)
 {
     const ARMCPRegInfo *ri = rip;
+    uint32_t res;
 
-    return ri->readfn(env, ri);
+    if (ri->type & ARM_CP_IO) {
+        qemu_mutex_lock_iothread();
+        res = ri->readfn(env, ri);
+        qemu_mutex_unlock_iothread();
+    } else {
+        res = ri->readfn(env, ri);
+    }
+
+    return res;
 }
 
 void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value)
 {
     const ARMCPRegInfo *ri = rip;
 
-    ri->writefn(env, ri, value);
+    if (ri->type & ARM_CP_IO) {
+        qemu_mutex_lock_iothread();
+        ri->writefn(env, ri, value);
+        qemu_mutex_unlock_iothread();
+    } else {
+        ri->writefn(env, ri, value);
+    }
 }
 
 uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip)
 {
     const ARMCPRegInfo *ri = rip;
+    uint64_t res;
+
+    if (ri->type & ARM_CP_IO) {
+        qemu_mutex_lock_iothread();
+        res = ri->readfn(env, ri);
+        qemu_mutex_unlock_iothread();
+    } else {
+        res = ri->readfn(env, ri);
+    }
 
-    return ri->readfn(env, ri);
+    return res;
 }
 
 void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 32/33] target-arm: helpers which may affect global state need the BQL
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (30 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 31/33] target-arm: ensure BQL taken for ARM_CP_IO register access Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 33/33] tcg: enable MTTCG by default for ARM on x86 hosts Alex Bennée
  2016-10-31  8:03 ` [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée, open list:ARM

As the arm_call_el_change_hook may affect global state (for example with
updating the global GIC state) we need to assert/take the BQL.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target-arm/helper.c    | 6 ++++++
 target-arm/op_helper.c | 4 ++++
 2 files changed, 10 insertions(+)

diff --git a/target-arm/helper.c b/target-arm/helper.c
index cb83ee2..ad93926 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -6662,6 +6662,12 @@ void arm_cpu_do_interrupt(CPUState *cs)
         arm_cpu_do_interrupt_aarch32(cs);
     }
 
+    /* Hooks may change global state so BQL should be held, also the
+     * BQL needs to be held for any modification of
+     * cs->interrupt_request.
+     */
+    g_assert(qemu_mutex_iothread_locked());
+
     arm_call_el_change_hook(cpu);
 
     if (!kvm_enabled()) {
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 4f0c754..41beabc 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -487,7 +487,9 @@ void HELPER(cpsr_write_eret)(CPUARMState *env, uint32_t val)
      */
     env->regs[15] &= (env->thumb ? ~1 : ~3);
 
+    qemu_mutex_lock_iothread();
     arm_call_el_change_hook(arm_env_get_cpu(env));
+    qemu_mutex_unlock_iothread();
 }
 
 /* Access to user mode registers from privileged modes.  */
@@ -1013,7 +1015,9 @@ void HELPER(exception_return)(CPUARMState *env)
         env->pc = env->elr_el[cur_el];
     }
 
+    qemu_mutex_lock_iothread();
     arm_call_el_change_hook(arm_env_get_cpu(env));
+    qemu_mutex_unlock_iothread();
 
     return;
 
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH v5 33/33] tcg: enable MTTCG by default for ARM on x86 hosts
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (31 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 32/33] target-arm: helpers which may affect global state need the BQL Alex Bennée
@ 2016-10-27 15:10 ` Alex Bennée
  2016-10-31  8:03 ` [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
  33 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:10 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Alex Bennée

This enables the multi-threaded system emulation by default for ARMv7
and ARMv8 guests using the x86_64 TCG backend. This means:

  - The x86_64 TCG backend supports cmpxchg based atomic ops
  - The x86_64 TCG backend emits barriers for barrier ops

And on the guest side:

  - The ARM translate.c/translate-64.c have been converted to
    - use MTTCG safe atomic primitives
    - emit the appropriate barrier ops
  - The ARM machine has been updated to
    - hold the BQL when modifying shared cross-vCPU state
    - defer cpu_reset to async safe work

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 configure                       | 12 ++++++++++++
 default-configs/arm-softmmu.mak |  2 ++
 2 files changed, 14 insertions(+)

diff --git a/configure b/configure
index 91a14c1..2043436 100755
--- a/configure
+++ b/configure
@@ -515,6 +515,7 @@ else
 fi
 
 ARCH=
+host_mttcg_support=
 # Normalise host CPU name and set ARCH.
 # Note that this case should only have supported host CPUs, not guests.
 case "$cpu" in
@@ -526,6 +527,7 @@ case "$cpu" in
   ;;
   x86_64|amd64)
     cpu="x86_64"
+    host_mttcg_support=yes
   ;;
   armv*b|armv*l|arm)
     cpu="arm"
@@ -5614,6 +5616,10 @@ if test "$pthread_setname_np" = "yes" ; then
   echo "CONFIG_PTHREAD_SETNAME_NP=y" >> $config_host_mak
 fi
 
+if test "$host_mttcg_support" = "yes" ; then
+  echo "CONFIG_MTTCG_HOST=y" >> $config_host_mak
+fi
+
 if test "$tcg_interpreter" = "yes"; then
   QEMU_INCLUDES="-I\$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
 elif test "$ARCH" = "sparc64" ; then
@@ -5726,6 +5732,7 @@ target_dir="$target"
 config_target_mak=$target_dir/config-target.mak
 target_name=$(echo $target | cut -d '-' -f 1)
 target_bigendian="no"
+target_mttcg_support="no"
 
 case "$target_name" in
   armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or32|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb)
@@ -5783,11 +5790,13 @@ case "$target_name" in
     TARGET_ARCH=arm
     bflt="yes"
     gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml"
+    target_mttcg_support="yes"
   ;;
   aarch64)
     TARGET_BASE_ARCH=arm
     bflt="yes"
     gdb_xml_files="aarch64-core.xml aarch64-fpu.xml arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml"
+    target_mttcg_support="yes"
   ;;
   cris)
   ;;
@@ -5938,6 +5947,9 @@ if test "$target_bigendian" = "yes" ; then
 fi
 if test "$target_softmmu" = "yes" ; then
   echo "CONFIG_SOFTMMU=y" >> $config_target_mak
+  if test "$target_mttcg_support" = "yes" ; then
+    echo "CONFIG_MTTCG_TARGET=y" >> $config_target_mak
+  fi
 fi
 if test "$target_user_only" = "yes" ; then
   echo "CONFIG_USER_ONLY=y" >> $config_target_mak
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 6de3e16..007f751 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -115,3 +115,5 @@ CONFIG_ACPI=y
 CONFIG_SMBIOS=y
 CONFIG_ASPEED_SOC=y
 CONFIG_GPIO_KEY=y
+
+CONFIG_MTTCG_TARGET=y
-- 
2.10.1

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH v5 14/33] tcg: add kick timer for single-threaded vCPU emulation
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 14/33] tcg: add kick timer for single-threaded vCPU emulation Alex Bennée
@ 2016-10-27 15:30   ` KONRAD Frederic
  2016-10-27 15:35     ` Alex Bennée
  0 siblings, 1 reply; 48+ messages in thread
From: KONRAD Frederic @ 2016-10-27 15:30 UTC (permalink / raw)
  To: Alex Bennée
  Cc: pbonzini, qemu-devel, mttcg, a.rigo, cota, bobby.prani, nikunj,
	mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Peter Crosthwaite

Hi Alex,

This is nice! Do we actually need to do qemu_cpu_kick_no_halt() in the
timer handler?

Thanks,
Fred

Le 27/10/2016 à 17:10, Alex Bennée a écrit :
> Currently we rely on the side effect of the main loop grabbing the
> iothread_mutex to give any long running basic block chains a kick to
> ensure the next vCPU is scheduled. As this code is being re-factored and
> rationalised we now do it explicitly here.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>
> ---
> v2
>   - re-base fixes
>   - get_ticks_per_sec() -> NANOSECONDS_PER_SEC
> v3
>   - add define for TCG_KICK_FREQ
>   - fix checkpatch warning
> v4
>   - wrap next calc in inline qemu_tcg_next_kick() instead of macro
> v5
>   - move all kick code into own section
>   - use global for timer
>   - add helper functions to start/stop timer
>   - stop timer when all cores paused
> ---
>  cpus.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 60 insertions(+)
>
> diff --git a/cpus.c b/cpus.c
> index aedec7c..ad4ab68 100644
> --- a/cpus.c
> +++ b/cpus.c
> @@ -735,6 +735,52 @@ void configure_icount(QemuOpts *opts, Error **errp)
>  }
>
>  /***********************************************************/
> +/* TCG vCPU kick timer
> + *
> + * The kick timer is responsible for moving single threaded vCPU
> + * emulation on to the next vCPU. If more than one vCPU is running a
> + * timer event with force a cpu->exit so the next vCPU can get
> + * scheduled.
> + *
> + * The timer is removed if all vCPUs are idle and restarted again once
> + * idleness is complete.
> + */
> +
> +static QEMUTimer *tcg_kick_vcpu_timer;
> +
> +static void qemu_cpu_kick_no_halt(void);
> +
> +#define TCG_KICK_PERIOD (NANOSECONDS_PER_SECOND / 10)
> +
> +static inline int64_t qemu_tcg_next_kick(void)
> +{
> +    return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + TCG_KICK_PERIOD;
> +}
> +
> +static void kick_tcg_thread(void *opaque)
> +{
> +    timer_mod(tcg_kick_vcpu_timer, qemu_tcg_next_kick());
> +    qemu_cpu_kick_no_halt();
> +}
> +
> +static void start_tcg_kick_timer(void)
> +{
> +    if (!tcg_kick_vcpu_timer && CPU_NEXT(first_cpu)) {
> +        tcg_kick_vcpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,  kick_tcg_thread, NULL);
> +        timer_mod(tcg_kick_vcpu_timer, qemu_tcg_next_kick());
> +    }
> +}
> +
> +static void stop_tcg_kick_timer(void)
> +{
> +    if (tcg_kick_vcpu_timer) {
> +        timer_del(tcg_kick_vcpu_timer);
> +        tcg_kick_vcpu_timer = NULL;
> +    }
> +}
> +
> +
> +/***********************************************************/
>  void hw_error(const char *fmt, ...)
>  {
>      va_list ap;
> @@ -988,9 +1034,12 @@ static void qemu_wait_io_event_common(CPUState *cpu)
>  static void qemu_tcg_wait_io_event(CPUState *cpu)
>  {
>      while (all_cpu_threads_idle()) {
> +        stop_tcg_kick_timer();
>          qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex);
>      }
>
> +    start_tcg_kick_timer();
> +
>      while (iothread_requesting_mutex) {
>          qemu_cond_wait(&qemu_io_proceeded_cond, &qemu_global_mutex);
>      }
> @@ -1178,6 +1227,15 @@ static void deal_with_unplugged_cpus(void)
>      }
>  }
>
> +/* Single-threaded TCG
> + *
> + * In the single-threaded case each vCPU is simulated in turn. If
> + * there is more than a single vCPU we create a simple timer to kick
> + * the vCPU and ensure we don't get stuck in a tight loop in one vCPU.
> + * This is done explicitly rather than relying on side-effects
> + * elsewhere.
> + */
> +
>  static void *qemu_tcg_cpu_thread_fn(void *arg)
>  {
>      CPUState *cpu = arg;
> @@ -1204,6 +1262,8 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
>          }
>      }
>
> +    start_tcg_kick_timer();
> +
>      /* process any pending work */
>      atomic_mb_set(&exit_request, 1);
>
>

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH v5 14/33] tcg: add kick timer for single-threaded vCPU emulation
  2016-10-27 15:30   ` KONRAD Frederic
@ 2016-10-27 15:35     ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-27 15:35 UTC (permalink / raw)
  To: KONRAD Frederic
  Cc: pbonzini, qemu-devel, mttcg, a.rigo, cota, bobby.prani, nikunj,
	mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Peter Crosthwaite


KONRAD Frederic <fred.konrad@greensocs.com> writes:

> Hi Alex,
>
> This is nice! Do we actually need to do qemu_cpu_kick_no_halt() in the
> timer handler?

It becomes qemu_cpu_kick_rr_cpu() in later patches and joins the rest of
this code.

>
> Thanks,
> Fred
>
> Le 27/10/2016 à 17:10, Alex Bennée a écrit :
>> Currently we rely on the side effect of the main loop grabbing the
>> iothread_mutex to give any long running basic block chains a kick to
>> ensure the next vCPU is scheduled. As this code is being re-factored and
>> rationalised we now do it explicitly here.
>>
>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>>
>> ---
>> v2
>>   - re-base fixes
>>   - get_ticks_per_sec() -> NANOSECONDS_PER_SEC
>> v3
>>   - add define for TCG_KICK_FREQ
>>   - fix checkpatch warning
>> v4
>>   - wrap next calc in inline qemu_tcg_next_kick() instead of macro
>> v5
>>   - move all kick code into own section
>>   - use global for timer
>>   - add helper functions to start/stop timer
>>   - stop timer when all cores paused
>> ---
>>  cpus.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 60 insertions(+)
>>
>> diff --git a/cpus.c b/cpus.c
>> index aedec7c..ad4ab68 100644
>> --- a/cpus.c
>> +++ b/cpus.c
>> @@ -735,6 +735,52 @@ void configure_icount(QemuOpts *opts, Error **errp)
>>  }
>>
>>  /***********************************************************/
>> +/* TCG vCPU kick timer
>> + *
>> + * The kick timer is responsible for moving single threaded vCPU
>> + * emulation on to the next vCPU. If more than one vCPU is running a
>> + * timer event with force a cpu->exit so the next vCPU can get
>> + * scheduled.
>> + *
>> + * The timer is removed if all vCPUs are idle and restarted again once
>> + * idleness is complete.
>> + */
>> +
>> +static QEMUTimer *tcg_kick_vcpu_timer;
>> +
>> +static void qemu_cpu_kick_no_halt(void);
>> +
>> +#define TCG_KICK_PERIOD (NANOSECONDS_PER_SECOND / 10)
>> +
>> +static inline int64_t qemu_tcg_next_kick(void)
>> +{
>> +    return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + TCG_KICK_PERIOD;
>> +}
>> +
>> +static void kick_tcg_thread(void *opaque)
>> +{
>> +    timer_mod(tcg_kick_vcpu_timer, qemu_tcg_next_kick());
>> +    qemu_cpu_kick_no_halt();
>> +}
>> +
>> +static void start_tcg_kick_timer(void)
>> +{
>> +    if (!tcg_kick_vcpu_timer && CPU_NEXT(first_cpu)) {
>> +        tcg_kick_vcpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,  kick_tcg_thread, NULL);
>> +        timer_mod(tcg_kick_vcpu_timer, qemu_tcg_next_kick());
>> +    }
>> +}
>> +
>> +static void stop_tcg_kick_timer(void)
>> +{
>> +    if (tcg_kick_vcpu_timer) {
>> +        timer_del(tcg_kick_vcpu_timer);
>> +        tcg_kick_vcpu_timer = NULL;
>> +    }
>> +}
>> +
>> +
>> +/***********************************************************/
>>  void hw_error(const char *fmt, ...)
>>  {
>>      va_list ap;
>> @@ -988,9 +1034,12 @@ static void qemu_wait_io_event_common(CPUState *cpu)
>>  static void qemu_tcg_wait_io_event(CPUState *cpu)
>>  {
>>      while (all_cpu_threads_idle()) {
>> +        stop_tcg_kick_timer();
>>          qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex);
>>      }
>>
>> +    start_tcg_kick_timer();
>> +
>>      while (iothread_requesting_mutex) {
>>          qemu_cond_wait(&qemu_io_proceeded_cond, &qemu_global_mutex);
>>      }
>> @@ -1178,6 +1227,15 @@ static void deal_with_unplugged_cpus(void)
>>      }
>>  }
>>
>> +/* Single-threaded TCG
>> + *
>> + * In the single-threaded case each vCPU is simulated in turn. If
>> + * there is more than a single vCPU we create a simple timer to kick
>> + * the vCPU and ensure we don't get stuck in a tight loop in one vCPU.
>> + * This is done explicitly rather than relying on side-effects
>> + * elsewhere.
>> + */
>> +
>>  static void *qemu_tcg_cpu_thread_fn(void *arg)
>>  {
>>      CPUState *cpu = arg;
>> @@ -1204,6 +1262,8 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
>>          }
>>      }
>>
>> +    start_tcg_kick_timer();
>> +
>>      /* process any pending work */
>>      atomic_mb_set(&exit_request, 1);
>>
>>


--
Alex Bennée

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH v5 30/33] target-arm/cpu: don't reset TLB structures, use cputlb to do it
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 30/33] target-arm/cpu: don't reset TLB structures, use cputlb to do it Alex Bennée
@ 2016-10-27 16:10   ` Richard Henderson
  2016-10-28  8:38     ` Alex Bennée
  0 siblings, 1 reply; 48+ messages in thread
From: Richard Henderson @ 2016-10-27 16:10 UTC (permalink / raw)
  To: Alex Bennée, pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, peter.maydell,
	claudio.fontana, open list:ARM

On 10/27/2016 08:10 AM, Alex Bennée wrote:
> cputlb owns the TLB entries and knows how to safely update them in
> MTTCG.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  target-arm/cpu.c | 6 ++++++
>  1 file changed, 6 insertions(+)
>
> diff --git a/target-arm/cpu.c b/target-arm/cpu.c
> index 1b9540e..ff8c594 100644
> --- a/target-arm/cpu.c
> +++ b/target-arm/cpu.c
> @@ -121,7 +121,13 @@ static void arm_cpu_reset(CPUState *s)
>
>      acc->parent_reset(s);
>
> +#ifdef CONFIG_SOFTMMU
> +    memset(env, 0, offsetof(CPUARMState, tlb_table));
> +    tlb_flush(s, 0);
> +#else
>      memset(env, 0, offsetof(CPUARMState, features));
> +#endif
> +

Why special case this for softmmu?  And don't we (or if not, shouldn't we) 
handle the tlb_flush generically for reset?


r~

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH v5 30/33] target-arm/cpu: don't reset TLB structures, use cputlb to do it
  2016-10-27 16:10   ` Richard Henderson
@ 2016-10-28  8:38     ` Alex Bennée
  2016-10-28  9:07       ` Peter Maydell
  0 siblings, 1 reply; 48+ messages in thread
From: Alex Bennée @ 2016-10-28  8:38 UTC (permalink / raw)
  To: Richard Henderson
  Cc: pbonzini, qemu-devel, mttcg, fred.konrad, a.rigo, cota,
	bobby.prani, nikunj, mark.burton, jan.kiszka, serge.fdrv,
	peter.maydell, claudio.fontana, open list:ARM


Richard Henderson <rth@twiddle.net> writes:

> On 10/27/2016 08:10 AM, Alex Bennée wrote:
>> cputlb owns the TLB entries and knows how to safely update them in
>> MTTCG.
>>
>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>> ---
>>  target-arm/cpu.c | 6 ++++++
>>  1 file changed, 6 insertions(+)
>>
>> diff --git a/target-arm/cpu.c b/target-arm/cpu.c
>> index 1b9540e..ff8c594 100644
>> --- a/target-arm/cpu.c
>> +++ b/target-arm/cpu.c
>> @@ -121,7 +121,13 @@ static void arm_cpu_reset(CPUState *s)
>>
>>      acc->parent_reset(s);
>>
>> +#ifdef CONFIG_SOFTMMU
>> +    memset(env, 0, offsetof(CPUARMState, tlb_table));
>> +    tlb_flush(s, 0);
>> +#else
>>      memset(env, 0, offsetof(CPUARMState, features));
>> +#endif
>> +
>
> Why special case this for softmmu?

I didn't want to move cpu->features to the other side of CPU_COMMON in
cpu.h as there is an explicit statement about being reset. Adding
another variable just to be an endpoint of a memset also seemed
sub-optimal.

> And don't we (or if not, shouldn't we)
> handle the tlb_flush generically for reset?

Probably. tlb_flush seems to be one of those things liberally sprinkled
in the arch code for all sorts of things but certainly cpu_reset is one
we could make the call from generic code.

>
>
> r~


--
Alex Bennée

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH v5 30/33] target-arm/cpu: don't reset TLB structures, use cputlb to do it
  2016-10-28  8:38     ` Alex Bennée
@ 2016-10-28  9:07       ` Peter Maydell
  2016-10-28  9:17         ` Alex Bennée
  0 siblings, 1 reply; 48+ messages in thread
From: Peter Maydell @ 2016-10-28  9:07 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Richard Henderson, Paolo Bonzini, QEMU Developers, MTTCG Devel,
	KONRAD Frédéric, Alvise Rigo, Emilio G. Cota,
	Pranith Kumar, Nikunj A Dadhania, Mark Burton, Jan Kiszka,
	Fedorov Sergey, Claudio Fontana, open list:ARM

On 28 October 2016 at 09:38, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> Richard Henderson <rth@twiddle.net> writes:
>> And don't we (or if not, shouldn't we)
>> handle the tlb_flush generically for reset?
>
> Probably. tlb_flush seems to be one of those things liberally sprinkled
> in the arch code for all sorts of things but certainly cpu_reset is one
> we could make the call from generic code.

I think the theory I formed last time I looked at it is that
if your CPU has no state which would require you to flush the
TLB when it changes, then there's no need to flush the TLB
on reset -- any entries still in the TLB from before reset are
still valid after reset. For ARM a CPU reset will reset state
like the ASID and the MMU-enabled bit which require a TLB flush
on change, so we have to call tlb_flush here.

You could argue that the set of CPUs which don't require a
tlb flush on reset are not worth trying to optimise for
like this and we should just do it generically.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH v5 30/33] target-arm/cpu: don't reset TLB structures, use cputlb to do it
  2016-10-28  9:07       ` Peter Maydell
@ 2016-10-28  9:17         ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-10-28  9:17 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Richard Henderson, Paolo Bonzini, QEMU Developers, MTTCG Devel,
	KONRAD Frédéric, Alvise Rigo, Emilio G. Cota,
	Pranith Kumar, Nikunj A Dadhania, Mark Burton, Jan Kiszka,
	Fedorov Sergey, Claudio Fontana, open list:ARM


Peter Maydell <peter.maydell@linaro.org> writes:

> On 28 October 2016 at 09:38, Alex Bennée <alex.bennee@linaro.org> wrote:
>>
>> Richard Henderson <rth@twiddle.net> writes:
>>> And don't we (or if not, shouldn't we)
>>> handle the tlb_flush generically for reset?
>>
>> Probably. tlb_flush seems to be one of those things liberally sprinkled
>> in the arch code for all sorts of things but certainly cpu_reset is one
>> we could make the call from generic code.
>
> I think the theory I formed last time I looked at it is that
> if your CPU has no state which would require you to flush the
> TLB when it changes, then there's no need to flush the TLB
> on reset -- any entries still in the TLB from before reset are
> still valid after reset. For ARM a CPU reset will reset state
> like the ASID and the MMU-enabled bit which require a TLB flush
> on change, so we have to call tlb_flush here.
>
> You could argue that the set of CPUs which don't require a
> tlb flush on reset are not worth trying to optimise for
> like this and we should just do it generically.

Well it can't harm anyone. It would just mean all CPUs whatever their
semantics would have to re-fill the TLBs after a reset. I guess that
might be a concern for reset latency under TCG but I doubt anyone would
notice.

--
Alex Bennée

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults
  2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
                   ` (32 preceding siblings ...)
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 33/33] tcg: enable MTTCG by default for ARM on x86 hosts Alex Bennée
@ 2016-10-31  8:03 ` Alex Bennée
  2016-10-31  8:48   ` Paolo Bonzini
  33 siblings, 1 reply; 48+ messages in thread
From: Alex Bennée @ 2016-10-31  8:03 UTC (permalink / raw)
  To: pbonzini
  Cc: qemu-devel, mttcg, fred.konrad, a.rigo, cota, bobby.prani,
	nikunj, mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana


Alex Bennée <alex.bennee@linaro.org> writes:

> This is the fifth iteration of the MTTCG patches and I'm finally
> dropping the RFC tag from the series.

Paolo,

Apologies for the needy ping but is there any chance of at least a
subset of this series making it into a pull-req today? I appreciate I've
run up against the looming freeze tomorrow so would like to reduce as much
of the delta as possible if we can't merged the series.

Regards,

--
Alex Bennée

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults
  2016-10-31  8:03 ` [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
@ 2016-10-31  8:48   ` Paolo Bonzini
  0 siblings, 0 replies; 48+ messages in thread
From: Paolo Bonzini @ 2016-10-31  8:48 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, mttcg, fred konrad, a rigo, cota, bobby prani,
	nikunj, mark burton, jan kiszka, serge fdrv, rth, peter maydell,
	claudio fontana

> Paolo,
> 
> Apologies for the needy ping but is there any chance of at least a
> subset of this series making it into a pull-req today? I appreciate I've
> run up against the looming freeze tomorrow so would like to reduce as much
> of the delta as possible if we can't merged the series.

Yes, I'm going to include as much as possible.

Paolo

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH v5 28/33] cputlb: make tlb_flush_by_mmuidx safe for MTTCG
  2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 28/33] cputlb: make tlb_flush_by_mmuidx safe for MTTCG Alex Bennée
@ 2016-11-01  5:20   ` Pranith Kumar
  2016-11-01  7:45     ` Alex Bennée
  0 siblings, 1 reply; 48+ messages in thread
From: Pranith Kumar @ 2016-11-01  5:20 UTC (permalink / raw)
  To: Alex Bennée
  Cc: pbonzini, qemu-devel, mttcg, fred.konrad, a.rigo, cota, nikunj,
	mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Peter Crosthwaite


Hi Alex,

Alex Bennée writes:

> These flushes allow a per-mmuidx granularity to the TLB flushing and are
> currently only used by the ARM model. As it is possible to hammer the
> other vCPU threads with flushes (and build up long queues of identical
> flushes) we extend mechanism used for the global tlb_flush and set a
> bitmap describing all the pending flushes. The updates are done
> atomically to avoid corruption of the bitmap but repeating a flush is
> certainly not a problem.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

<snip>

>
>  static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
> @@ -233,16 +288,50 @@ void tlb_flush_page(CPUState *cpu, target_ulong addr)
>      }
>  }
>  
> -void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, ...)
> +/* As we are going to hijack the bottom bits of the page address for a
> + * mmuidx bit mask we need to fail to build if we can't do that
> + */
> +QEMU_BUILD_BUG_ON(NB_MMU_MODES > TARGET_PAGE_BITS);
> +

FYI, this is causing a build error on my system with gcc 6.2.

  CC      aarch64-softmmu/cputlb.o
In file included from /home/pranith/devops/code/qemu/include/qemu/osdep.h:36:0,
                 from /home/pranith/devops/code/qemu/cputlb.c:20:
/home/pranith/devops/code/qemu/include/exec/cpu-all.h:196:26: error: braced-group within expression allowed only inside a function
 #define TARGET_PAGE_BITS ({ assert(target_page_bits_decided); \
                          ^
/home/pranith/devops/code/qemu/include/qemu/compiler.h:89:54: note: in definition of macro ‘QEMU_BUILD_BUG_ON’
     typedef char glue(qemu_build_bug_on__,__LINE__)[(x)?-1:1] __attribute__((unused));
                                                      ^
/home/pranith/devops/code/qemu/cputlb.c:293:34: note: in expansion of macro ‘TARGET_PAGE_BITS’
 QEMU_BUILD_BUG_ON(NB_MMU_MODES > TARGET_PAGE_BITS);
                                  ^~~~~~~~~~~~~~~~
/home/pranith/devops/code/qemu/rules.mak:60: recipe for target 'cputlb.o' failed
make[1]: *** [cputlb.o] Error 1
Makefile:202: recipe for target 'subdir-aarch64-softmmu' failed
make: *** [subdir-aarch64-softmmu] Error 2

Thanks,
--
Pranith

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH v5 28/33] cputlb: make tlb_flush_by_mmuidx safe for MTTCG
  2016-11-01  5:20   ` Pranith Kumar
@ 2016-11-01  7:45     ` Alex Bennée
  2016-11-01  8:03       ` Peter Maydell
  2016-11-01 13:22       ` Pranith Kumar
  0 siblings, 2 replies; 48+ messages in thread
From: Alex Bennée @ 2016-11-01  7:45 UTC (permalink / raw)
  To: Pranith Kumar
  Cc: pbonzini, qemu-devel, mttcg, fred.konrad, a.rigo, cota, nikunj,
	mark.burton, jan.kiszka, serge.fdrv, rth, peter.maydell,
	claudio.fontana, Peter Crosthwaite


Pranith Kumar <bobby.prani@gmail.com> writes:

> Hi Alex,
>
> Alex Bennée writes:
>
>> These flushes allow a per-mmuidx granularity to the TLB flushing and are
>> currently only used by the ARM model. As it is possible to hammer the
>> other vCPU threads with flushes (and build up long queues of identical
>> flushes) we extend mechanism used for the global tlb_flush and set a
>> bitmap describing all the pending flushes. The updates are done
>> atomically to avoid corruption of the bitmap but repeating a flush is
>> certainly not a problem.
>>
>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>
> <snip>
>
>>
>>  static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
>> @@ -233,16 +288,50 @@ void tlb_flush_page(CPUState *cpu, target_ulong addr)
>>      }
>>  }
>>
>> -void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, ...)
>> +/* As we are going to hijack the bottom bits of the page address for a
>> + * mmuidx bit mask we need to fail to build if we can't do that
>> + */
>> +QEMU_BUILD_BUG_ON(NB_MMU_MODES > TARGET_PAGE_BITS);
>> +
>
> FYI, this is causing a build error on my system with gcc 6.2.
>
>   CC      aarch64-softmmu/cputlb.o
> In file included from /home/pranith/devops/code/qemu/include/qemu/osdep.h:36:0,
>                  from /home/pranith/devops/code/qemu/cputlb.c:20:
> /home/pranith/devops/code/qemu/include/exec/cpu-all.h:196:26: error: braced-group within expression allowed only inside a function
>  #define TARGET_PAGE_BITS ({ assert(target_page_bits_decided); \
>                           ^
> /home/pranith/devops/code/qemu/include/qemu/compiler.h:89:54: note: in definition of macro ‘QEMU_BUILD_BUG_ON’
>      typedef char glue(qemu_build_bug_on__,__LINE__)[(x)?-1:1] __attribute__((unused));
>                                                       ^
> /home/pranith/devops/code/qemu/cputlb.c:293:34: note: in expansion of macro ‘TARGET_PAGE_BITS’
>  QEMU_BUILD_BUG_ON(NB_MMU_MODES > TARGET_PAGE_BITS);
>                                   ^~~~~~~~~~~~~~~~
> /home/pranith/devops/code/qemu/rules.mak:60: recipe for target 'cputlb.o' failed
> make[1]: *** [cputlb.o] Error 1
> Makefile:202: recipe for target 'subdir-aarch64-softmmu' failed
> make: *** [subdir-aarch64-softmmu] Error 2

Odd. I'll look into it. What was you configure string and host architecture?

>
> Thanks,


--
Alex Bennée

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH v5 28/33] cputlb: make tlb_flush_by_mmuidx safe for MTTCG
  2016-11-01  7:45     ` Alex Bennée
@ 2016-11-01  8:03       ` Peter Maydell
  2016-11-01 13:22       ` Pranith Kumar
  1 sibling, 0 replies; 48+ messages in thread
From: Peter Maydell @ 2016-11-01  8:03 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Pranith Kumar, Paolo Bonzini, QEMU Developers, MTTCG Devel,
	KONRAD Frédéric, Alvise Rigo, Emilio G. Cota,
	Nikunj A Dadhania, Mark Burton, Jan Kiszka, Fedorov Sergey,
	Richard Henderson, Claudio Fontana, Peter Crosthwaite

On 1 November 2016 at 07:45, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> Pranith Kumar <bobby.prani@gmail.com> writes:
>> FYI, this is causing a build error on my system with gcc 6.2.
>>
>>   CC      aarch64-softmmu/cputlb.o
>> In file included from /home/pranith/devops/code/qemu/include/qemu/osdep.h:36:0,
>>                  from /home/pranith/devops/code/qemu/cputlb.c:20:
>> /home/pranith/devops/code/qemu/include/exec/cpu-all.h:196:26: error: braced-group within expression allowed only inside a function
>>  #define TARGET_PAGE_BITS ({ assert(target_page_bits_decided); \
>>                           ^
>> /home/pranith/devops/code/qemu/include/qemu/compiler.h:89:54: note: in definition of macro ‘QEMU_BUILD_BUG_ON’
>>      typedef char glue(qemu_build_bug_on__,__LINE__)[(x)?-1:1] __attribute__((unused));
>>                                                       ^
>> /home/pranith/devops/code/qemu/cputlb.c:293:34: note: in expansion of macro ‘TARGET_PAGE_BITS’
>>  QEMU_BUILD_BUG_ON(NB_MMU_MODES > TARGET_PAGE_BITS);
>>                                   ^~~~~~~~~~~~~~~~
>> /home/pranith/devops/code/qemu/rules.mak:60: recipe for target 'cputlb.o' failed
>> make[1]: *** [cputlb.o] Error 1
>> Makefile:202: recipe for target 'subdir-aarch64-softmmu' failed
>> make: *** [subdir-aarch64-softmmu] Error 2
>
> Odd. I'll look into it. What was you configure string and host architecture?

Looks like a clash between the variable-page-size patchset
and your stuff. Now TARGET_PAGE_BITS isn't necessarily
constant you can't use it in a compile time assert like that.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH v5 28/33] cputlb: make tlb_flush_by_mmuidx safe for MTTCG
  2016-11-01  7:45     ` Alex Bennée
  2016-11-01  8:03       ` Peter Maydell
@ 2016-11-01 13:22       ` Pranith Kumar
  2016-11-01 16:53         ` Alex Bennée
  1 sibling, 1 reply; 48+ messages in thread
From: Pranith Kumar @ 2016-11-01 13:22 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Paolo Bonzini, qemu-devel, MTTCG Devel,
	KONRAD Frédéric, alvise rigo, Emilio G. Cota, nikunj,
	Mark Burton, Jan Kiszka, Sergey Fedorov, Richard Henderson,
	Peter Maydell, Claudio Fontana, Peter Crosthwaite

On Tue, Nov 1, 2016 at 3:45 AM, Alex Bennée <alex.bennee@linaro.org> wrote:

>
> Odd. I'll look into it. What was you configure string and host architecture?
>

It's a plain configure string, nothing special:

$ ../configure --target-list=aarch64-softmmu

But I did rebase your patches on master, May be something new in the
tree tripped this?

-- 
Pranith

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH v5 28/33] cputlb: make tlb_flush_by_mmuidx safe for MTTCG
  2016-11-01 13:22       ` Pranith Kumar
@ 2016-11-01 16:53         ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2016-11-01 16:53 UTC (permalink / raw)
  To: Pranith Kumar
  Cc: Paolo Bonzini, qemu-devel, MTTCG Devel,
	KONRAD Frédéric, alvise rigo, Emilio G. Cota, nikunj,
	Mark Burton, Jan Kiszka, Sergey Fedorov, Richard Henderson,
	Peter Maydell, Claudio Fontana, Peter Crosthwaite


Pranith Kumar <bobby.prani@gmail.com> writes:

> On Tue, Nov 1, 2016 at 3:45 AM, Alex Bennée <alex.bennee@linaro.org> wrote:
>
>>
>> Odd. I'll look into it. What was you configure string and host architecture?
>>
>
> It's a plain configure string, nothing special:
>
> $ ../configure --target-list=aarch64-softmmu
>
> But I did rebase your patches on master, May be something new in the
> tree tripped this?

Yeah, I'll look for a fix with dynamic page sizes when I re-base.

--
Alex Bennée

^ permalink raw reply	[flat|nested] 48+ messages in thread

end of thread, other threads:[~2016-11-01 16:53 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-27 15:09 [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
2016-10-27 15:09 ` [Qemu-devel] [PATCH v5 01/33] cpus: make all_vcpus_paused() return bool Alex Bennée
2016-10-27 15:09 ` [Qemu-devel] [PATCH v5 02/33] translate_all: DEBUG_FLUSH -> DEBUG_TB_FLUSH Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 03/33] translate-all: add DEBUG_LOCKING asserts Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 04/33] cpu-exec: include cpu_index in CPU_LOG_EXEC messages Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 05/33] docs: new design document multi-thread-tcg.txt (DRAFTING) Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 06/33] tcg: comment on which functions have to be called with tb_lock held Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 07/33] linux-user/elfload: ensure mmap_lock() held while setting up Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 08/33] translate-all: Add assert_(memory|tb)_lock annotations Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 09/33] tcg: protect translation related stuff with tb_lock Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 10/33] target-arm/arm-powerctl: wake up sleeping CPUs Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 11/33] tcg: move tcg_exec_all and helpers above thread fn Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 12/33] tcg: cpus rm tcg_exec_all() Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 13/33] tcg: add options for enabling MTTCG Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 14/33] tcg: add kick timer for single-threaded vCPU emulation Alex Bennée
2016-10-27 15:30   ` KONRAD Frederic
2016-10-27 15:35     ` Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 15/33] tcg: rename tcg_current_cpu to tcg_current_rr_cpu Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 16/33] tcg: drop global lock during TCG code execution Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 17/33] cpus: re-factor out handle_icount_deadline Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 18/33] tcg: remove global exit_request Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 19/33] tcg: move locking for tb_invalidate_phys_page_range up Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 20/33] tcg: enable tb_lock() for SoftMMU Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 21/33] tcg: enable thread-per-vCPU Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 22/33] atomic: introduce cmpxchg_bool Alex Bennée
2016-10-27 15:10 ` [PATCH v5 23/33] *_run_on_cpu: introduce run_on_cpu_data type Alex Bennée
2016-10-27 15:10   ` [Qemu-devel] " Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 24/33] cputlb: add assert_cpu_is_self checks Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 25/33] cputlb: introduce tlb_flush_* async work Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 26/33] cputlb: tweak qemu_ram_addr_from_host_nofail reporting Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 27/33] cputlb: atomically update tlb fields used by tlb_reset_dirty Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 28/33] cputlb: make tlb_flush_by_mmuidx safe for MTTCG Alex Bennée
2016-11-01  5:20   ` Pranith Kumar
2016-11-01  7:45     ` Alex Bennée
2016-11-01  8:03       ` Peter Maydell
2016-11-01 13:22       ` Pranith Kumar
2016-11-01 16:53         ` Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 29/33] target-arm/powerctl: defer cpu reset work to CPU context Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 30/33] target-arm/cpu: don't reset TLB structures, use cputlb to do it Alex Bennée
2016-10-27 16:10   ` Richard Henderson
2016-10-28  8:38     ` Alex Bennée
2016-10-28  9:07       ` Peter Maydell
2016-10-28  9:17         ` Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 31/33] target-arm: ensure BQL taken for ARM_CP_IO register access Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 32/33] target-arm: helpers which may affect global state need the BQL Alex Bennée
2016-10-27 15:10 ` [Qemu-devel] [PATCH v5 33/33] tcg: enable MTTCG by default for ARM on x86 hosts Alex Bennée
2016-10-31  8:03 ` [Qemu-devel] [PATCH v5 00/33] MTTCG Base Enabling patches with ARM on x86 defaults Alex Bennée
2016-10-31  8:48   ` Paolo Bonzini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.