add syscall emulation page table fault so we can allocate more stack pages
[gem5.git] / src / cpu / simple / base.cc
1 /*
2 * Copyright (c) 2002-2005 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 * Authors: Steve Reinhardt
29 * Korey Sewell
30 */
31
32 #include "arch/utility.hh"
33 #include "base/cprintf.hh"
34 #include "base/inifile.hh"
35 #include "base/loader/symtab.hh"
36 #include "base/misc.hh"
37 #include "base/pollevent.hh"
38 #include "base/range.hh"
39 #include "base/stats/events.hh"
40 #include "base/trace.hh"
41 #include "cpu/base.hh"
42 #include "cpu/exetrace.hh"
43 #include "cpu/profile.hh"
44 #include "cpu/sampler/sampler.hh"
45 #include "cpu/simple/base.hh"
46 #include "cpu/simple_thread.hh"
47 #include "cpu/smt.hh"
48 #include "cpu/static_inst.hh"
49 #include "cpu/thread_context.hh"
50 #include "kern/kernel_stats.hh"
51 #include "mem/packet_impl.hh"
52 #include "sim/builder.hh"
53 #include "sim/byteswap.hh"
54 #include "sim/debug.hh"
55 #include "sim/host.hh"
56 #include "sim/sim_events.hh"
57 #include "sim/sim_object.hh"
58 #include "sim/stats.hh"
59
60 #if FULL_SYSTEM
61 #include "base/remote_gdb.hh"
62 #include "sim/system.hh"
63 #include "arch/tlb.hh"
64 #include "arch/stacktrace.hh"
65 #include "arch/vtophys.hh"
66 #else // !FULL_SYSTEM
67 #include "mem/mem_object.hh"
68 #endif // FULL_SYSTEM
69
70 using namespace std;
71 using namespace TheISA;
72
73 BaseSimpleCPU::BaseSimpleCPU(Params *p)
74 : BaseCPU(p), mem(p->mem), thread(NULL)
75 {
76 #if FULL_SYSTEM
77 thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb);
78 #else
79 thread = new SimpleThread(this, /* thread_num */ 0, p->process,
80 /* asid */ 0, mem);
81 #endif // !FULL_SYSTEM
82
83 thread->setStatus(ThreadContext::Suspended);
84
85 tc = thread->getTC();
86
87 numInst = 0;
88 startNumInst = 0;
89 numLoad = 0;
90 startNumLoad = 0;
91 lastIcacheStall = 0;
92 lastDcacheStall = 0;
93
94 threadContexts.push_back(tc);
95 }
96
97 BaseSimpleCPU::~BaseSimpleCPU()
98 {
99 }
100
101 void
102 BaseSimpleCPU::deallocateContext(int thread_num)
103 {
104 // for now, these are equivalent
105 suspendContext(thread_num);
106 }
107
108
109 void
110 BaseSimpleCPU::haltContext(int thread_num)
111 {
112 // for now, these are equivalent
113 suspendContext(thread_num);
114 }
115
116
117 void
118 BaseSimpleCPU::regStats()
119 {
120 using namespace Stats;
121
122 BaseCPU::regStats();
123
124 numInsts
125 .name(name() + ".num_insts")
126 .desc("Number of instructions executed")
127 ;
128
129 numMemRefs
130 .name(name() + ".num_refs")
131 .desc("Number of memory references")
132 ;
133
134 notIdleFraction
135 .name(name() + ".not_idle_fraction")
136 .desc("Percentage of non-idle cycles")
137 ;
138
139 idleFraction
140 .name(name() + ".idle_fraction")
141 .desc("Percentage of idle cycles")
142 ;
143
144 icacheStallCycles
145 .name(name() + ".icache_stall_cycles")
146 .desc("ICache total stall cycles")
147 .prereq(icacheStallCycles)
148 ;
149
150 dcacheStallCycles
151 .name(name() + ".dcache_stall_cycles")
152 .desc("DCache total stall cycles")
153 .prereq(dcacheStallCycles)
154 ;
155
156 icacheRetryCycles
157 .name(name() + ".icache_retry_cycles")
158 .desc("ICache total retry cycles")
159 .prereq(icacheRetryCycles)
160 ;
161
162 dcacheRetryCycles
163 .name(name() + ".dcache_retry_cycles")
164 .desc("DCache total retry cycles")
165 .prereq(dcacheRetryCycles)
166 ;
167
168 idleFraction = constant(1.0) - notIdleFraction;
169 }
170
171 void
172 BaseSimpleCPU::resetStats()
173 {
174 startNumInst = numInst;
175 // notIdleFraction = (_status != Idle);
176 }
177
178 void
179 BaseSimpleCPU::serialize(ostream &os)
180 {
181 BaseCPU::serialize(os);
182 SERIALIZE_SCALAR(inst);
183 nameOut(os, csprintf("%s.xc", name()));
184 thread->serialize(os);
185 }
186
187 void
188 BaseSimpleCPU::unserialize(Checkpoint *cp, const string &section)
189 {
190 BaseCPU::unserialize(cp, section);
191 UNSERIALIZE_SCALAR(inst);
192 thread->unserialize(cp, csprintf("%s.xc", section));
193 }
194
195 void
196 change_thread_state(int thread_number, int activate, int priority)
197 {
198 }
199
200 Fault
201 BaseSimpleCPU::copySrcTranslate(Addr src)
202 {
203 #if 0
204 static bool no_warn = true;
205 int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
206 // Only support block sizes of 64 atm.
207 assert(blk_size == 64);
208 int offset = src & (blk_size - 1);
209
210 // Make sure block doesn't span page
211 if (no_warn &&
212 (src & PageMask) != ((src + blk_size) & PageMask) &&
213 (src >> 40) != 0xfffffc) {
214 warn("Copied block source spans pages %x.", src);
215 no_warn = false;
216 }
217
218 memReq->reset(src & ~(blk_size - 1), blk_size);
219
220 // translate to physical address
221 Fault fault = thread->translateDataReadReq(req);
222
223 if (fault == NoFault) {
224 thread->copySrcAddr = src;
225 thread->copySrcPhysAddr = memReq->paddr + offset;
226 } else {
227 assert(!fault->isAlignmentFault());
228
229 thread->copySrcAddr = 0;
230 thread->copySrcPhysAddr = 0;
231 }
232 return fault;
233 #else
234 return NoFault;
235 #endif
236 }
237
238 Fault
239 BaseSimpleCPU::copy(Addr dest)
240 {
241 #if 0
242 static bool no_warn = true;
243 int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
244 // Only support block sizes of 64 atm.
245 assert(blk_size == 64);
246 uint8_t data[blk_size];
247 //assert(thread->copySrcAddr);
248 int offset = dest & (blk_size - 1);
249
250 // Make sure block doesn't span page
251 if (no_warn &&
252 (dest & PageMask) != ((dest + blk_size) & PageMask) &&
253 (dest >> 40) != 0xfffffc) {
254 no_warn = false;
255 warn("Copied block destination spans pages %x. ", dest);
256 }
257
258 memReq->reset(dest & ~(blk_size -1), blk_size);
259 // translate to physical address
260 Fault fault = thread->translateDataWriteReq(req);
261
262 if (fault == NoFault) {
263 Addr dest_addr = memReq->paddr + offset;
264 // Need to read straight from memory since we have more than 8 bytes.
265 memReq->paddr = thread->copySrcPhysAddr;
266 thread->mem->read(memReq, data);
267 memReq->paddr = dest_addr;
268 thread->mem->write(memReq, data);
269 if (dcacheInterface) {
270 memReq->cmd = Copy;
271 memReq->completionEvent = NULL;
272 memReq->paddr = thread->copySrcPhysAddr;
273 memReq->dest = dest_addr;
274 memReq->size = 64;
275 memReq->time = curTick;
276 memReq->flags &= ~INST_READ;
277 dcacheInterface->access(memReq);
278 }
279 }
280 else
281 assert(!fault->isAlignmentFault());
282
283 return fault;
284 #else
285 panic("copy not implemented");
286 return NoFault;
287 #endif
288 }
289
290 #if FULL_SYSTEM
291 Addr
292 BaseSimpleCPU::dbg_vtophys(Addr addr)
293 {
294 return vtophys(tc, addr);
295 }
296 #endif // FULL_SYSTEM
297
298 #if FULL_SYSTEM
299 void
300 BaseSimpleCPU::post_interrupt(int int_num, int index)
301 {
302 BaseCPU::post_interrupt(int_num, index);
303
304 if (thread->status() == ThreadContext::Suspended) {
305 DPRINTF(IPI,"Suspended Processor awoke\n");
306 thread->activate();
307 }
308 }
309 #endif // FULL_SYSTEM
310
311 void
312 BaseSimpleCPU::checkForInterrupts()
313 {
314 #if FULL_SYSTEM
315 if (checkInterrupts && check_interrupts() && !thread->inPalMode()) {
316 int ipl = 0;
317 int summary = 0;
318 checkInterrupts = false;
319
320 if (thread->readMiscReg(IPR_SIRR)) {
321 for (int i = INTLEVEL_SOFTWARE_MIN;
322 i < INTLEVEL_SOFTWARE_MAX; i++) {
323 if (thread->readMiscReg(IPR_SIRR) & (ULL(1) << i)) {
324 // See table 4-19 of 21164 hardware reference
325 ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
326 summary |= (ULL(1) << i);
327 }
328 }
329 }
330
331 uint64_t interrupts = thread->cpu->intr_status();
332 for (int i = INTLEVEL_EXTERNAL_MIN;
333 i < INTLEVEL_EXTERNAL_MAX; i++) {
334 if (interrupts & (ULL(1) << i)) {
335 // See table 4-19 of 21164 hardware reference
336 ipl = i;
337 summary |= (ULL(1) << i);
338 }
339 }
340
341 if (thread->readMiscReg(IPR_ASTRR))
342 panic("asynchronous traps not implemented\n");
343
344 if (ipl && ipl > thread->readMiscReg(IPR_IPLR)) {
345 thread->setMiscReg(IPR_ISR, summary);
346 thread->setMiscReg(IPR_INTID, ipl);
347
348 Fault(new InterruptFault)->invoke(tc);
349
350 DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
351 thread->readMiscReg(IPR_IPLR), ipl, summary);
352 }
353 }
354 #endif
355 }
356
357
358 Fault
359 BaseSimpleCPU::setupFetchRequest(Request *req)
360 {
361 // set up memory request for instruction fetch
362 #if THE_ISA == ALPHA_ISA
363 DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p",thread->readPC(),
364 thread->readNextPC());
365 #else
366 DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",thread->readPC(),
367 thread->readNextPC(),thread->readNextNPC());
368 #endif
369
370 req->setVirt(0, thread->readPC() & ~3, sizeof(MachInst),
371 (FULL_SYSTEM && (thread->readPC() & 1)) ? PHYSICAL : 0,
372 thread->readPC());
373
374 Fault fault = thread->translateInstReq(req);
375
376 return fault;
377 }
378
379
380 void
381 BaseSimpleCPU::preExecute()
382 {
383 // maintain $r0 semantics
384 thread->setIntReg(ZeroReg, 0);
385 #if THE_ISA == ALPHA_ISA
386 thread->setFloatReg(ZeroReg, 0.0);
387 #endif // ALPHA_ISA
388
389 // keep an instruction count
390 numInst++;
391 numInsts++;
392
393 thread->funcExeInst++;
394
395 // check for instruction-count-based events
396 comInstEventQueue[0]->serviceEvents(numInst);
397
398 // decode the instruction
399 inst = gtoh(inst);
400 curStaticInst = StaticInst::decode(makeExtMI(inst, thread->readPC()));
401
402 traceData = Trace::getInstRecord(curTick, tc, this, curStaticInst,
403 thread->readPC());
404
405 DPRINTF(Decode,"Decode: Decoded %s instruction (opcode: 0x%x): 0x%x\n",
406 curStaticInst->getName(), curStaticInst->getOpcode(),
407 curStaticInst->machInst);
408
409 #if FULL_SYSTEM
410 thread->setInst(inst);
411 #endif // FULL_SYSTEM
412 }
413
414 void
415 BaseSimpleCPU::postExecute()
416 {
417 #if FULL_SYSTEM
418 if (thread->profile) {
419 bool usermode =
420 (thread->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
421 thread->profilePC = usermode ? 1 : thread->readPC();
422 ProfileNode *node = thread->profile->consume(tc, inst);
423 if (node)
424 thread->profileNode = node;
425 }
426 #endif
427
428 if (curStaticInst->isMemRef()) {
429 numMemRefs++;
430 }
431
432 if (curStaticInst->isLoad()) {
433 ++numLoad;
434 comLoadEventQueue[0]->serviceEvents(numLoad);
435 }
436
437 traceFunctions(thread->readPC());
438
439 if (traceData) {
440 traceData->finalize();
441 }
442 }
443
444
445 void
446 BaseSimpleCPU::advancePC(Fault fault)
447 {
448 if (fault != NoFault) {
449 fault->invoke(tc);
450 }
451 else {
452 // go to the next instruction
453 thread->setPC(thread->readNextPC());
454 #if THE_ISA == ALPHA_ISA
455 thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
456 #else
457 thread->setNextPC(thread->readNextNPC());
458 thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
459 #endif
460
461 }
462
463 #if FULL_SYSTEM
464 Addr oldpc;
465 do {
466 oldpc = thread->readPC();
467 system->pcEventQueue.service(tc);
468 } while (oldpc != thread->readPC());
469 #endif
470 }
471