device.hh revision 1992
1/*
2 * Copyright (c) 2004-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
29/* @file
30 * Interface for devices using PCI configuration
31 */
32
33#ifndef __DEV_PCIDEV_HH__
34#define __DEV_PCIDEV_HH__
35
36#include "dev/io_device.hh"
37#include "dev/pcireg.h"
38#include "dev/platform.hh"
39
40#define BAR_IO_MASK 0x3
41#define BAR_MEM_MASK 0xF
42#define BAR_IO_SPACE_BIT 0x1
43#define BAR_IO_SPACE(x) ((x) & BAR_IO_SPACE_BIT)
44#define BAR_NUMBER(x) (((x) - PCI0_BASE_ADDR0) >> 0x2);
45
46class PciConfigAll;
47class MemoryController;
48
49
50/**
51 * This class encapulates the first 64 bytes of a singles PCI
52 * devices config space that in configured by the configuration file.
53 */
54class PciConfigData : public SimObject
55{
56  public:
57    /**
58     * Constructor to initialize the devices config space to 0.
59     */
60    PciConfigData(const std::string &name)
61        : SimObject(name)
62    {
63        memset(config.data, 0, sizeof(config.data));
64        memset(BARAddrs, 0, sizeof(BARAddrs));
65        memset(BARSize, 0, sizeof(BARSize));
66    }
67
68    /** The first 64 bytes */
69    PCIConfig config;
70
71    /** The size of the BARs */
72    uint32_t BARSize[6];
73
74    /** The addresses of the BARs */
75    Addr BARAddrs[6];
76};
77
78/**
79 * PCI device, base implemnation is only config space.
80 * Each device is connected to a PCIConfigSpace device
81 * which returns -1 for everything but the pcidevs that
82 * register with it. This object registers with the PCIConfig space
83 * object.
84 */
85class PciDev : public DmaDevice
86{
87  public:
88    struct Params
89    {
90        std::string name;
91        Platform *plat;
92        MemoryController *mmu;
93
94        /**
95         * A pointer to the configspace all object that calls us when
96         * a read comes to this particular device/function.
97         */
98        PciConfigAll *configSpace;
99
100        /**
101         * A pointer to the object that contains the first 64 bytes of
102         * config space
103         */
104        PciConfigData *configData;
105
106        /** The bus number we are on */
107        uint32_t busNum;
108
109        /** The device number we have */
110        uint32_t deviceNum;
111
112        /** The function number */
113        uint32_t functionNum;
114    };
115
116  protected:
117    Params *_params;
118
119  public:
120    const Params *params() const { return _params; }
121
122  protected:
123    /** The current config space. Unlike the PciConfigData this is
124     * updated during simulation while continues to reflect what was
125     * in the config file.
126     */
127    PCIConfig config;
128
129    /** The size of the BARs */
130    uint32_t BARSize[6];
131
132    /** The current address mapping of the BARs */
133    Addr BARAddrs[6];
134
135    bool
136    isBAR(Addr addr, int bar) const
137    {
138        assert(bar >= 0 && bar < 6);
139        return BARAddrs[bar] <= addr && addr < BARAddrs[bar] + BARSize[bar];
140    }
141
142    int
143    getBAR(Addr addr)
144    {
145        for (int i = 0; i <= 5; ++i)
146            if (isBAR(addr, i))
147                return i;
148
149        return -1;
150    }
151
152    bool
153    getBAR(Addr paddr, Addr &daddr, int &bar)
154    {
155        int b = getBAR(paddr);
156        if (b < 0)
157            return false;
158
159        daddr = paddr - BARAddrs[b];
160        bar = b;
161        return true;
162    }
163
164  protected:
165    Platform *plat;
166    PciConfigData *configData;
167
168  public:
169    Addr pciToDma(Addr pciAddr) const
170    { return plat->pciToDma(pciAddr); }
171
172    void
173    intrPost()
174    { plat->postPciInt(configData->config.interruptLine); }
175
176    void
177    intrClear()
178    { plat->clearPciInt(configData->config.interruptLine); }
179
180    uint8_t
181    interruptLine()
182    { return configData->config.interruptLine; }
183
184  public:
185    /**
186     * Constructor for PCI Dev. This function copies data from the
187     * config file object PCIConfigData and registers the device with
188     * a PciConfigAll object.
189     */
190    PciDev(Params *params);
191
192    virtual Fault read(MemReqPtr &req, uint8_t *data);
193    virtual Fault write(MemReqPtr &req, const uint8_t *data);
194
195  public:
196    /**
197     * Implement the read/write as BAR accesses
198     */
199    Fault readBar(MemReqPtr &req, uint8_t *data);
200    Fault writeBar(MemReqPtr &req, const uint8_t *data);
201
202  public:
203    /**
204     * Read from a specific BAR
205     */
206    virtual Fault readBar0(MemReqPtr &req, Addr daddr, uint8_t *data);
207    virtual Fault readBar1(MemReqPtr &req, Addr daddr, uint8_t *data);
208    virtual Fault readBar2(MemReqPtr &req, Addr daddr, uint8_t *data);
209    virtual Fault readBar3(MemReqPtr &req, Addr daddr, uint8_t *data);
210    virtual Fault readBar4(MemReqPtr &req, Addr daddr, uint8_t *data);
211    virtual Fault readBar5(MemReqPtr &req, Addr daddr, uint8_t *data);
212
213  public:
214    /**
215     * Write to a specific BAR
216     */
217    virtual Fault writeBar0(MemReqPtr &req, Addr daddr, const uint8_t *data);
218    virtual Fault writeBar1(MemReqPtr &req, Addr daddr, const uint8_t *data);
219    virtual Fault writeBar2(MemReqPtr &req, Addr daddr, const uint8_t *data);
220    virtual Fault writeBar3(MemReqPtr &req, Addr daddr, const uint8_t *data);
221    virtual Fault writeBar4(MemReqPtr &req, Addr daddr, const uint8_t *data);
222    virtual Fault writeBar5(MemReqPtr &req, Addr daddr, const uint8_t *data);
223
224  public:
225    /**
226     * Write to the PCI config space data that is stored locally. This may be
227     * overridden by the device but at some point it will eventually call this
228     * for normal operations that it does not need to override.
229     * @param offset the offset into config space
230     * @param size the size of the write
231     * @param data the data to write
232     */
233    virtual void writeConfig(int offset, int size, const uint8_t* data);
234
235
236    /**
237     * Read from the PCI config space data that is stored locally. This may be
238     * overridden by the device but at some point it will eventually call this
239     * for normal operations that it does not need to override.
240     * @param offset the offset into config space
241     * @param size the size of the read
242     * @param data pointer to the location where the read value should be stored
243     */
244    virtual void readConfig(int offset, int size, uint8_t *data);
245
246    /**
247     * Serialize this object to the given output stream.
248     * @param os The stream to serialize to.
249     */
250    virtual void serialize(std::ostream &os);
251
252    /**
253     * Reconstruct the state of this object from a checkpoint.
254     * @param cp The checkpoint use.
255     * @param section The section name of this object
256     */
257    virtual void unserialize(Checkpoint *cp, const std::string &section);
258};
259
260inline Fault
261PciDev::readBar(MemReqPtr &req, uint8_t *data)
262{
263    if (isBAR(req->paddr, 0))
264        return readBar0(req, req->paddr - BARAddrs[0], data);
265    if (isBAR(req->paddr, 1))
266        return readBar1(req, req->paddr - BARAddrs[1], data);
267    if (isBAR(req->paddr, 2))
268        return readBar2(req, req->paddr - BARAddrs[2], data);
269    if (isBAR(req->paddr, 3))
270        return readBar3(req, req->paddr - BARAddrs[3], data);
271    if (isBAR(req->paddr, 4))
272        return readBar4(req, req->paddr - BARAddrs[4], data);
273    if (isBAR(req->paddr, 5))
274        return readBar5(req, req->paddr - BARAddrs[5], data);
275    return Machine_Check_Fault;
276}
277
278inline Fault
279PciDev::writeBar(MemReqPtr &req, const uint8_t *data)
280{
281    if (isBAR(req->paddr, 0))
282        return writeBar0(req, req->paddr - BARAddrs[0], data);
283    if (isBAR(req->paddr, 1))
284        return writeBar1(req, req->paddr - BARAddrs[1], data);
285    if (isBAR(req->paddr, 2))
286        return writeBar2(req, req->paddr - BARAddrs[2], data);
287    if (isBAR(req->paddr, 3))
288        return writeBar3(req, req->paddr - BARAddrs[3], data);
289    if (isBAR(req->paddr, 4))
290        return writeBar4(req, req->paddr - BARAddrs[4], data);
291    if (isBAR(req->paddr, 5))
292        return writeBar5(req, req->paddr - BARAddrs[5], data);
293    return Machine_Check_Fault;
294}
295
296#endif // __DEV_PCIDEV_HH__
297