pc_event.cc revision 76
1/*
2 * Copyright (c) 2003 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 <algorithm>
30#include <map>
31#include <string>
32#include <utility>
33
34#include "sim/debug.hh"
35#include "cpu/exec_context.hh"
36#include "cpu/pc_event.hh"
37#include "base/trace.hh"
38#include "sim/universe.hh"
39
40#ifdef FULL_SYSTEM
41#include "targetarch/arguments.hh"
42#include "targetarch/pmap.h"
43#include "mem/functional_mem/memory_control.hh"
44#include "cpu/full_cpu/cpu.hh"
45#include "sim/system.hh"
46#include "cpu/full_cpu/bpred.hh"
47#endif
48
49using namespace std;
50
51PCEventQueue::PCEventQueue()
52{}
53
54PCEventQueue::~PCEventQueue()
55{}
56
57bool
58PCEventQueue::remove(PCEvent *event)
59{
60    int removed = 0;
61    range_t range = equal_range(event);
62    for (iterator i = range.first; i != range.second; ++i) {
63        if (*i == event) {
64            DPRINTF(PCEvent, "PC based event removed at %#x: %s\n",
65                    event->pc(), event->descr());
66            pc_map.erase(i);
67            ++removed;
68        }
69    }
70
71    return removed > 0;
72}
73
74bool
75PCEventQueue::schedule(PCEvent *event)
76{
77    pc_map.push_back(event);
78    sort(pc_map.begin(), pc_map.end(), MapCompare());
79
80    DPRINTF(PCEvent, "PC based event scheduled for %#x: %s\n",
81            event->pc(), event->descr());
82
83    return true;
84}
85
86bool
87PCEventQueue::doService(ExecContext *xc)
88{
89    Addr pc = xc->regs.pc;
90    int serviced = 0;
91    range_t range = equal_range(pc);
92    for (iterator i = range.first; i != range.second; ++i) {
93        // Make sure that the pc wasn't changed as the side effect of
94        // another event.  This for example, prevents two invocations
95        // of the SkipFuncEvent.  Maybe we should have separate PC
96        // event queues for each processor?
97        if (pc != xc->regs.pc)
98            continue;
99
100        DPRINTF(PCEvent, "PC based event serviced at %#x: %s\n",
101                (*i)->pc(), (*i)->descr());
102
103        (*i)->process(xc);
104        ++serviced;
105    }
106
107    return serviced > 0;
108}
109
110void
111PCEventQueue::dump() const
112{
113    const_iterator i = pc_map.begin();
114    const_iterator e = pc_map.end();
115
116    for (; i != e; ++i)
117        cprintf("%d: event at %#x: %s\n", curTick, (*i)->pc(),
118                (*i)->descr());
119}
120
121PCEventQueue::range_t
122PCEventQueue::equal_range(Addr pc)
123{
124    return std::equal_range(pc_map.begin(), pc_map.end(), pc, MapCompare());
125}
126
127#ifdef FULL_SYSTEM
128void
129SkipFuncEvent::process(ExecContext *xc)
130{
131    Addr newpc = xc->regs.intRegFile[ReturnAddressReg];
132
133    DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description,
134            xc->regs.pc, newpc);
135
136    xc->regs.pc = newpc;
137    xc->regs.npc = xc->regs.pc + sizeof(MachInst);
138
139    BranchPred *bp = xc->cpu->getBranchPred();
140    if (bp != NULL) {
141        bp->popRAS(xc->thread_num);
142    }
143}
144
145void
146BadAddrEvent::process(ExecContext *xc)
147{
148    // The following gross hack is the equivalent function to the
149    // annotation for vmunix::badaddr in:
150    // simos/simulation/apps/tcl/osf/tlaser.tcl
151
152    uint64_t a0 = xc->regs.intRegFile[ArgumentReg0];
153
154    if (a0 < ALPHA_K0SEG_BASE || a0 >= ALPHA_K1SEG_BASE ||
155        xc->memCtrl->badaddr(ALPHA_K0SEG_TO_PHYS(a0) & PA_IMPL_MASK)) {
156
157        DPRINTF(BADADDR, "badaddr arg=%#x bad\n", a0);
158        xc->regs.intRegFile[ReturnValueReg] = 0x1;
159        SkipFuncEvent::process(xc);
160    }
161    else
162        DPRINTF(BADADDR, "badaddr arg=%#x good\n", a0);
163}
164
165void Printf(AlphaArguments args);
166void DumpMbuf(AlphaArguments args);
167
168void
169PrintfEvent::process(ExecContext *xc)
170{
171    if (DTRACE(Printf)) {
172        DebugOut() << curTick << ": " << xc->cpu->name() << ": ";
173
174        AlphaArguments args(xc);
175        Printf(args);
176    }
177}
178
179void
180DebugPrintfEvent::process(ExecContext *xc)
181{
182    if (DTRACE(DebugPrintf)) {
183        if (!raw)
184            DebugOut() << curTick << ": " << xc->cpu->name() << ": ";
185
186        AlphaArguments args(xc);
187        Printf(args);
188    }
189}
190
191void
192DumpMbufEvent::process(ExecContext *xc)
193{
194    if (DTRACE(DebugPrintf)) {
195        AlphaArguments args(xc);
196        DumpMbuf(args);
197    }
198}
199#endif
200
201BreakPCEvent::BreakPCEvent(PCEventQueue *q, const std::string &desc, bool del)
202    : PCEvent(q, desc), remove(del)
203{
204}
205
206void
207BreakPCEvent::process(ExecContext *xc)
208{
209    debug_break();
210    if (remove)
211        delete this;
212}
213
214#ifdef FULL_SYSTEM
215extern "C"
216void
217sched_break_pc_sys(System *sys, Addr addr)
218{
219    PCEvent *event = new BreakPCEvent(&sys->pcEventQueue, "debug break", true);
220    event->schedule(addr);
221}
222
223extern "C"
224void
225sched_break_pc(Addr addr)
226{
227     for (vector<System *>::iterator sysi = System::systemList.begin();
228          sysi != System::systemList.end(); ++sysi) {
229         sched_break_pc_sys(*sysi, addr);
230    }
231
232}
233#endif
234