dev, arm: Fix multi-core KVM race in the generic timer
authorAndreas Sandberg <andreas.sandberg@arm.com>
Fri, 17 Mar 2017 11:57:23 +0000 (11:57 +0000)
committerAndreas Sandberg <andreas.sandberg@arm.com>
Mon, 3 Apr 2017 16:37:55 +0000 (16:37 +0000)
The generic timer sometimes needs to access global state. This can
lead to race conditions when simulating a multi-core KVM system where
each core lives in its own thread. In that case, the setMiscReg and
readMiscReg methods are called from the thread owning the CPU and not
the global device thread.

Change-Id: Ie3e982258648c8562cce0b30a0c122dfbfaf42cd
Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Gabor Dozsa <gabor.dozsa@arm.com>
Reviewed-by: Curtis Dunham <curtis.dunham@arm.com>
Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/2460
Reviewed-by: Weiping Liao <weipingliao@google.com>
src/dev/arm/generic_timer.cc

index 1b8d917e946d1156837fc54c835e4f2b0abd9988..d33090d743ef7d426c4627b7364a85b847c972a3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015 ARM Limited
+ * Copyright (c) 2013, 2015, 2017 ARM Limited
  * All rights reserved.
  *
  * The license below extends only to copyright in the software and shall
@@ -307,6 +307,11 @@ GenericTimer::createTimers(unsigned cpus)
 void
 GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val)
 {
+    // This method might have been called from another context if we
+    // are running in multi-core KVM. Migrate to the SimObject's event
+    // queue to prevent surprising race conditions.
+    EventQueue::ScopedMigration migrate(eventQueue());
+
     CoreTimers &core(getTimers(cpu));
 
     switch (reg) {
@@ -399,6 +404,11 @@ GenericTimer::setMiscReg(int reg, unsigned cpu, MiscReg val)
 MiscReg
 GenericTimer::readMiscReg(int reg, unsigned cpu)
 {
+    // This method might have been called from another context if we
+    // are running in multi-core KVM. Migrate to the SimObject's event
+    // queue to prevent surprising race conditions.
+    EventQueue::ScopedMigration migrate(eventQueue());
+
     CoreTimers &core(getTimers(cpu));
 
     switch (reg) {