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