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