7c2b32a93ba2aa3da35bcdcbde9dc2ac820a1ffe
[gem5.git] / src / 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 "arch/isa_traits.hh"
32 #include "cpu/base.hh"
33 #include "cpu/cpu_exec_context.hh"
34 #include "cpu/exec_context.hh"
35
36 #if FULL_SYSTEM
37 #include "base/callback.hh"
38 #include "base/cprintf.hh"
39 #include "base/output.hh"
40 #include "base/trace.hh"
41 #include "cpu/profile.hh"
42 #include "cpu/quiesce_event.hh"
43 #include "kern/kernel_stats.hh"
44 #include "sim/serialize.hh"
45 #include "sim/sim_exit.hh"
46 #include "arch/stacktrace.hh"
47 #else
48 #include "sim/process.hh"
49 #include "sim/system.hh"
50 #include "mem/translating_port.hh"
51 #endif
52
53 using namespace std;
54
55 // constructor
56 #if FULL_SYSTEM
57 CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_sys,
58 AlphaITB *_itb, AlphaDTB *_dtb,
59 bool use_kernel_stats)
60 : _status(ExecContext::Unallocated), cpu(_cpu), thread_num(_thread_num),
61 cpu_id(-1), lastActivate(0), lastSuspend(0), system(_sys), itb(_itb),
62 dtb(_dtb), profile(NULL), func_exe_inst(0), storeCondFailures(0)
63
64 {
65 proxy = new ProxyExecContext<CPUExecContext>(this);
66
67 quiesceEvent = new EndQuiesceEvent(proxy);
68
69 regs.clear();
70
71 if (cpu->params->profile) {
72 profile = new FunctionProfile(system->kernelSymtab);
73 Callback *cb =
74 new MakeCallback<CPUExecContext,
75 &CPUExecContext::dumpFuncProfile>(this);
76 registerExitCallback(cb);
77 }
78
79 // let's fill with a dummy node for now so we don't get a segfault
80 // on the first cycle when there's no node available.
81 static ProfileNode dummyNode;
82 profileNode = &dummyNode;
83 profilePC = 3;
84
85
86 if (use_kernel_stats) {
87 kernelStats = new Kernel::Statistics(system);
88 } else {
89 kernelStats = NULL;
90 }
91 Port *mem_port;
92 physPort = new FunctionalPort(csprintf("%s-%d-funcport",
93 cpu->name(), thread_num));
94 mem_port = system->physmem->getPort("functional");
95 mem_port->setPeer(physPort);
96 physPort->setPeer(mem_port);
97
98 virtPort = new VirtualPort(csprintf("%s-%d-vport",
99 cpu->name(), thread_num));
100 mem_port = system->physmem->getPort("functional");
101 mem_port->setPeer(virtPort);
102 virtPort->setPeer(mem_port);
103 }
104 #else
105 CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num,
106 Process *_process, int _asid, MemObject* memobj)
107 : _status(ExecContext::Unallocated),
108 cpu(_cpu), thread_num(_thread_num), cpu_id(-1), lastActivate(0),
109 lastSuspend(0), process(_process), asid(_asid),
110 func_exe_inst(0), storeCondFailures(0)
111 {
112 /* Use this port to for syscall emulation writes to memory. */
113 Port *mem_port;
114 port = new TranslatingPort(csprintf("%s-%d-funcport",
115 cpu->name(), thread_num),
116 process->pTable, false);
117 mem_port = memobj->getPort("functional");
118 mem_port->setPeer(port);
119 port->setPeer(mem_port);
120
121 regs.clear();
122 proxy = new ProxyExecContext<CPUExecContext>(this);
123 }
124
125 CPUExecContext::CPUExecContext(RegFile *regFile)
126 : cpu(NULL), thread_num(-1), process(NULL), asid(-1),
127 func_exe_inst(0), storeCondFailures(0)
128 {
129 regs = *regFile;
130 proxy = new ProxyExecContext<CPUExecContext>(this);
131 }
132
133 #endif
134
135 CPUExecContext::~CPUExecContext()
136 {
137 delete proxy;
138 }
139
140 #if FULL_SYSTEM
141 void
142 CPUExecContext::dumpFuncProfile()
143 {
144 std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name()));
145 profile->dump(proxy, *os);
146 }
147
148 void
149 CPUExecContext::profileClear()
150 {
151 if (profile)
152 profile->clear();
153 }
154
155 void
156 CPUExecContext::profileSample()
157 {
158 if (profile)
159 profile->sample(profileNode, profilePC);
160 }
161
162 #endif
163
164 void
165 CPUExecContext::takeOverFrom(ExecContext *oldContext)
166 {
167 // some things should already be set up
168 #if FULL_SYSTEM
169 assert(system == oldContext->getSystemPtr());
170 #else
171 assert(process == oldContext->getProcessPtr());
172 #endif
173
174 // copy over functional state
175 _status = oldContext->status();
176 copyArchRegs(oldContext);
177 cpu_id = oldContext->readCpuId();
178 #if !FULL_SYSTEM
179 func_exe_inst = oldContext->readFuncExeInst();
180 #else
181 EndQuiesceEvent *quiesce = oldContext->getQuiesceEvent();
182 if (quiesce) {
183 // Point the quiesce event's XC at this XC so that it wakes up
184 // the proper CPU.
185 quiesce->xc = proxy;
186 }
187 if (quiesceEvent) {
188 quiesceEvent->xc = proxy;
189 }
190 #endif
191
192 storeCondFailures = 0;
193
194 oldContext->setStatus(ExecContext::Unallocated);
195 }
196
197 void
198 CPUExecContext::serialize(ostream &os)
199 {
200 SERIALIZE_ENUM(_status);
201 regs.serialize(os);
202 // thread_num and cpu_id are deterministic from the config
203 SERIALIZE_SCALAR(func_exe_inst);
204 SERIALIZE_SCALAR(inst);
205
206 #if FULL_SYSTEM
207 Tick quiesceEndTick = 0;
208 if (quiesceEvent->scheduled())
209 quiesceEndTick = quiesceEvent->when();
210 SERIALIZE_SCALAR(quiesceEndTick);
211 if (kernelStats)
212 kernelStats->serialize(os);
213 #endif
214 }
215
216
217 void
218 CPUExecContext::unserialize(Checkpoint *cp, const std::string &section)
219 {
220 UNSERIALIZE_ENUM(_status);
221 regs.unserialize(cp, section);
222 // thread_num and cpu_id are deterministic from the config
223 UNSERIALIZE_SCALAR(func_exe_inst);
224 UNSERIALIZE_SCALAR(inst);
225
226 #if FULL_SYSTEM
227 Tick quiesceEndTick;
228 UNSERIALIZE_SCALAR(quiesceEndTick);
229 if (quiesceEndTick)
230 quiesceEvent->schedule(quiesceEndTick);
231 if (kernelStats)
232 kernelStats->unserialize(cp, section);
233 #endif
234 }
235
236
237 void
238 CPUExecContext::activate(int delay)
239 {
240 if (status() == ExecContext::Active)
241 return;
242
243 lastActivate = curTick;
244
245 if (status() == ExecContext::Unallocated) {
246 cpu->activateWhenReady(thread_num);
247 return;
248 }
249
250 _status = ExecContext::Active;
251
252 // status() == Suspended
253 cpu->activateContext(thread_num, delay);
254 }
255
256 void
257 CPUExecContext::suspend()
258 {
259 if (status() == ExecContext::Suspended)
260 return;
261
262 lastActivate = curTick;
263 lastSuspend = curTick;
264 /*
265 #if FULL_SYSTEM
266 // Don't change the status from active if there are pending interrupts
267 if (cpu->check_interrupts()) {
268 assert(status() == ExecContext::Active);
269 return;
270 }
271 #endif
272 */
273 _status = ExecContext::Suspended;
274 cpu->suspendContext(thread_num);
275 }
276
277 void
278 CPUExecContext::deallocate()
279 {
280 if (status() == ExecContext::Unallocated)
281 return;
282
283 _status = ExecContext::Unallocated;
284 cpu->deallocateContext(thread_num);
285 }
286
287 void
288 CPUExecContext::halt()
289 {
290 if (status() == ExecContext::Halted)
291 return;
292
293 _status = ExecContext::Halted;
294 cpu->haltContext(thread_num);
295 }
296
297
298 void
299 CPUExecContext::regStats(const string &name)
300 {
301 #if FULL_SYSTEM
302 if (kernelStats)
303 kernelStats->regStats(name + ".kern");
304 #endif
305 }
306
307 void
308 CPUExecContext::copyArchRegs(ExecContext *xc)
309 {
310 TheISA::copyRegs(xc, proxy);
311 }
312
313 #if FULL_SYSTEM
314 VirtualPort*
315 CPUExecContext::getVirtPort(ExecContext *xc)
316 {
317 if (!xc)
318 return virtPort;
319
320 VirtualPort *vp;
321 Port *mem_port;
322
323 vp = new VirtualPort("xc-vport", xc);
324 mem_port = system->physmem->getPort("functional");
325 mem_port->setPeer(vp);
326 vp->setPeer(mem_port);
327 return vp;
328 }
329
330 void
331 CPUExecContext::delVirtPort(VirtualPort *vp)
332 {
333 // assert(!vp->nullExecContext());
334 delete vp->getPeer();
335 delete vp;
336 }
337
338
339 #endif
340