physical.cc revision 2630
17585SAli.Saidi@arm.com/*
27585SAli.Saidi@arm.com * Copyright (c) 2001-2005 The Regents of The University of Michigan
37585SAli.Saidi@arm.com * All rights reserved.
47585SAli.Saidi@arm.com *
57585SAli.Saidi@arm.com * Redistribution and use in source and binary forms, with or without
67585SAli.Saidi@arm.com * modification, are permitted provided that the following conditions are
77585SAli.Saidi@arm.com * met: redistributions of source code must retain the above copyright
87585SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer;
97585SAli.Saidi@arm.com * redistributions in binary form must reproduce the above copyright
107585SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer in the
117585SAli.Saidi@arm.com * documentation and/or other materials provided with the distribution;
127585SAli.Saidi@arm.com * neither the name of the copyright holders nor the names of its
137585SAli.Saidi@arm.com * contributors may be used to endorse or promote products derived from
147585SAli.Saidi@arm.com * this software without specific prior written permission.
157585SAli.Saidi@arm.com *
167585SAli.Saidi@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177585SAli.Saidi@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187585SAli.Saidi@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197585SAli.Saidi@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207585SAli.Saidi@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217585SAli.Saidi@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227585SAli.Saidi@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237585SAli.Saidi@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247585SAli.Saidi@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257585SAli.Saidi@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
267585SAli.Saidi@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277585SAli.Saidi@arm.com */
287585SAli.Saidi@arm.com
297585SAli.Saidi@arm.com#include <sys/types.h>
307585SAli.Saidi@arm.com#include <sys/mman.h>
317585SAli.Saidi@arm.com#include <errno.h>
327585SAli.Saidi@arm.com#include <fcntl.h>
337585SAli.Saidi@arm.com#include <unistd.h>
347585SAli.Saidi@arm.com#include <zlib.h>
357585SAli.Saidi@arm.com
367585SAli.Saidi@arm.com#include <iostream>
377585SAli.Saidi@arm.com#include <string>
387585SAli.Saidi@arm.com
397585SAli.Saidi@arm.com
407585SAli.Saidi@arm.com#include "base/misc.hh"
417585SAli.Saidi@arm.com#include "config/full_system.hh"
427585SAli.Saidi@arm.com#include "mem/packet_impl.hh"
437585SAli.Saidi@arm.com#include "mem/physical.hh"
447585SAli.Saidi@arm.com#include "sim/host.hh"
457585SAli.Saidi@arm.com#include "sim/builder.hh"
467585SAli.Saidi@arm.com#include "sim/eventq.hh"
477585SAli.Saidi@arm.com#include "arch/isa_traits.hh"
487585SAli.Saidi@arm.com
497585SAli.Saidi@arm.com
507585SAli.Saidi@arm.comusing namespace std;
517585SAli.Saidi@arm.comusing namespace TheISA;
527585SAli.Saidi@arm.com
537585SAli.Saidi@arm.comPhysicalMemory::MemResponseEvent::MemResponseEvent(Packet *pkt, MemoryPort* _m)
547585SAli.Saidi@arm.com    : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m)
557585SAli.Saidi@arm.com{
567585SAli.Saidi@arm.com
577585SAli.Saidi@arm.com    this->setFlags(AutoDelete);
587585SAli.Saidi@arm.com}
597585SAli.Saidi@arm.com
607585SAli.Saidi@arm.comvoid
617585SAli.Saidi@arm.comPhysicalMemory::MemResponseEvent::process()
627585SAli.Saidi@arm.com{
637585SAli.Saidi@arm.com    memoryPort->sendTiming(pkt);
647585SAli.Saidi@arm.com}
657585SAli.Saidi@arm.com
667585SAli.Saidi@arm.comconst char *
677585SAli.Saidi@arm.comPhysicalMemory::MemResponseEvent::description()
687585SAli.Saidi@arm.com{
697585SAli.Saidi@arm.com    return "Physical Memory Timing Access respnse event";
707733SAli.Saidi@ARM.com}
717733SAli.Saidi@ARM.com
727585SAli.Saidi@arm.comPhysicalMemory::PhysicalMemory(const string &n, Tick latency)
737585SAli.Saidi@arm.com    : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency)
747585SAli.Saidi@arm.com{
757585SAli.Saidi@arm.com    // Hardcoded to 128 MB for now.
767585SAli.Saidi@arm.com    pmem_size = 1 << 27;
777585SAli.Saidi@arm.com
787585SAli.Saidi@arm.com    if (pmem_size % TheISA::PageBytes != 0)
797585SAli.Saidi@arm.com        panic("Memory Size not divisible by page size\n");
807585SAli.Saidi@arm.com
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    pkt->dest = pkt->src;
131    MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort);
132    response->schedule(curTick + lat);
133
134    return true;
135}
136
137Tick
138PhysicalMemory::doAtomicAccess(Packet *pkt)
139{
140    doFunctionalAccess(pkt);
141    pkt->time = curTick + lat;
142    return curTick + lat;
143}
144
145void
146PhysicalMemory::doFunctionalAccess(Packet *pkt)
147{
148    assert(pkt->addr + pkt->size < pmem_size);
149
150    switch (pkt->cmd) {
151      case Read:
152        memcpy(pkt->getPtr<uint8_t>(), pmem_addr + pkt->addr - base_addr,
153                pkt->size);
154        break;
155      case Write:
156        memcpy(pmem_addr + pkt->addr - base_addr, pkt->getPtr<uint8_t>(),
157                pkt->size);
158        break;
159      default:
160        panic("unimplemented");
161    }
162
163    pkt->result = Success;
164}
165
166Port *
167PhysicalMemory::getPort(const std::string &if_name)
168{
169    if (if_name == "") {
170        if (port != NULL)
171           panic("PhysicalMemory::getPort: additional port requested to memory!");
172        port = new MemoryPort(this);
173        return port;
174    } else if (if_name == "functional") {
175        /* special port for functional writes at startup. */
176        return new MemoryPort(this);
177    } else {
178        panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
179    }
180}
181
182void
183PhysicalMemory::recvStatusChange(Port::Status status)
184{
185}
186
187PhysicalMemory::MemoryPort::MemoryPort(PhysicalMemory *_memory)
188    : memory(_memory)
189{ }
190
191void
192PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
193{
194    memory->recvStatusChange(status);
195}
196
197void
198PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
199                                            AddrRangeList &snoop)
200{
201    memory->getAddressRanges(resp, snoop);
202}
203
204void
205PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
206{
207    snoop.clear();
208    resp.clear();
209    resp.push_back(RangeSize(base_addr, pmem_size));
210}
211
212int
213PhysicalMemory::MemoryPort::deviceBlockSize()
214{
215    return memory->deviceBlockSize();
216}
217
218bool
219PhysicalMemory::MemoryPort::recvTiming(Packet *pkt)
220{
221    return memory->doTimingAccess(pkt, this);
222}
223
224Tick
225PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
226{
227    return memory->doAtomicAccess(pkt);
228}
229
230void
231PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt)
232{
233    memory->doFunctionalAccess(pkt);
234}
235
236
237
238void
239PhysicalMemory::serialize(ostream &os)
240{
241    gzFile compressedMem;
242    string filename = name() + ".physmem";
243
244    SERIALIZE_SCALAR(pmem_size);
245    SERIALIZE_SCALAR(filename);
246
247    // write memory file
248    string thefile = Checkpoint::dir() + "/" + filename.c_str();
249    int fd = creat(thefile.c_str(), 0664);
250    if (fd < 0) {
251        perror("creat");
252        fatal("Can't open physical memory checkpoint file '%s'\n", filename);
253    }
254
255    compressedMem = gzdopen(fd, "wb");
256    if (compressedMem == NULL)
257        fatal("Insufficient memory to allocate compression state for %s\n",
258                filename);
259
260    if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
261        fatal("Write failed on physical memory checkpoint file '%s'\n",
262              filename);
263    }
264
265    if (gzclose(compressedMem))
266        fatal("Close failed on physical memory checkpoint file '%s'\n",
267              filename);
268}
269
270void
271PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
272{
273    gzFile compressedMem;
274    long *tempPage;
275    long *pmem_current;
276    uint64_t curSize;
277    uint32_t bytesRead;
278    const int chunkSize = 16384;
279
280
281    // unmap file that was mmaped in the constructor
282    munmap(pmem_addr, pmem_size);
283
284    string filename;
285
286    UNSERIALIZE_SCALAR(pmem_size);
287    UNSERIALIZE_SCALAR(filename);
288
289    filename = cp->cptDir + "/" + filename;
290
291    // mmap memoryfile
292    int fd = open(filename.c_str(), O_RDONLY);
293    if (fd < 0) {
294        perror("open");
295        fatal("Can't open physical memory checkpoint file '%s'", filename);
296    }
297
298    compressedMem = gzdopen(fd, "rb");
299    if (compressedMem == NULL)
300        fatal("Insufficient memory to allocate compression state for %s\n",
301                filename);
302
303
304    pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
305                                MAP_ANON | MAP_PRIVATE, -1, 0);
306
307    if (pmem_addr == (void *)MAP_FAILED) {
308        perror("mmap");
309        fatal("Could not mmap physical memory!\n");
310    }
311
312    curSize = 0;
313    tempPage = (long*)malloc(chunkSize);
314    if (tempPage == NULL)
315        fatal("Unable to malloc memory to read file %s\n", filename);
316
317    /* Only copy bytes that are non-zero, so we don't give the VM system hell */
318    while (curSize < pmem_size) {
319        bytesRead = gzread(compressedMem, tempPage, chunkSize);
320        if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
321            fatal("Read failed on physical memory checkpoint file '%s'"
322                  " got %d bytes, expected %d or %d bytes\n",
323                  filename, bytesRead, chunkSize, pmem_size-curSize);
324
325        assert(bytesRead % sizeof(long) == 0);
326
327        for (int x = 0; x < bytesRead/sizeof(long); x++)
328        {
329             if (*(tempPage+x) != 0) {
330                 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
331                 *pmem_current = *(tempPage+x);
332             }
333        }
334        curSize += bytesRead;
335    }
336
337    free(tempPage);
338
339    if (gzclose(compressedMem))
340        fatal("Close failed on physical memory checkpoint file '%s'\n",
341              filename);
342
343}
344
345
346BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
347
348    Param<string> file;
349    Param<Range<Addr> > range;
350    Param<Tick> latency;
351
352END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
353
354BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
355
356    INIT_PARAM_DFLT(file, "memory mapped file", ""),
357    INIT_PARAM(range, "Device Address Range"),
358    INIT_PARAM(latency, "Memory access latency")
359
360END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
361
362CREATE_SIM_OBJECT(PhysicalMemory)
363{
364
365    return new PhysicalMemory(getInstanceName(), latency);
366}
367
368REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
369