physical.cc revision 2541
14479Sbinkertn@umich.edu/*
24479Sbinkertn@umich.edu * Copyright (c) 2001-2005 The Regents of The University of Michigan
34479Sbinkertn@umich.edu * All rights reserved.
44479Sbinkertn@umich.edu *
54479Sbinkertn@umich.edu * Redistribution and use in source and binary forms, with or without
64479Sbinkertn@umich.edu * modification, are permitted provided that the following conditions are
74479Sbinkertn@umich.edu * met: redistributions of source code must retain the above copyright
84479Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer;
94479Sbinkertn@umich.edu * redistributions in binary form must reproduce the above copyright
104479Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer in the
114479Sbinkertn@umich.edu * documentation and/or other materials provided with the distribution;
124479Sbinkertn@umich.edu * neither the name of the copyright holders nor the names of its
134479Sbinkertn@umich.edu * contributors may be used to endorse or promote products derived from
144479Sbinkertn@umich.edu * this software without specific prior written permission.
154479Sbinkertn@umich.edu *
164479Sbinkertn@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
174479Sbinkertn@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
184479Sbinkertn@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
194479Sbinkertn@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
204479Sbinkertn@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
214479Sbinkertn@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
224479Sbinkertn@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
234479Sbinkertn@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
244479Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254479Sbinkertn@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
264479Sbinkertn@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274479Sbinkertn@umich.edu */
284479Sbinkertn@umich.edu
294479Sbinkertn@umich.edu#include <sys/types.h>
304479Sbinkertn@umich.edu#include <sys/mman.h>
314479Sbinkertn@umich.edu#include <errno.h>
324479Sbinkertn@umich.edu#include <fcntl.h>
334479Sbinkertn@umich.edu#include <unistd.h>
344479Sbinkertn@umich.edu#include <zlib.h>
354479Sbinkertn@umich.edu
364479Sbinkertn@umich.edu#include <cstdio>
374479Sbinkertn@umich.edu#include <iostream>
384479Sbinkertn@umich.edu#include <string>
394479Sbinkertn@umich.edu
404479Sbinkertn@umich.edu
414479Sbinkertn@umich.edu#include "base/misc.hh"
424479Sbinkertn@umich.edu#include "config/full_system.hh"
434479Sbinkertn@umich.edu#include "mem/physical.hh"
444479Sbinkertn@umich.edu#include "sim/host.hh"
454479Sbinkertn@umich.edu#include "sim/builder.hh"
464479Sbinkertn@umich.edu#include "sim/eventq.hh"
474479Sbinkertn@umich.edu#include "arch/isa_traits.hh"
484479Sbinkertn@umich.edu
494479Sbinkertn@umich.edu
504479Sbinkertn@umich.eduusing namespace std;
514479Sbinkertn@umich.eduusing namespace TheISA;
524479Sbinkertn@umich.edu
534479Sbinkertn@umich.eduPhysicalMemory::MemResponseEvent::MemResponseEvent(Packet &pkt, MemoryPort* _m)
544479Sbinkertn@umich.edu    : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m)
554479Sbinkertn@umich.edu{
564479Sbinkertn@umich.edu
574479Sbinkertn@umich.edu    this->setFlags(AutoDelete);
584479Sbinkertn@umich.edu}
594479Sbinkertn@umich.edu
604479Sbinkertn@umich.eduvoid
614479Sbinkertn@umich.eduPhysicalMemory::MemResponseEvent::process()
624479Sbinkertn@umich.edu{
634479Sbinkertn@umich.edu    memoryPort->sendTiming(pkt);
644479Sbinkertn@umich.edu}
654479Sbinkertn@umich.edu
664479Sbinkertn@umich.educonst char *
674479Sbinkertn@umich.eduPhysicalMemory::MemResponseEvent::description()
684479Sbinkertn@umich.edu{
694479Sbinkertn@umich.edu    return "Physical Memory Timing Access respnse event";
704479Sbinkertn@umich.edu}
714479Sbinkertn@umich.edu
724479Sbinkertn@umich.eduPhysicalMemory::PhysicalMemory(const string &n)
734479Sbinkertn@umich.edu    : MemObject(n), base_addr(0), pmem_addr(NULL), port(NULL)
744479Sbinkertn@umich.edu{
754479Sbinkertn@umich.edu    // Hardcoded to 128 MB for now.
764479Sbinkertn@umich.edu    pmem_size = 1 << 27;
774479Sbinkertn@umich.edu
784479Sbinkertn@umich.edu    if (pmem_size % TheISA::PageBytes != 0)
794479Sbinkertn@umich.edu        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
93void
94PhysicalMemory::init()
95{
96    if (!port)
97        panic("PhysicalMemory not connected to anything!");
98    port->sendStatusChange(Port::RangeChange);
99}
100
101PhysicalMemory::~PhysicalMemory()
102{
103    if (pmem_addr)
104        munmap(pmem_addr, pmem_size);
105    //Remove memPorts?
106}
107
108Addr
109PhysicalMemory::new_page()
110{
111    Addr return_addr = page_ptr << LogVMPageSize;
112    return_addr += base_addr;
113
114    ++page_ptr;
115    return return_addr;
116}
117
118int
119PhysicalMemory::deviceBlockSize()
120{
121    //Can accept anysize request
122    return 0;
123}
124
125bool
126PhysicalMemory::doTimingAccess (Packet &pkt, MemoryPort* memoryPort)
127{
128    doFunctionalAccess(pkt);
129
130    MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort);
131    response->schedule(curTick + lat);
132
133    return true;
134}
135
136Tick
137PhysicalMemory::doAtomicAccess(Packet &pkt)
138{
139    doFunctionalAccess(pkt);
140    return curTick + lat;
141}
142
143void
144PhysicalMemory::doFunctionalAccess(Packet &pkt)
145{
146    assert(pkt.addr + pkt.size < pmem_size);
147
148    switch (pkt.cmd) {
149      case Read:
150        memcpy(pkt.data, pmem_addr + pkt.addr - base_addr, pkt.size);
151        break;
152      case Write:
153        memcpy(pmem_addr + pkt.addr - base_addr, pkt.data, pkt.size);
154        break;
155      default:
156        panic("unimplemented");
157    }
158
159    pkt.result = Success;
160}
161
162Port *
163PhysicalMemory::getPort(const std::string &if_name)
164{
165    if (if_name == "") {
166        if (port != NULL)
167           panic("PhysicalMemory::getPort: additional port requested to memory!");
168        port = new MemoryPort(this);
169        return port;
170    } else if (if_name == "functional") {
171        /* special port for functional writes at startup. */
172        return new MemoryPort(this);
173    } else {
174        panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
175    }
176}
177
178void
179PhysicalMemory::recvStatusChange(Port::Status status)
180{
181    panic("??");
182}
183
184PhysicalMemory::MemoryPort::MemoryPort(PhysicalMemory *_memory)
185    : memory(_memory)
186{ }
187
188void
189PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
190{
191    memory->recvStatusChange(status);
192}
193
194void
195PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
196                                            AddrRangeList &snoop)
197{
198    memory->getAddressRanges(resp, snoop);
199}
200
201void
202PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
203{
204    snoop.clear();
205    resp.clear();
206    resp.push_back(RangeSize(base_addr, pmem_size));
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    Param<Range<Addr> > range;
347
348END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
349
350BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
351
352    INIT_PARAM_DFLT(file, "memory mapped file", ""),
353    INIT_PARAM(range, "Device Address Range")
354
355END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
356
357CREATE_SIM_OBJECT(PhysicalMemory)
358{
359
360    return new PhysicalMemory(getInstanceName());
361}
362
363REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
364