physical.cc revision 2499
111986Sandreas.sandberg@arm.com/*
211986Sandreas.sandberg@arm.com * Copyright (c) 2001-2005 The Regents of The University of Michigan
311986Sandreas.sandberg@arm.com * All rights reserved.
411986Sandreas.sandberg@arm.com *
511986Sandreas.sandberg@arm.com * Redistribution and use in source and binary forms, with or without
611986Sandreas.sandberg@arm.com * modification, are permitted provided that the following conditions are
711986Sandreas.sandberg@arm.com * met: redistributions of source code must retain the above copyright
811986Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer;
914299Sbbruce@ucdavis.edu * redistributions in binary form must reproduce the above copyright
1014299Sbbruce@ucdavis.edu * notice, this list of conditions and the following disclaimer in the
1114299Sbbruce@ucdavis.edu * documentation and/or other materials provided with the distribution;
1214299Sbbruce@ucdavis.edu * 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 <cstdio>
37#include <iostream>
38#include <string>
39
40
41#include "base/misc.hh"
42#include "config/full_system.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)
73    : MemObject(n), base_addr(0), pmem_addr(NULL)
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
93PhysicalMemory::~PhysicalMemory()
94{
95    if (pmem_addr)
96        munmap(pmem_addr, pmem_size);
97    //Remove memPorts?
98}
99
100Addr
101PhysicalMemory::new_page()
102{
103    Addr return_addr = page_ptr << LogVMPageSize;
104    return_addr += base_addr;
105
106    ++page_ptr;
107    return return_addr;
108}
109
110int
111PhysicalMemory::deviceBlockSize()
112{
113    //Can accept anysize request
114    return 0;
115}
116
117bool
118PhysicalMemory::doTimingAccess (Packet &pkt, MemoryPort* memoryPort)
119{
120    doFunctionalAccess(pkt);
121
122    MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort);
123    response->schedule(curTick + lat);
124
125    return true;
126}
127
128Tick
129PhysicalMemory::doAtomicAccess(Packet &pkt)
130{
131    doFunctionalAccess(pkt);
132    return curTick + lat;
133}
134
135void
136PhysicalMemory::doFunctionalAccess(Packet &pkt)
137{
138    assert(pkt.addr + pkt.size < pmem_size);
139
140    switch (pkt.cmd) {
141      case Read:
142        memcpy(pkt.data, pmem_addr + pkt.addr - base_addr, pkt.size);
143        break;
144      case Write:
145        memcpy(pmem_addr + pkt.addr - base_addr, pkt.data, pkt.size);
146        break;
147      default:
148        panic("unimplemented");
149    }
150
151    pkt.result = Success;
152}
153
154Port *
155PhysicalMemory::getPort(const std::string &if_name)
156{
157    if (if_name == "") {
158        if (port != NULL)
159           panic("PhysicalMemory::getPort: additional port requested to memory!");
160        port = new MemoryPort(this);
161        return port;
162    } else {
163        panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
164    }
165}
166
167void
168PhysicalMemory::recvStatusChange(Port::Status status)
169{
170    panic("??");
171}
172
173PhysicalMemory::MemoryPort::MemoryPort(PhysicalMemory *_memory)
174    : memory(_memory)
175{ }
176
177void
178PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
179{
180    memory->recvStatusChange(status);
181}
182
183void
184PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &range_list,
185                                           bool &owner)
186{
187    memory->getAddressRanges(range_list, owner);
188}
189
190void
191PhysicalMemory::getAddressRanges(AddrRangeList &range_list, bool &owner)
192{
193    owner = true;
194    range_list.clear();
195    range_list.push_back(RangeSize(base_addr, pmem_size));
196}
197
198int
199PhysicalMemory::MemoryPort::deviceBlockSize()
200{
201    return memory->deviceBlockSize();
202}
203
204bool
205PhysicalMemory::MemoryPort::recvTiming(Packet &pkt)
206{
207    return memory->doTimingAccess(pkt, this);
208}
209
210Tick
211PhysicalMemory::MemoryPort::recvAtomic(Packet &pkt)
212{
213    return memory->doAtomicAccess(pkt);
214}
215
216void
217PhysicalMemory::MemoryPort::recvFunctional(Packet &pkt)
218{
219    memory->doFunctionalAccess(pkt);
220}
221
222
223
224void
225PhysicalMemory::serialize(ostream &os)
226{
227    gzFile compressedMem;
228    string filename = name() + ".physmem";
229
230    SERIALIZE_SCALAR(pmem_size);
231    SERIALIZE_SCALAR(filename);
232
233    // write memory file
234    string thefile = Checkpoint::dir() + "/" + filename.c_str();
235    int fd = creat(thefile.c_str(), 0664);
236    if (fd < 0) {
237        perror("creat");
238        fatal("Can't open physical memory checkpoint file '%s'\n", filename);
239    }
240
241    compressedMem = gzdopen(fd, "wb");
242    if (compressedMem == NULL)
243        fatal("Insufficient memory to allocate compression state for %s\n",
244                filename);
245
246    if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
247        fatal("Write failed on physical memory checkpoint file '%s'\n",
248              filename);
249    }
250
251    if (gzclose(compressedMem))
252        fatal("Close failed on physical memory checkpoint file '%s'\n",
253              filename);
254}
255
256void
257PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
258{
259    gzFile compressedMem;
260    long *tempPage;
261    long *pmem_current;
262    uint64_t curSize;
263    uint32_t bytesRead;
264    const int chunkSize = 16384;
265
266
267    // unmap file that was mmaped in the constructor
268    munmap(pmem_addr, pmem_size);
269
270    string filename;
271
272    UNSERIALIZE_SCALAR(pmem_size);
273    UNSERIALIZE_SCALAR(filename);
274
275    filename = cp->cptDir + "/" + filename;
276
277    // mmap memoryfile
278    int fd = open(filename.c_str(), O_RDONLY);
279    if (fd < 0) {
280        perror("open");
281        fatal("Can't open physical memory checkpoint file '%s'", filename);
282    }
283
284    compressedMem = gzdopen(fd, "rb");
285    if (compressedMem == NULL)
286        fatal("Insufficient memory to allocate compression state for %s\n",
287                filename);
288
289
290    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
291                                MAP_ANON | MAP_PRIVATE, -1, 0);
292
293    if (pmem_addr == (void *)MAP_FAILED) {
294        perror("mmap");
295        fatal("Could not mmap physical memory!\n");
296    }
297
298    curSize = 0;
299    tempPage = (long*)malloc(chunkSize);
300    if (tempPage == NULL)
301        fatal("Unable to malloc memory to read file %s\n", filename);
302
303    /* Only copy bytes that are non-zero, so we don't give the VM system hell */
304    while (curSize < pmem_size) {
305        bytesRead = gzread(compressedMem, tempPage, chunkSize);
306        if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
307            fatal("Read failed on physical memory checkpoint file '%s'"
308                  " got %d bytes, expected %d or %d bytes\n",
309                  filename, bytesRead, chunkSize, pmem_size-curSize);
310
311        assert(bytesRead % sizeof(long) == 0);
312
313        for (int x = 0; x < bytesRead/sizeof(long); x++)
314        {
315             if (*(tempPage+x) != 0) {
316                 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
317                 *pmem_current = *(tempPage+x);
318             }
319        }
320        curSize += bytesRead;
321    }
322
323    free(tempPage);
324
325    if (gzclose(compressedMem))
326        fatal("Close failed on physical memory checkpoint file '%s'\n",
327              filename);
328
329}
330
331
332BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
333
334    Param<string> file;
335#if FULL_SYSTEM
336    SimObjectParam<MemoryController *> mmu;
337#endif
338    Param<Range<Addr> > range;
339
340END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
341
342BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
343
344    INIT_PARAM_DFLT(file, "memory mapped file", ""),
345#if FULL_SYSTEM
346    INIT_PARAM(mmu, "Memory Controller"),
347#endif
348    INIT_PARAM(range, "Device Address Range")
349
350END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
351
352CREATE_SIM_OBJECT(PhysicalMemory)
353{
354#if FULL_SYSTEM
355    if (mmu) {
356        return new PhysicalMemory(getInstanceName(), range, mmu, file);
357    }
358#endif
359
360    return new PhysicalMemory(getInstanceName());
361}
362
363REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
364