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