physical.cc (2914:2c524dc023d2) physical.cc (3012:1d5e18f6a100)
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 * Authors: Ron Dreslinski
29 * Ali Saidi
30 */
31
32#include <sys/types.h>
33#include <sys/mman.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <unistd.h>
37#include <zlib.h>
38
39#include <iostream>
40#include <string>
41
42
43#include "base/misc.hh"
44#include "config/full_system.hh"
45#include "mem/packet_impl.hh"
46#include "mem/physical.hh"
47#include "sim/host.hh"
48#include "sim/builder.hh"
49#include "sim/eventq.hh"
50#include "arch/isa_traits.hh"
51
52
53using namespace std;
54using namespace TheISA;
55
56
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 * Authors: Ron Dreslinski
29 * Ali Saidi
30 */
31
32#include <sys/types.h>
33#include <sys/mman.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <unistd.h>
37#include <zlib.h>
38
39#include <iostream>
40#include <string>
41
42
43#include "base/misc.hh"
44#include "config/full_system.hh"
45#include "mem/packet_impl.hh"
46#include "mem/physical.hh"
47#include "sim/host.hh"
48#include "sim/builder.hh"
49#include "sim/eventq.hh"
50#include "arch/isa_traits.hh"
51
52
53using namespace std;
54using namespace TheISA;
55
56
57PhysicalMemory::PhysicalMemory(const string &n, Tick latency)
58 : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency)
57PhysicalMemory::PhysicalMemory(Params *p)
58 : MemObject(p->name), pmemAddr(NULL), port(NULL), lat(p->latency), _params(p)
59{
59{
60 // Hardcoded to 128 MB for now.
61 pmem_size = 1 << 27;
62
63 if (pmem_size % TheISA::PageBytes != 0)
60 if (params()->addrRange.size() % TheISA::PageBytes != 0)
64 panic("Memory Size not divisible by page size\n");
65
66 int map_flags = MAP_ANON | MAP_PRIVATE;
61 panic("Memory Size not divisible by page size\n");
62
63 int map_flags = MAP_ANON | MAP_PRIVATE;
67 pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
64 pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
68 map_flags, -1, 0);
69
65 map_flags, -1, 0);
66
70 if (pmem_addr == (void *)MAP_FAILED) {
67 if (pmemAddr == (void *)MAP_FAILED) {
71 perror("mmap");
72 fatal("Could not mmap!\n");
73 }
74
68 perror("mmap");
69 fatal("Could not mmap!\n");
70 }
71
75 page_ptr = 0;
72 pagePtr = 0;
76}
77
78void
79PhysicalMemory::init()
80{
81 if (!port)
82 panic("PhysicalMemory not connected to anything!");
83 port->sendStatusChange(Port::RangeChange);
84}
85
86PhysicalMemory::~PhysicalMemory()
87{
73}
74
75void
76PhysicalMemory::init()
77{
78 if (!port)
79 panic("PhysicalMemory not connected to anything!");
80 port->sendStatusChange(Port::RangeChange);
81}
82
83PhysicalMemory::~PhysicalMemory()
84{
88 if (pmem_addr)
89 munmap(pmem_addr, pmem_size);
85 if (pmemAddr)
86 munmap(pmemAddr, params()->addrRange.size());
90 //Remove memPorts?
91}
92
93Addr
94PhysicalMemory::new_page()
95{
87 //Remove memPorts?
88}
89
90Addr
91PhysicalMemory::new_page()
92{
96 Addr return_addr = page_ptr << LogVMPageSize;
97 return_addr += base_addr;
93 Addr return_addr = pagePtr << LogVMPageSize;
94 return_addr += params()->addrRange.start;
98
95
99 ++page_ptr;
96 ++pagePtr;
100 return return_addr;
101}
102
103int
104PhysicalMemory::deviceBlockSize()
105{
106 //Can accept anysize request
107 return 0;
108}
109
97 return return_addr;
98}
99
100int
101PhysicalMemory::deviceBlockSize()
102{
103 //Can accept anysize request
104 return 0;
105}
106
107Tick
108PhysicalMemory::calculateLatency(Packet *pkt)
109{
110 return lat;
111}
110
111Tick
112PhysicalMemory::doFunctionalAccess(Packet *pkt)
113{
112
113Tick
114PhysicalMemory::doFunctionalAccess(Packet *pkt)
115{
114 assert(pkt->getAddr() + pkt->getSize() < pmem_size);
116 assert(pkt->getAddr() + pkt->getSize() < params()->addrRange.size());
115
116 switch (pkt->cmd) {
117 case Packet::ReadReq:
118 memcpy(pkt->getPtr<uint8_t>(),
117
118 switch (pkt->cmd) {
119 case Packet::ReadReq:
120 memcpy(pkt->getPtr<uint8_t>(),
119 pmem_addr + pkt->getAddr() - base_addr,
121 pmemAddr + pkt->getAddr() - params()->addrRange.start,
120 pkt->getSize());
121 break;
122 case Packet::WriteReq:
122 pkt->getSize());
123 break;
124 case Packet::WriteReq:
123 memcpy(pmem_addr + pkt->getAddr() - base_addr,
125 memcpy(pmemAddr + pkt->getAddr() - params()->addrRange.start,
124 pkt->getPtr<uint8_t>(),
125 pkt->getSize());
126 // temporary hack: will need to add real LL/SC implementation
127 // for cacheless systems later.
128 if (pkt->req->getFlags() & LOCKED) {
129 pkt->req->setScResult(1);
130 }
131 break;
132 default:
133 panic("unimplemented");
134 }
135
136 pkt->result = Packet::Success;
126 pkt->getPtr<uint8_t>(),
127 pkt->getSize());
128 // temporary hack: will need to add real LL/SC implementation
129 // for cacheless systems later.
130 if (pkt->req->getFlags() & LOCKED) {
131 pkt->req->setScResult(1);
132 }
133 break;
134 default:
135 panic("unimplemented");
136 }
137
138 pkt->result = Packet::Success;
137 return lat;
139 return calculateLatency(pkt);
138}
139
140Port *
141PhysicalMemory::getPort(const std::string &if_name, int idx)
142{
143 if (if_name == "port" && idx == -1) {
144 if (port != NULL)
145 panic("PhysicalMemory::getPort: additional port requested to memory!");
146 port = new MemoryPort(name() + "-port", this);
147 return port;
148 } else if (if_name == "functional") {
149 /* special port for functional writes at startup. */
150 return new MemoryPort(name() + "-funcport", this);
151 } else {
152 panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
153 }
154}
155
156void
157PhysicalMemory::recvStatusChange(Port::Status status)
158{
159}
160
161PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
162 PhysicalMemory *_memory)
163 : SimpleTimingPort(_name), memory(_memory)
164{ }
165
166void
167PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
168{
169 memory->recvStatusChange(status);
170}
171
172void
173PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
174 AddrRangeList &snoop)
175{
176 memory->getAddressRanges(resp, snoop);
177}
178
179void
180PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
181{
182 snoop.clear();
183 resp.clear();
140}
141
142Port *
143PhysicalMemory::getPort(const std::string &if_name, int idx)
144{
145 if (if_name == "port" && idx == -1) {
146 if (port != NULL)
147 panic("PhysicalMemory::getPort: additional port requested to memory!");
148 port = new MemoryPort(name() + "-port", this);
149 return port;
150 } else if (if_name == "functional") {
151 /* special port for functional writes at startup. */
152 return new MemoryPort(name() + "-funcport", this);
153 } else {
154 panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
155 }
156}
157
158void
159PhysicalMemory::recvStatusChange(Port::Status status)
160{
161}
162
163PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
164 PhysicalMemory *_memory)
165 : SimpleTimingPort(_name), memory(_memory)
166{ }
167
168void
169PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
170{
171 memory->recvStatusChange(status);
172}
173
174void
175PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
176 AddrRangeList &snoop)
177{
178 memory->getAddressRanges(resp, snoop);
179}
180
181void
182PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
183{
184 snoop.clear();
185 resp.clear();
184 resp.push_back(RangeSize(base_addr, pmem_size));
186 resp.push_back(RangeSize(params()->addrRange.start, params()->addrRange.size()));
185}
186
187int
188PhysicalMemory::MemoryPort::deviceBlockSize()
189{
190 return memory->deviceBlockSize();
191}
192
193bool
194PhysicalMemory::MemoryPort::recvTiming(Packet *pkt)
195{
196 assert(pkt->result != Packet::Nacked);
197
198 Tick latency = memory->doFunctionalAccess(pkt);
199
200 pkt->makeTimingResponse();
201 sendTiming(pkt, latency);
202
203 return true;
204}
205
206Tick
207PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
208{
209 return memory->doFunctionalAccess(pkt);
210}
211
212void
213PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt)
214{
215 memory->doFunctionalAccess(pkt);
216}
217
218unsigned int
219PhysicalMemory::drain(Event *de)
220{
221 int count = port->drain(de);
222 if (count)
223 changeState(Draining);
224 else
225 changeState(Drained);
226 return count;
227}
228
229void
230PhysicalMemory::serialize(ostream &os)
231{
232 gzFile compressedMem;
233 string filename = name() + ".physmem";
234
187}
188
189int
190PhysicalMemory::MemoryPort::deviceBlockSize()
191{
192 return memory->deviceBlockSize();
193}
194
195bool
196PhysicalMemory::MemoryPort::recvTiming(Packet *pkt)
197{
198 assert(pkt->result != Packet::Nacked);
199
200 Tick latency = memory->doFunctionalAccess(pkt);
201
202 pkt->makeTimingResponse();
203 sendTiming(pkt, latency);
204
205 return true;
206}
207
208Tick
209PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
210{
211 return memory->doFunctionalAccess(pkt);
212}
213
214void
215PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt)
216{
217 memory->doFunctionalAccess(pkt);
218}
219
220unsigned int
221PhysicalMemory::drain(Event *de)
222{
223 int count = port->drain(de);
224 if (count)
225 changeState(Draining);
226 else
227 changeState(Drained);
228 return count;
229}
230
231void
232PhysicalMemory::serialize(ostream &os)
233{
234 gzFile compressedMem;
235 string filename = name() + ".physmem";
236
235 SERIALIZE_SCALAR(pmem_size);
236 SERIALIZE_SCALAR(filename);
237
238 // write memory file
239 string thefile = Checkpoint::dir() + "/" + filename.c_str();
240 int fd = creat(thefile.c_str(), 0664);
241 if (fd < 0) {
242 perror("creat");
243 fatal("Can't open physical memory checkpoint file '%s'\n", filename);
244 }
245
246 compressedMem = gzdopen(fd, "wb");
247 if (compressedMem == NULL)
248 fatal("Insufficient memory to allocate compression state for %s\n",
249 filename);
250
237 SERIALIZE_SCALAR(filename);
238
239 // write memory file
240 string thefile = Checkpoint::dir() + "/" + filename.c_str();
241 int fd = creat(thefile.c_str(), 0664);
242 if (fd < 0) {
243 perror("creat");
244 fatal("Can't open physical memory checkpoint file '%s'\n", filename);
245 }
246
247 compressedMem = gzdopen(fd, "wb");
248 if (compressedMem == NULL)
249 fatal("Insufficient memory to allocate compression state for %s\n",
250 filename);
251
251 if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
252 if (gzwrite(compressedMem, pmemAddr, params()->addrRange.size()) != params()->addrRange.size()) {
252 fatal("Write failed on physical memory checkpoint file '%s'\n",
253 filename);
254 }
255
256 if (gzclose(compressedMem))
257 fatal("Close failed on physical memory checkpoint file '%s'\n",
258 filename);
259}
260
261void
262PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
263{
264 gzFile compressedMem;
265 long *tempPage;
266 long *pmem_current;
267 uint64_t curSize;
268 uint32_t bytesRead;
269 const int chunkSize = 16384;
270
271
253 fatal("Write failed on physical memory checkpoint file '%s'\n",
254 filename);
255 }
256
257 if (gzclose(compressedMem))
258 fatal("Close failed on physical memory checkpoint file '%s'\n",
259 filename);
260}
261
262void
263PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
264{
265 gzFile compressedMem;
266 long *tempPage;
267 long *pmem_current;
268 uint64_t curSize;
269 uint32_t bytesRead;
270 const int chunkSize = 16384;
271
272
272 // unmap file that was mmaped in the constructor
273 munmap(pmem_addr, pmem_size);
274
275 string filename;
276
273 string filename;
274
277 UNSERIALIZE_SCALAR(pmem_size);
278 UNSERIALIZE_SCALAR(filename);
279
280 filename = cp->cptDir + "/" + filename;
281
282 // mmap memoryfile
283 int fd = open(filename.c_str(), O_RDONLY);
284 if (fd < 0) {
285 perror("open");
286 fatal("Can't open physical memory checkpoint file '%s'", filename);
287 }
288
289 compressedMem = gzdopen(fd, "rb");
290 if (compressedMem == NULL)
291 fatal("Insufficient memory to allocate compression state for %s\n",
292 filename);
293
275 UNSERIALIZE_SCALAR(filename);
276
277 filename = cp->cptDir + "/" + filename;
278
279 // mmap memoryfile
280 int fd = open(filename.c_str(), O_RDONLY);
281 if (fd < 0) {
282 perror("open");
283 fatal("Can't open physical memory checkpoint file '%s'", filename);
284 }
285
286 compressedMem = gzdopen(fd, "rb");
287 if (compressedMem == NULL)
288 fatal("Insufficient memory to allocate compression state for %s\n",
289 filename);
290
291 // unmap file that was mmaped in the constructor
292 // This is done here to make sure that gzip and open don't muck with our
293 // nice large space of memory before we reallocate it
294 munmap(pmemAddr, params()->addrRange.size());
294
295
295 pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
296 pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
296 MAP_ANON | MAP_PRIVATE, -1, 0);
297
297 MAP_ANON | MAP_PRIVATE, -1, 0);
298
298 if (pmem_addr == (void *)MAP_FAILED) {
299 if (pmemAddr == (void *)MAP_FAILED) {
299 perror("mmap");
300 fatal("Could not mmap physical memory!\n");
301 }
302
303 curSize = 0;
304 tempPage = (long*)malloc(chunkSize);
305 if (tempPage == NULL)
306 fatal("Unable to malloc memory to read file %s\n", filename);
307
308 /* Only copy bytes that are non-zero, so we don't give the VM system hell */
300 perror("mmap");
301 fatal("Could not mmap physical memory!\n");
302 }
303
304 curSize = 0;
305 tempPage = (long*)malloc(chunkSize);
306 if (tempPage == NULL)
307 fatal("Unable to malloc memory to read file %s\n", filename);
308
309 /* Only copy bytes that are non-zero, so we don't give the VM system hell */
309 while (curSize < pmem_size) {
310 while (curSize < params()->addrRange.size()) {
310 bytesRead = gzread(compressedMem, tempPage, chunkSize);
311 bytesRead = gzread(compressedMem, tempPage, chunkSize);
311 if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
312 if (bytesRead != chunkSize && bytesRead != params()->addrRange.size() - curSize)
312 fatal("Read failed on physical memory checkpoint file '%s'"
313 " got %d bytes, expected %d or %d bytes\n",
313 fatal("Read failed on physical memory checkpoint file '%s'"
314 " got %d bytes, expected %d or %d bytes\n",
314 filename, bytesRead, chunkSize, pmem_size-curSize);
315 filename, bytesRead, chunkSize, params()->addrRange.size()-curSize);
315
316 assert(bytesRead % sizeof(long) == 0);
317
318 for (int x = 0; x < bytesRead/sizeof(long); x++)
319 {
320 if (*(tempPage+x) != 0) {
316
317 assert(bytesRead % sizeof(long) == 0);
318
319 for (int x = 0; x < bytesRead/sizeof(long); x++)
320 {
321 if (*(tempPage+x) != 0) {
321 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
322 pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long));
322 *pmem_current = *(tempPage+x);
323 }
324 }
325 curSize += bytesRead;
326 }
327
328 free(tempPage);
329
330 if (gzclose(compressedMem))
331 fatal("Close failed on physical memory checkpoint file '%s'\n",
332 filename);
333
334}
335
336
337BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
338
339 Param<string> file;
340 Param<Range<Addr> > range;
341 Param<Tick> latency;
342
343END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
344
345BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
346
347 INIT_PARAM_DFLT(file, "memory mapped file", ""),
348 INIT_PARAM(range, "Device Address Range"),
349 INIT_PARAM(latency, "Memory access latency")
350
351END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
352
353CREATE_SIM_OBJECT(PhysicalMemory)
354{
323 *pmem_current = *(tempPage+x);
324 }
325 }
326 curSize += bytesRead;
327 }
328
329 free(tempPage);
330
331 if (gzclose(compressedMem))
332 fatal("Close failed on physical memory checkpoint file '%s'\n",
333 filename);
334
335}
336
337
338BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
339
340 Param<string> file;
341 Param<Range<Addr> > range;
342 Param<Tick> latency;
343
344END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
345
346BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
347
348 INIT_PARAM_DFLT(file, "memory mapped file", ""),
349 INIT_PARAM(range, "Device Address Range"),
350 INIT_PARAM(latency, "Memory access latency")
351
352END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
353
354CREATE_SIM_OBJECT(PhysicalMemory)
355{
355
356 return new PhysicalMemory(getInstanceName(), latency);
356 PhysicalMemory::Params *p = new PhysicalMemory::Params;
357 p->name = getInstanceName();
358 p->addrRange = range;
359 p->latency = latency;
360 return new PhysicalMemory(p);
357}
358
359REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
361}
362
363REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)