69146599603d5d321ddf2143ab6b036d3a355c70
[gem5.git] / src / cpu / thread_context.cc
1 /*
2 * Copyright (c) 2012 ARM Limited
3 * Copyright (c) 2013 Advanced Micro Devices, Inc.
4 * All rights reserved
5 *
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder. You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
14 *
15 * Copyright (c) 2006 The Regents of The University of Michigan
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Authors: Kevin Lim
42 */
43
44 #include "arch/kernel_stats.hh"
45 #include "base/misc.hh"
46 #include "base/trace.hh"
47 #include "config/the_isa.hh"
48 #include "cpu/base.hh"
49 #include "cpu/quiesce_event.hh"
50 #include "cpu/thread_context.hh"
51 #include "debug/Context.hh"
52 #include "debug/Quiesce.hh"
53 #include "params/BaseCPU.hh"
54 #include "sim/full_system.hh"
55
56 void
57 ThreadContext::compare(ThreadContext *one, ThreadContext *two)
58 {
59 DPRINTF(Context, "Comparing thread contexts\n");
60
61 // First loop through the integer registers.
62 for (int i = 0; i < TheISA::NumIntRegs; ++i) {
63 TheISA::IntReg t1 = one->readIntReg(i);
64 TheISA::IntReg t2 = two->readIntReg(i);
65 if (t1 != t2)
66 panic("Int reg idx %d doesn't match, one: %#x, two: %#x",
67 i, t1, t2);
68 }
69
70 // Then loop through the floating point registers.
71 for (int i = 0; i < TheISA::NumFloatRegs; ++i) {
72 TheISA::FloatRegBits t1 = one->readFloatRegBits(i);
73 TheISA::FloatRegBits t2 = two->readFloatRegBits(i);
74 if (t1 != t2)
75 panic("Float reg idx %d doesn't match, one: %#x, two: %#x",
76 i, t1, t2);
77 }
78 for (int i = 0; i < TheISA::NumMiscRegs; ++i) {
79 TheISA::MiscReg t1 = one->readMiscRegNoEffect(i);
80 TheISA::MiscReg t2 = two->readMiscRegNoEffect(i);
81 if (t1 != t2)
82 panic("Misc reg idx %d doesn't match, one: %#x, two: %#x",
83 i, t1, t2);
84 }
85
86 // loop through the Condition Code registers.
87 for (int i = 0; i < TheISA::NumCCRegs; ++i) {
88 TheISA::CCReg t1 = one->readCCReg(i);
89 TheISA::CCReg t2 = two->readCCReg(i);
90 if (t1 != t2)
91 panic("CC reg idx %d doesn't match, one: %#x, two: %#x",
92 i, t1, t2);
93 }
94 if (!(one->pcState() == two->pcState()))
95 panic("PC state doesn't match.");
96 int id1 = one->cpuId();
97 int id2 = two->cpuId();
98 if (id1 != id2)
99 panic("CPU ids don't match, one: %d, two: %d", id1, id2);
100
101 const ContextID cid1 = one->contextId();
102 const ContextID cid2 = two->contextId();
103 if (cid1 != cid2)
104 panic("Context ids don't match, one: %d, two: %d", id1, id2);
105
106
107 }
108
109 void
110 ThreadContext::quiesce()
111 {
112 if (!getCpuPtr()->params()->do_quiesce)
113 return;
114
115 DPRINTF(Quiesce, "%s: quiesce()\n", getCpuPtr()->name());
116
117 suspend();
118 if (getKernelStats())
119 getKernelStats()->quiesce();
120 }
121
122
123 void
124 ThreadContext::quiesceTick(Tick resume)
125 {
126 BaseCPU *cpu = getCpuPtr();
127
128 if (!cpu->params()->do_quiesce)
129 return;
130
131 EndQuiesceEvent *quiesceEvent = getQuiesceEvent();
132
133 cpu->reschedule(quiesceEvent, resume, true);
134
135 DPRINTF(Quiesce, "%s: quiesceTick until %lu\n", cpu->name(), resume);
136
137 suspend();
138 if (getKernelStats())
139 getKernelStats()->quiesce();
140 }
141
142 void
143 serialize(ThreadContext &tc, CheckpointOut &cp)
144 {
145 using namespace TheISA;
146
147 FloatRegBits floatRegs[NumFloatRegs];
148 for (int i = 0; i < NumFloatRegs; ++i)
149 floatRegs[i] = tc.readFloatRegBitsFlat(i);
150 // This is a bit ugly, but needed to maintain backwards
151 // compatibility.
152 arrayParamOut(cp, "floatRegs.i", floatRegs, NumFloatRegs);
153
154 IntReg intRegs[NumIntRegs];
155 for (int i = 0; i < NumIntRegs; ++i)
156 intRegs[i] = tc.readIntRegFlat(i);
157 SERIALIZE_ARRAY(intRegs, NumIntRegs);
158
159 #ifdef ISA_HAS_CC_REGS
160 CCReg ccRegs[NumCCRegs];
161 for (int i = 0; i < NumCCRegs; ++i)
162 ccRegs[i] = tc.readCCRegFlat(i);
163 SERIALIZE_ARRAY(ccRegs, NumCCRegs);
164 #endif
165
166 tc.pcState().serialize(cp);
167
168 // thread_num and cpu_id are deterministic from the config
169 }
170
171 void
172 unserialize(ThreadContext &tc, CheckpointIn &cp)
173 {
174 using namespace TheISA;
175
176 FloatRegBits floatRegs[NumFloatRegs];
177 // This is a bit ugly, but needed to maintain backwards
178 // compatibility.
179 arrayParamIn(cp, "floatRegs.i", floatRegs, NumFloatRegs);
180 for (int i = 0; i < NumFloatRegs; ++i)
181 tc.setFloatRegBitsFlat(i, floatRegs[i]);
182
183 IntReg intRegs[NumIntRegs];
184 UNSERIALIZE_ARRAY(intRegs, NumIntRegs);
185 for (int i = 0; i < NumIntRegs; ++i)
186 tc.setIntRegFlat(i, intRegs[i]);
187
188 #ifdef ISA_HAS_CC_REGS
189 CCReg ccRegs[NumCCRegs];
190 UNSERIALIZE_ARRAY(ccRegs, NumCCRegs);
191 for (int i = 0; i < NumCCRegs; ++i)
192 tc.setCCRegFlat(i, ccRegs[i]);
193 #endif
194
195 PCState pcState;
196 pcState.unserialize(cp);
197 tc.pcState(pcState);
198
199 // thread_num and cpu_id are deterministic from the config
200 }
201
202 void
203 takeOverFrom(ThreadContext &ntc, ThreadContext &otc)
204 {
205 assert(ntc.getProcessPtr() == otc.getProcessPtr());
206
207 ntc.setStatus(otc.status());
208 ntc.copyArchRegs(&otc);
209 ntc.setContextId(otc.contextId());
210 ntc.setThreadId(otc.threadId());
211
212 if (FullSystem) {
213 assert(ntc.getSystemPtr() == otc.getSystemPtr());
214
215 BaseCPU *ncpu(ntc.getCpuPtr());
216 assert(ncpu);
217 EndQuiesceEvent *oqe(otc.getQuiesceEvent());
218 assert(oqe);
219 assert(oqe->tc == &otc);
220
221 BaseCPU *ocpu(otc.getCpuPtr());
222 assert(ocpu);
223 EndQuiesceEvent *nqe(ntc.getQuiesceEvent());
224 assert(nqe);
225 assert(nqe->tc == &ntc);
226
227 if (oqe->scheduled()) {
228 ncpu->schedule(nqe, oqe->when());
229 ocpu->deschedule(oqe);
230 }
231 }
232
233 otc.setStatus(ThreadContext::Halted);
234 }