1/*
2 * Copyright (c) 2011 ARM Limited
3 * All rights reserved.
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2002-2005 The Regents of The University of Michigan
15 * Copyright (c) 2009 The University of Edinburgh
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: Gabe Black
42 *          Timothy M. Jones
43 */
44
45#ifndef __CPU_TRANSLATION_HH__
46#define __CPU_TRANSLATION_HH__
47
48#include "arch/generic/tlb.hh"
49#include "sim/faults.hh"
50
51/**
52 * This class captures the state of an address translation.  A translation
53 * can be split in two if the ISA supports it and the memory access crosses
54 * a page boundary.  In this case, this class is shared by two data
55 * translations (below).  Otherwise it is used by a single data translation
56 * class.  When each part of the translation is finished, the finish
57 * function is called which will indicate whether the whole translation is
58 * completed or not.  There are also functions for accessing parts of the
59 * translation state which deal with the possible split correctly.
60 */
61class WholeTranslationState
62{
63  protected:
64    int outstanding;
65    Fault faults[2];
66
67  public:
68    bool delay;
69    bool isSplit;
70    RequestPtr mainReq;
71    RequestPtr sreqLow;
72    RequestPtr sreqHigh;
73    uint8_t *data;
74    uint64_t *res;
75    BaseTLB::Mode mode;
76
77    /**
78     * Single translation state.  We set the number of outstanding
79     * translations to one and indicate that it is not split.
80     */
81    WholeTranslationState(const RequestPtr &_req, uint8_t *_data,
82                          uint64_t *_res, BaseTLB::Mode _mode)
83        : outstanding(1), delay(false), isSplit(false), mainReq(_req),
84          sreqLow(NULL), sreqHigh(NULL), data(_data), res(_res), mode(_mode)
85    {
86        faults[0] = faults[1] = NoFault;
87        assert(mode == BaseTLB::Read || mode == BaseTLB::Write);
88    }
89
90    /**
91     * Split translation state.  We copy all state into this class, set the
92     * number of outstanding translations to two and then mark this as a
93     * split translation.
94     */
95    WholeTranslationState(const RequestPtr &_req, const RequestPtr &_sreqLow,
96                          const RequestPtr &_sreqHigh, uint8_t *_data,
97                          uint64_t *_res, BaseTLB::Mode _mode)
98        : outstanding(2), delay(false), isSplit(true), mainReq(_req),
99          sreqLow(_sreqLow), sreqHigh(_sreqHigh), data(_data), res(_res),
100          mode(_mode)
101    {
102        faults[0] = faults[1] = NoFault;
103        assert(mode == BaseTLB::Read || mode == BaseTLB::Write);
104    }
105
106    /**
107     * Finish part of a translation.  If there is only one request then this
108     * translation is completed.  If the request has been split in two then
109     * the outstanding count determines whether the translation is complete.
110     * In this case, flags from the split request are copied to the main
111     * request to make it easier to access them later on.
112     */
113    bool
114    finish(const Fault &fault, int index)
115    {
116        assert(outstanding);
117        faults[index] = fault;
118        outstanding--;
119        if (isSplit && outstanding == 0) {
120
121            // For ease later, we copy some state to the main request.
122            if (faults[0] == NoFault) {
123                mainReq->setPaddr(sreqLow->getPaddr());
124            }
125            mainReq->setFlags(sreqLow->getFlags());
126            mainReq->setFlags(sreqHigh->getFlags());
127        }
128        return outstanding == 0;
129    }
130
131    /**
132     * Determine whether this translation produced a fault.  Both parts of the
133     * translation must be checked if this is a split translation.
134     */
135    Fault
136    getFault() const
137    {
138        if (!isSplit)
139            return faults[0];
140        else if (faults[0] != NoFault)
141            return faults[0];
142        else if (faults[1] != NoFault)
143            return faults[1];
144        else
145            return NoFault;
146    }
147
148    /** Remove all faults from the translation. */
149    void
150    setNoFault()
151    {
152        faults[0] = faults[1] = NoFault;
153    }
154
155    /**
156     * Check if this request is strictly ordered device access.  We
157     * only need to check the main request because the flags will have
158     * been copied here on a split translation.
159     */
160    bool
161    isStrictlyOrdered() const
162    {
163        return mainReq->isStrictlyOrdered();
164    }
165
166    /**
167     * Check if this request is a prefetch.  We only need to check the main
168     * request because the flags will have been copied here on a split
169     * translation.
170     */
171    bool
172    isPrefetch() const
173    {
174        return mainReq->isPrefetch();
175    }
176
177    /** Get the physical address of this request. */
178    Addr
179    getPaddr() const
180    {
181        return mainReq->getPaddr();
182    }
183
184    /**
185     * Get the flags associated with this request.  We only need to access
186     * the main request because the flags will have been copied here on a
187     * split translation.
188     */
189    unsigned
190    getFlags()
191    {
192        return mainReq->getFlags();
193    }
194
195    /** Delete all requests that make up this translation. */
196    void
197    deleteReqs()
198    {
199        mainReq.reset();
200        if (isSplit) {
201            sreqLow.reset();
202            sreqHigh.reset();
203        }
204    }
205};
206
207
208/**
209 * This class represents part of a data address translation.  All state for
210 * the translation is held in WholeTranslationState (above).  Therefore this
211 * class does not need to know whether the translation is split or not.  The
212 * index variable determines this but is simply passed on to the state class.
213 * When this part of the translation is completed, finish is called.  If the
214 * translation state class indicate that the whole translation is complete
215 * then the execution context is informed.
216 */
217template <class ExecContextPtr>
218class DataTranslation : public BaseTLB::Translation
219{
220  protected:
221    ExecContextPtr xc;
222    WholeTranslationState *state;
223    int index;
224
225  public:
226    DataTranslation(ExecContextPtr _xc, WholeTranslationState* _state)
227        : xc(_xc), state(_state), index(0)
228    {
229    }
230
231    DataTranslation(ExecContextPtr _xc, WholeTranslationState* _state,
232                    int _index)
233        : xc(_xc), state(_state), index(_index)
234    {
235    }
236
237    /**
238     * Signal the translation state that the translation has been delayed due
239     * to a hw page table walk.  Split requests are transparently handled.
240     */
241    void
242    markDelayed()
243    {
244        state->delay = true;
245    }
246
247    /**
248     * Finish this part of the translation and indicate that the whole
249     * translation is complete if the state says so.
250     */
251    void
252    finish(const Fault &fault, const RequestPtr &req, ThreadContext *tc,
253           BaseTLB::Mode mode)
254    {
255        assert(state);
256        assert(mode == state->mode);
257        if (state->finish(fault, index)) {
258            if (state->getFault() == NoFault) {
259                // Don't access the request if faulted (due to squash)
260                req->setTranslateLatency();
261            }
262            xc->finishTranslation(state);
263        }
264        delete this;
265    }
266
267    bool
268    squashed() const
269    {
270        return xc->isSquashed();
271    }
272};
273
274#endif // __CPU_TRANSLATION_HH__
275