physical.cc revision 2391
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/functional/physical.hh"
47#include "sim/host.hh"
48#include "sim/builder.hh"
49#include "targetarch/isa_traits.hh"
50
51using namespace std;
52
53#if FULL_SYSTEM
54PhysicalMemory::PhysicalMemory(const string &n, Range<Addr> range,
55                               MemoryController *mmu, const std::string &fname)
56    : FunctionalMemory(n), base_addr(range.start), pmem_size(range.size()),
57      pmem_addr(NULL)
58{
59    if (pmem_size % TheISA::PageBytes != 0)
60        panic("Memory Size not divisible by page size\n");
61
62    mmu->add_child(this, range);
63
64    int fd = -1;
65
66    if (!fname.empty()) {
67        fd = open(fname.c_str(), O_RDWR | O_CREAT, 0644);
68        if (fd == -1) {
69            perror("open");
70            fatal("Could not open physical memory file: %s\n", fname);
71        }
72        ftruncate(fd, pmem_size);
73    }
74
75    int map_flags = (fd == -1) ? (MAP_ANON | MAP_PRIVATE) : MAP_SHARED;
76    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
77                                map_flags, fd, 0);
78
79    if (fd != -1)
80        close(fd);
81
82    if (pmem_addr == (void *)MAP_FAILED) {
83        perror("mmap");
84        fatal("Could not mmap!\n");
85    }
86
87    page_ptr = 0;
88}
89#endif
90
91PhysicalMemory::PhysicalMemory(const string &n)
92    : FunctionalMemory(n), base_addr(0), pmem_addr(NULL)
93{
94    // Hardcoded to 128 MB for now.
95    pmem_size = 1 << 27;
96
97    if (pmem_size % TheISA::PageBytes != 0)
98        panic("Memory Size not divisible by page size\n");
99
100    int map_flags = MAP_ANON | MAP_PRIVATE;
101    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
102                                map_flags, -1, 0);
103
104    if (pmem_addr == (void *)MAP_FAILED) {
105        perror("mmap");
106        fatal("Could not mmap!\n");
107    }
108
109    page_ptr = 0;
110}
111
112PhysicalMemory::~PhysicalMemory()
113{
114    if (pmem_addr)
115        munmap(pmem_addr, pmem_size);
116}
117
118Addr
119PhysicalMemory::new_page()
120{
121    Addr return_addr = page_ptr << LogVMPageSize;
122    return_addr += base_addr;
123
124    ++page_ptr;
125    return return_addr;
126}
127
128//
129// little helper for better prot_* error messages
130//
131void
132PhysicalMemory::prot_access_error(Addr addr, int size, const string &func)
133{
134    panic("invalid physical memory access!\n"
135          "%s: %s(addr=%#x, size=%d) out of range (max=%#x)\n",
136          name(), func, addr, size, pmem_size - 1);
137}
138
139void
140PhysicalMemory::prot_read(Addr addr, uint8_t *p, int size)
141{
142    if (addr + size >= pmem_size)
143        prot_access_error(addr, size, "prot_read");
144
145    memcpy(p, pmem_addr + addr - base_addr, size);
146}
147
148void
149PhysicalMemory::prot_write(Addr addr, const uint8_t *p, int size)
150{
151    if (addr + size >= pmem_size)
152        prot_access_error(addr, size, "prot_write");
153
154    memcpy(pmem_addr + addr - base_addr, p, size);
155}
156
157void
158PhysicalMemory::prot_memset(Addr addr, uint8_t val, int size)
159{
160    if (addr + size >= pmem_size)
161        prot_access_error(addr, size, "prot_memset");
162
163    memset(pmem_addr + addr - base_addr, val, size);
164}
165
166void
167PhysicalMemory::serialize(ostream &os)
168{
169    gzFile compressedMem;
170    string filename = name() + ".physmem";
171
172    SERIALIZE_SCALAR(pmem_size);
173    SERIALIZE_SCALAR(filename);
174
175    // write memory file
176    string thefile = Checkpoint::dir() + "/" + filename.c_str();
177    int fd = creat(thefile.c_str(), 0664);
178    if (fd < 0) {
179        perror("creat");
180        fatal("Can't open physical memory checkpoint file '%s'\n", filename);
181    }
182
183    compressedMem = gzdopen(fd, "wb");
184    if (compressedMem == NULL)
185        fatal("Insufficient memory to allocate compression state for %s\n",
186                filename);
187
188    if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
189        fatal("Write failed on physical memory checkpoint file '%s'\n",
190              filename);
191    }
192
193    if (gzclose(compressedMem))
194        fatal("Close failed on physical memory checkpoint file '%s'\n",
195              filename);
196}
197
198void
199PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
200{
201    gzFile compressedMem;
202    long *tempPage;
203    long *pmem_current;
204    uint64_t curSize;
205    uint32_t bytesRead;
206    const int chunkSize = 16384;
207
208
209    // unmap file that was mmaped in the constructor
210    munmap(pmem_addr, pmem_size);
211
212    string filename;
213
214    UNSERIALIZE_SCALAR(pmem_size);
215    UNSERIALIZE_SCALAR(filename);
216
217    filename = cp->cptDir + "/" + filename;
218
219    // mmap memoryfile
220    int fd = open(filename.c_str(), O_RDONLY);
221    if (fd < 0) {
222        perror("open");
223        fatal("Can't open physical memory checkpoint file '%s'", filename);
224    }
225
226    compressedMem = gzdopen(fd, "rb");
227    if (compressedMem == NULL)
228        fatal("Insufficient memory to allocate compression state for %s\n",
229                filename);
230
231
232    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
233                                MAP_ANON | MAP_PRIVATE, -1, 0);
234
235    if (pmem_addr == (void *)MAP_FAILED) {
236        perror("mmap");
237        fatal("Could not mmap physical memory!\n");
238    }
239
240    curSize = 0;
241    tempPage = (long*)malloc(chunkSize);
242    if (tempPage == NULL)
243        fatal("Unable to malloc memory to read file %s\n", filename);
244
245    /* Only copy bytes that are non-zero, so we don't give the VM system hell */
246    while (curSize < pmem_size) {
247        bytesRead = gzread(compressedMem, tempPage, chunkSize);
248        if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
249            fatal("Read failed on physical memory checkpoint file '%s'"
250                  " got %d bytes, expected %d or %d bytes\n",
251                  filename, bytesRead, chunkSize, pmem_size-curSize);
252
253        assert(bytesRead % sizeof(long) == 0);
254
255        for (int x = 0; x < bytesRead/sizeof(long); x++)
256        {
257             if (*(tempPage+x) != 0) {
258                 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
259                 *pmem_current = *(tempPage+x);
260             }
261        }
262        curSize += bytesRead;
263    }
264
265    free(tempPage);
266
267    if (gzclose(compressedMem))
268        fatal("Close failed on physical memory checkpoint file '%s'\n",
269              filename);
270
271}
272
273BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
274
275    Param<string> file;
276#if FULL_SYSTEM
277    SimObjectParam<MemoryController *> mmu;
278#endif
279    Param<Range<Addr> > range;
280
281END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
282
283BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
284
285    INIT_PARAM_DFLT(file, "memory mapped file", ""),
286#if FULL_SYSTEM
287    INIT_PARAM(mmu, "Memory Controller"),
288#endif
289    INIT_PARAM(range, "Device Address Range")
290
291END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
292
293CREATE_SIM_OBJECT(PhysicalMemory)
294{
295#if FULL_SYSTEM
296    if (mmu) {
297        return new PhysicalMemory(getInstanceName(), range, mmu, file);
298    }
299#endif
300
301    return new PhysicalMemory(getInstanceName());
302}
303
304REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
305