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