abstract_mem.cc revision 2914
1/*
2 * Copyright (c) 2001-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: Ron Dreslinski
29 *          Ali Saidi
30 */
31
32#include <sys/types.h>
33#include <sys/mman.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <unistd.h>
37#include <zlib.h>
38
39#include <iostream>
40#include <string>
41
42
43#include "base/misc.hh"
44#include "config/full_system.hh"
45#include "mem/packet_impl.hh"
46#include "mem/physical.hh"
47#include "sim/host.hh"
48#include "sim/builder.hh"
49#include "sim/eventq.hh"
50#include "arch/isa_traits.hh"
51
52
53using namespace std;
54using namespace TheISA;
55
56
57PhysicalMemory::PhysicalMemory(const string &n, Tick latency)
58    : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency)
59{
60    // Hardcoded to 128 MB for now.
61    pmem_size = 1 << 27;
62
63    if (pmem_size % TheISA::PageBytes != 0)
64        panic("Memory Size not divisible by page size\n");
65
66    int map_flags = MAP_ANON | MAP_PRIVATE;
67    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
68                                map_flags, -1, 0);
69
70    if (pmem_addr == (void *)MAP_FAILED) {
71        perror("mmap");
72        fatal("Could not mmap!\n");
73    }
74
75    page_ptr = 0;
76}
77
78void
79PhysicalMemory::init()
80{
81    if (!port)
82        panic("PhysicalMemory not connected to anything!");
83    port->sendStatusChange(Port::RangeChange);
84}
85
86PhysicalMemory::~PhysicalMemory()
87{
88    if (pmem_addr)
89        munmap(pmem_addr, pmem_size);
90    //Remove memPorts?
91}
92
93Addr
94PhysicalMemory::new_page()
95{
96    Addr return_addr = page_ptr << LogVMPageSize;
97    return_addr += base_addr;
98
99    ++page_ptr;
100    return return_addr;
101}
102
103int
104PhysicalMemory::deviceBlockSize()
105{
106    //Can accept anysize request
107    return 0;
108}
109
110
111Tick
112PhysicalMemory::doFunctionalAccess(Packet *pkt)
113{
114    assert(pkt->getAddr() + pkt->getSize() < pmem_size);
115
116    switch (pkt->cmd) {
117      case Packet::ReadReq:
118        memcpy(pkt->getPtr<uint8_t>(),
119               pmem_addr + pkt->getAddr() - base_addr,
120               pkt->getSize());
121        break;
122      case Packet::WriteReq:
123        memcpy(pmem_addr + pkt->getAddr() - base_addr,
124               pkt->getPtr<uint8_t>(),
125               pkt->getSize());
126        // temporary hack: will need to add real LL/SC implementation
127        // for cacheless systems later.
128        if (pkt->req->getFlags() & LOCKED) {
129            pkt->req->setScResult(1);
130        }
131        break;
132      default:
133        panic("unimplemented");
134    }
135
136    pkt->result = Packet::Success;
137    return lat;
138}
139
140Port *
141PhysicalMemory::getPort(const std::string &if_name, int idx)
142{
143    if (if_name == "port" && idx == -1) {
144        if (port != NULL)
145           panic("PhysicalMemory::getPort: additional port requested to memory!");
146        port = new MemoryPort(name() + "-port", this);
147        return port;
148    } else if (if_name == "functional") {
149        /* special port for functional writes at startup. */
150        return new MemoryPort(name() + "-funcport", this);
151    } else {
152        panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
153    }
154}
155
156void
157PhysicalMemory::recvStatusChange(Port::Status status)
158{
159}
160
161PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
162                                       PhysicalMemory *_memory)
163    : SimpleTimingPort(_name), memory(_memory)
164{ }
165
166void
167PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
168{
169    memory->recvStatusChange(status);
170}
171
172void
173PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
174                                            AddrRangeList &snoop)
175{
176    memory->getAddressRanges(resp, snoop);
177}
178
179void
180PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
181{
182    snoop.clear();
183    resp.clear();
184    resp.push_back(RangeSize(base_addr, pmem_size));
185}
186
187int
188PhysicalMemory::MemoryPort::deviceBlockSize()
189{
190    return memory->deviceBlockSize();
191}
192
193bool
194PhysicalMemory::MemoryPort::recvTiming(Packet *pkt)
195{
196    assert(pkt->result != Packet::Nacked);
197
198    Tick latency = memory->doFunctionalAccess(pkt);
199
200    pkt->makeTimingResponse();
201    sendTiming(pkt, latency);
202
203    return true;
204}
205
206Tick
207PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
208{
209    return memory->doFunctionalAccess(pkt);
210}
211
212void
213PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt)
214{
215    memory->doFunctionalAccess(pkt);
216}
217
218unsigned int
219PhysicalMemory::drain(Event *de)
220{
221    int count = port->drain(de);
222    if (count)
223        changeState(Draining);
224    else
225        changeState(Drained);
226    return count;
227}
228
229void
230PhysicalMemory::serialize(ostream &os)
231{
232    gzFile compressedMem;
233    string filename = name() + ".physmem";
234
235    SERIALIZE_SCALAR(pmem_size);
236    SERIALIZE_SCALAR(filename);
237
238    // write memory file
239    string thefile = Checkpoint::dir() + "/" + filename.c_str();
240    int fd = creat(thefile.c_str(), 0664);
241    if (fd < 0) {
242        perror("creat");
243        fatal("Can't open physical memory checkpoint file '%s'\n", filename);
244    }
245
246    compressedMem = gzdopen(fd, "wb");
247    if (compressedMem == NULL)
248        fatal("Insufficient memory to allocate compression state for %s\n",
249                filename);
250
251    if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
252        fatal("Write failed on physical memory checkpoint file '%s'\n",
253              filename);
254    }
255
256    if (gzclose(compressedMem))
257        fatal("Close failed on physical memory checkpoint file '%s'\n",
258              filename);
259}
260
261void
262PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
263{
264    gzFile compressedMem;
265    long *tempPage;
266    long *pmem_current;
267    uint64_t curSize;
268    uint32_t bytesRead;
269    const int chunkSize = 16384;
270
271
272    // unmap file that was mmaped in the constructor
273    munmap(pmem_addr, pmem_size);
274
275    string filename;
276
277    UNSERIALIZE_SCALAR(pmem_size);
278    UNSERIALIZE_SCALAR(filename);
279
280    filename = cp->cptDir + "/" + filename;
281
282    // mmap memoryfile
283    int fd = open(filename.c_str(), O_RDONLY);
284    if (fd < 0) {
285        perror("open");
286        fatal("Can't open physical memory checkpoint file '%s'", filename);
287    }
288
289    compressedMem = gzdopen(fd, "rb");
290    if (compressedMem == NULL)
291        fatal("Insufficient memory to allocate compression state for %s\n",
292                filename);
293
294
295    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
296                                MAP_ANON | MAP_PRIVATE, -1, 0);
297
298    if (pmem_addr == (void *)MAP_FAILED) {
299        perror("mmap");
300        fatal("Could not mmap physical memory!\n");
301    }
302
303    curSize = 0;
304    tempPage = (long*)malloc(chunkSize);
305    if (tempPage == NULL)
306        fatal("Unable to malloc memory to read file %s\n", filename);
307
308    /* Only copy bytes that are non-zero, so we don't give the VM system hell */
309    while (curSize < pmem_size) {
310        bytesRead = gzread(compressedMem, tempPage, chunkSize);
311        if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
312            fatal("Read failed on physical memory checkpoint file '%s'"
313                  " got %d bytes, expected %d or %d bytes\n",
314                  filename, bytesRead, chunkSize, pmem_size-curSize);
315
316        assert(bytesRead % sizeof(long) == 0);
317
318        for (int x = 0; x < bytesRead/sizeof(long); x++)
319        {
320             if (*(tempPage+x) != 0) {
321                 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
322                 *pmem_current = *(tempPage+x);
323             }
324        }
325        curSize += bytesRead;
326    }
327
328    free(tempPage);
329
330    if (gzclose(compressedMem))
331        fatal("Close failed on physical memory checkpoint file '%s'\n",
332              filename);
333
334}
335
336
337BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
338
339    Param<string> file;
340    Param<Range<Addr> > range;
341    Param<Tick> latency;
342
343END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
344
345BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
346
347    INIT_PARAM_DFLT(file, "memory mapped file", ""),
348    INIT_PARAM(range, "Device Address Range"),
349    INIT_PARAM(latency, "Memory access latency")
350
351END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
352
353CREATE_SIM_OBJECT(PhysicalMemory)
354{
355
356    return new PhysicalMemory(getInstanceName(), latency);
357}
358
359REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
360