summaryrefslogtreecommitdiff
path: root/src/cpu
diff options
context:
space:
mode:
authorGeoffrey Blake <Geoffrey.Blake@arm.com>2014-05-09 18:58:47 -0400
committerGeoffrey Blake <Geoffrey.Blake@arm.com>2014-05-09 18:58:47 -0400
commit85940fd53795bd4b7b2118f4fa2a59a03bf6a8b1 (patch)
tree985e5611aa976bfe0c7e10e9458e7e5db8ed1eba /src/cpu
parent1028c03320c6c7822b8f5a32da2297c1be2d1487 (diff)
downloadgem5-85940fd53795bd4b7b2118f4fa2a59a03bf6a8b1.tar.xz
arch, arm: Preserve TLB bootUncacheability when switching CPUs
The ARM TLBs have a bootUncacheability flag used to make some loads and stores become uncacheable when booting in FS mode. Later the flag is cleared to let those loads and stores operate as normal. When doing a takeOverFrom(), this flag's state is not preserved and is momentarily reset until the CPSR is touched. On single core runs this is a non-issue. On multi-core runs this can lead to crashes on the O3 CPU model from the following series of events: 1) takeOverFrom executed to switch from Atomic -> O3 2) All bootUncacheability flags are reset to true 3) Core2 tries to execute a load covered by bootUncacheability, it is flagged as uncacheable 4) Core2's load needs to replay due to a pipeline flush 3) Core1 core does an action on CPSR 4) The handling code for CPSR then checks all other cores to determine if bootUncacheability can be set to false 5) Asynchronously set bootUncacheability on all cores to false 6) Core2 replays load previously set as uncacheable and notices it is now flagged as cacheable, leads to a panic. This patch implements takeOverFrom() functionality for the ARM TLBs to preserve flag values when switching from atomic -> detailed.
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/base.cc5
1 files changed, 5 insertions, 0 deletions
diff --git a/src/cpu/base.cc b/src/cpu/base.cc
index 905785631..c8c8ac571 100644
--- a/src/cpu/base.cc
+++ b/src/cpu/base.cc
@@ -432,6 +432,8 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU)
old_dtb_port->unbind();
new_dtb_port->bind(slavePort);
}
+ newTC->getITBPtr()->takeOverFrom(oldTC->getITBPtr());
+ newTC->getDTBPtr()->takeOverFrom(oldTC->getDTBPtr());
// Checker whether or not we have to transfer CheckerCPU
// objects over in the switch
@@ -447,6 +449,9 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU)
BaseMasterPort *new_checker_dtb_port =
newChecker->getDTBPtr()->getMasterPort();
+ newChecker->getITBPtr()->takeOverFrom(oldChecker->getITBPtr());
+ newChecker->getDTBPtr()->takeOverFrom(oldChecker->getDTBPtr());
+
// Move over any table walker ports if they exist for checker
if (new_checker_itb_port) {
assert(!new_checker_itb_port->isConnected());