e28c34f88fa735adb88b6feb2bad8cf134738345
[gem5.git] / cpu / cpu_exec_context.cc
1 /*
2 * Copyright (c) 2001-2006 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <string>
30
31 #include "cpu/base.hh"
32 #include "cpu/cpu_exec_context.hh"
33 #include "cpu/exec_context.hh"
34
35 #if FULL_SYSTEM
36 #include "base/callback.hh"
37 #include "base/cprintf.hh"
38 #include "base/output.hh"
39 #include "base/trace.hh"
40 #include "cpu/profile.hh"
41 #include "cpu/quiesce_event.hh"
42 #include "kern/kernel_stats.hh"
43 #include "sim/serialize.hh"
44 #include "sim/sim_exit.hh"
45 #include "sim/system.hh"
46 #include "arch/stacktrace.hh"
47 #else
48 #include "sim/process.hh"
49 #endif
50
51 using namespace std;
52
53 // constructor
54 #if FULL_SYSTEM
55 CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_sys,
56 AlphaITB *_itb, AlphaDTB *_dtb,
57 FunctionalMemory *_mem,
58 bool use_kernel_stats)
59 : _status(ExecContext::Unallocated), cpu(_cpu), thread_num(_thread_num),
60 cpu_id(-1), lastActivate(0), lastSuspend(0), mem(_mem), itb(_itb),
61 dtb(_dtb), system(_sys), memctrl(_sys->memctrl), physmem(_sys->physmem),
62 profile(NULL), func_exe_inst(0), storeCondFailures(0)
63 {
64 proxy = new ProxyExecContext<CPUExecContext>(this);
65
66 quiesceEvent = new EndQuiesceEvent(proxy);
67
68 memset(&regs, 0, sizeof(RegFile));
69
70 if (cpu->params->profile) {
71 profile = new FunctionProfile(system->kernelSymtab);
72 Callback *cb =
73 new MakeCallback<CPUExecContext,
74 &CPUExecContext::dumpFuncProfile>(this);
75 registerExitCallback(cb);
76 }
77
78 // let's fill with a dummy node for now so we don't get a segfault
79 // on the first cycle when there's no node available.
80 static ProfileNode dummyNode;
81 profileNode = &dummyNode;
82 profilePC = 3;
83
84 if (use_kernel_stats) {
85 kernelStats = new Kernel::Statistics(system);
86 } else {
87 kernelStats = NULL;
88 }
89 }
90 #else
91 CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num,
92 Process *_process, int _asid)
93 : _status(ExecContext::Unallocated),
94 cpu(_cpu), thread_num(_thread_num), cpu_id(-1), lastActivate(0),
95 lastSuspend(0), process(_process), mem(process->getMemory()), asid(_asid),
96 func_exe_inst(0), storeCondFailures(0)
97 {
98 memset(&regs, 0, sizeof(RegFile));
99 proxy = new ProxyExecContext<CPUExecContext>(this);
100 }
101
102 CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num,
103 FunctionalMemory *_mem, int _asid)
104 : cpu(_cpu), thread_num(_thread_num), process(0), mem(_mem), asid(_asid),
105 func_exe_inst(0), storeCondFailures(0)
106 {
107 memset(&regs, 0, sizeof(RegFile));
108 proxy = new ProxyExecContext<CPUExecContext>(this);
109 }
110
111 CPUExecContext::CPUExecContext(RegFile *regFile)
112 : cpu(NULL), thread_num(-1), process(NULL), mem(NULL), asid(-1),
113 func_exe_inst(0), storeCondFailures(0)
114 {
115 regs = *regFile;
116 proxy = new ProxyExecContext<CPUExecContext>(this);
117 }
118
119 #endif
120
121 CPUExecContext::~CPUExecContext()
122 {
123 delete proxy;
124 }
125
126 #if FULL_SYSTEM
127 void
128 CPUExecContext::dumpFuncProfile()
129 {
130 std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name()));
131 profile->dump(proxy, *os);
132 }
133
134 void
135 CPUExecContext::profileClear()
136 {
137 if (profile)
138 profile->clear();
139 }
140
141 void
142 CPUExecContext::profileSample()
143 {
144 if (profile)
145 profile->sample(profileNode, profilePC);
146 }
147
148 #endif
149
150 void
151 CPUExecContext::takeOverFrom(ExecContext *oldContext)
152 {
153 // some things should already be set up
154 assert(mem == oldContext->getMemPtr());
155 #if FULL_SYSTEM
156 assert(system == oldContext->getSystemPtr());
157 #else
158 assert(process == oldContext->getProcessPtr());
159 #endif
160
161 // copy over functional state
162 _status = oldContext->status();
163 copyArchRegs(oldContext);
164 cpu_id = oldContext->readCpuId();
165 #if !FULL_SYSTEM
166 func_exe_inst = oldContext->readFuncExeInst();
167 #else
168 EndQuiesceEvent *quiesce = oldContext->getQuiesceEvent();
169 if (quiesce) {
170 // Point the quiesce event's XC at this XC so that it wakes up
171 // the proper CPU.
172 quiesce->xc = proxy;
173 }
174 if (quiesceEvent) {
175 quiesceEvent->xc = proxy;
176 }
177 #endif
178
179 storeCondFailures = 0;
180
181 oldContext->setStatus(ExecContext::Unallocated);
182 }
183
184 void
185 CPUExecContext::serialize(ostream &os)
186 {
187 SERIALIZE_ENUM(_status);
188 regs.serialize(os);
189 // thread_num and cpu_id are deterministic from the config
190 SERIALIZE_SCALAR(func_exe_inst);
191 SERIALIZE_SCALAR(inst);
192
193 #if FULL_SYSTEM
194 Tick quiesceEndTick = 0;
195 if (quiesceEvent->scheduled())
196 quiesceEndTick = quiesceEvent->when();
197 SERIALIZE_SCALAR(quiesceEndTick);
198 if (kernelStats)
199 kernelStats->serialize(os);
200 #endif
201 }
202
203
204 void
205 CPUExecContext::unserialize(Checkpoint *cp, const std::string &section)
206 {
207 UNSERIALIZE_ENUM(_status);
208 regs.unserialize(cp, section);
209 // thread_num and cpu_id are deterministic from the config
210 UNSERIALIZE_SCALAR(func_exe_inst);
211 UNSERIALIZE_SCALAR(inst);
212
213 #if FULL_SYSTEM
214 Tick quiesceEndTick;
215 UNSERIALIZE_SCALAR(quiesceEndTick);
216 if (quiesceEndTick)
217 quiesceEvent->schedule(quiesceEndTick);
218 if (kernelStats)
219 kernelStats->unserialize(cp, section);
220 #endif
221 }
222
223
224 void
225 CPUExecContext::activate(int delay)
226 {
227 if (status() == ExecContext::Active)
228 return;
229
230 lastActivate = curTick;
231
232 if (status() == ExecContext::Unallocated) {
233 cpu->activateWhenReady(thread_num);
234 return;
235 }
236
237 _status = ExecContext::Active;
238
239 // status() == Suspended
240 cpu->activateContext(thread_num, delay);
241 }
242
243 void
244 CPUExecContext::suspend()
245 {
246 if (status() == ExecContext::Suspended)
247 return;
248
249 lastActivate = curTick;
250 lastSuspend = curTick;
251 /*
252 #if FULL_SYSTEM
253 // Don't change the status from active if there are pending interrupts
254 if (cpu->check_interrupts()) {
255 assert(status() == ExecContext::Active);
256 return;
257 }
258 #endif
259 */
260 _status = ExecContext::Suspended;
261 cpu->suspendContext(thread_num);
262 }
263
264 void
265 CPUExecContext::deallocate()
266 {
267 if (status() == ExecContext::Unallocated)
268 return;
269
270 _status = ExecContext::Unallocated;
271 cpu->deallocateContext(thread_num);
272 }
273
274 void
275 CPUExecContext::halt()
276 {
277 if (status() == ExecContext::Halted)
278 return;
279
280 _status = ExecContext::Halted;
281 cpu->haltContext(thread_num);
282 }
283
284
285 void
286 CPUExecContext::regStats(const string &name)
287 {
288 #if FULL_SYSTEM
289 if (kernelStats)
290 kernelStats->regStats(name + ".kern");
291 #endif
292 }
293
294 void
295 CPUExecContext::copyArchRegs(ExecContext *xc)
296 {
297 // First loop through the integer registers.
298 for (int i = 0; i < AlphaISA::NumIntRegs; ++i) {
299 setIntReg(i, xc->readIntReg(i));
300 }
301
302 // Then loop through the floating point registers.
303 for (int i = 0; i < AlphaISA::NumFloatRegs; ++i) {
304 setFloatRegDouble(i, xc->readFloatRegDouble(i));
305 setFloatRegInt(i, xc->readFloatRegInt(i));
306 }
307
308 // Copy misc. registers
309 TheISA::copyMiscRegs(xc, proxy);
310
311 // Lastly copy PC/NPC
312 setPC(xc->readPC());
313 setNextPC(xc->readNextPC());
314 }
315