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