Minor further cleanup & commenting of Packet class.
[gem5.git] / src / mem / physical.cc
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 <iostream>
37 #include <string>
38
39
40 #include "base/misc.hh"
41 #include "config/full_system.hh"
42 #include "mem/packet_impl.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
50 using namespace std;
51 using namespace TheISA;
52
53 PhysicalMemory::MemResponseEvent::MemResponseEvent(Packet *pkt, MemoryPort* _m)
54 : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m)
55 {
56
57 this->setFlags(AutoDelete);
58 }
59
60 void
61 PhysicalMemory::MemResponseEvent::process()
62 {
63 memoryPort->sendTiming(pkt);
64 }
65
66 const char *
67 PhysicalMemory::MemResponseEvent::description()
68 {
69 return "Physical Memory Timing Access respnse event";
70 }
71
72 PhysicalMemory::PhysicalMemory(const string &n, Tick latency)
73 : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency)
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
93 void
94 PhysicalMemory::init()
95 {
96 if (!port)
97 panic("PhysicalMemory not connected to anything!");
98 port->sendStatusChange(Port::RangeChange);
99 }
100
101 PhysicalMemory::~PhysicalMemory()
102 {
103 if (pmem_addr)
104 munmap(pmem_addr, pmem_size);
105 //Remove memPorts?
106 }
107
108 Addr
109 PhysicalMemory::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
118 int
119 PhysicalMemory::deviceBlockSize()
120 {
121 //Can accept anysize request
122 return 0;
123 }
124
125 bool
126 PhysicalMemory::doTimingAccess (Packet *pkt, MemoryPort* memoryPort)
127 {
128 doFunctionalAccess(pkt);
129
130 // turn packet around to go back to requester
131 pkt->makeTimingResponse();
132 MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort);
133 response->schedule(curTick + lat);
134
135 return true;
136 }
137
138 Tick
139 PhysicalMemory::doAtomicAccess(Packet *pkt)
140 {
141 doFunctionalAccess(pkt);
142 return lat;
143 }
144
145 void
146 PhysicalMemory::doFunctionalAccess(Packet *pkt)
147 {
148 assert(pkt->getAddr() + pkt->getSize() < pmem_size);
149
150 switch (pkt->cmd) {
151 case Packet::ReadReq:
152 memcpy(pkt->getPtr<uint8_t>(),
153 pmem_addr + pkt->getAddr() - base_addr,
154 pkt->getSize());
155 break;
156 case Packet::WriteReq:
157 memcpy(pmem_addr + pkt->getAddr() - base_addr,
158 pkt->getPtr<uint8_t>(),
159 pkt->getSize());
160 // temporary hack: will need to add real LL/SC implementation
161 // for cacheless systems later.
162 if (pkt->req->getFlags() & LOCKED) {
163 pkt->req->setScResult(1);
164 }
165 break;
166 default:
167 panic("unimplemented");
168 }
169
170 pkt->result = Packet::Success;
171 }
172
173 Port *
174 PhysicalMemory::getPort(const std::string &if_name)
175 {
176 if (if_name == "") {
177 if (port != NULL)
178 panic("PhysicalMemory::getPort: additional port requested to memory!");
179 port = new MemoryPort(name() + "-port", this);
180 return port;
181 } else if (if_name == "functional") {
182 /* special port for functional writes at startup. */
183 return new MemoryPort(name() + "-funcport", this);
184 } else {
185 panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
186 }
187 }
188
189 void
190 PhysicalMemory::recvStatusChange(Port::Status status)
191 {
192 }
193
194 PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
195 PhysicalMemory *_memory)
196 : Port(_name), memory(_memory)
197 { }
198
199 void
200 PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
201 {
202 memory->recvStatusChange(status);
203 }
204
205 void
206 PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
207 AddrRangeList &snoop)
208 {
209 memory->getAddressRanges(resp, snoop);
210 }
211
212 void
213 PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
214 {
215 snoop.clear();
216 resp.clear();
217 resp.push_back(RangeSize(base_addr, pmem_size));
218 }
219
220 int
221 PhysicalMemory::MemoryPort::deviceBlockSize()
222 {
223 return memory->deviceBlockSize();
224 }
225
226 bool
227 PhysicalMemory::MemoryPort::recvTiming(Packet *pkt)
228 {
229 return memory->doTimingAccess(pkt, this);
230 }
231
232 Tick
233 PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
234 {
235 return memory->doAtomicAccess(pkt);
236 }
237
238 void
239 PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt)
240 {
241 memory->doFunctionalAccess(pkt);
242 }
243
244
245
246 void
247 PhysicalMemory::serialize(ostream &os)
248 {
249 gzFile compressedMem;
250 string filename = name() + ".physmem";
251
252 SERIALIZE_SCALAR(pmem_size);
253 SERIALIZE_SCALAR(filename);
254
255 // write memory file
256 string thefile = Checkpoint::dir() + "/" + filename.c_str();
257 int fd = creat(thefile.c_str(), 0664);
258 if (fd < 0) {
259 perror("creat");
260 fatal("Can't open physical memory checkpoint file '%s'\n", filename);
261 }
262
263 compressedMem = gzdopen(fd, "wb");
264 if (compressedMem == NULL)
265 fatal("Insufficient memory to allocate compression state for %s\n",
266 filename);
267
268 if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
269 fatal("Write failed on physical memory checkpoint file '%s'\n",
270 filename);
271 }
272
273 if (gzclose(compressedMem))
274 fatal("Close failed on physical memory checkpoint file '%s'\n",
275 filename);
276 }
277
278 void
279 PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
280 {
281 gzFile compressedMem;
282 long *tempPage;
283 long *pmem_current;
284 uint64_t curSize;
285 uint32_t bytesRead;
286 const int chunkSize = 16384;
287
288
289 // unmap file that was mmaped in the constructor
290 munmap(pmem_addr, pmem_size);
291
292 string filename;
293
294 UNSERIALIZE_SCALAR(pmem_size);
295 UNSERIALIZE_SCALAR(filename);
296
297 filename = cp->cptDir + "/" + filename;
298
299 // mmap memoryfile
300 int fd = open(filename.c_str(), O_RDONLY);
301 if (fd < 0) {
302 perror("open");
303 fatal("Can't open physical memory checkpoint file '%s'", filename);
304 }
305
306 compressedMem = gzdopen(fd, "rb");
307 if (compressedMem == NULL)
308 fatal("Insufficient memory to allocate compression state for %s\n",
309 filename);
310
311
312 pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
313 MAP_ANON | MAP_PRIVATE, -1, 0);
314
315 if (pmem_addr == (void *)MAP_FAILED) {
316 perror("mmap");
317 fatal("Could not mmap physical memory!\n");
318 }
319
320 curSize = 0;
321 tempPage = (long*)malloc(chunkSize);
322 if (tempPage == NULL)
323 fatal("Unable to malloc memory to read file %s\n", filename);
324
325 /* Only copy bytes that are non-zero, so we don't give the VM system hell */
326 while (curSize < pmem_size) {
327 bytesRead = gzread(compressedMem, tempPage, chunkSize);
328 if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
329 fatal("Read failed on physical memory checkpoint file '%s'"
330 " got %d bytes, expected %d or %d bytes\n",
331 filename, bytesRead, chunkSize, pmem_size-curSize);
332
333 assert(bytesRead % sizeof(long) == 0);
334
335 for (int x = 0; x < bytesRead/sizeof(long); x++)
336 {
337 if (*(tempPage+x) != 0) {
338 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
339 *pmem_current = *(tempPage+x);
340 }
341 }
342 curSize += bytesRead;
343 }
344
345 free(tempPage);
346
347 if (gzclose(compressedMem))
348 fatal("Close failed on physical memory checkpoint file '%s'\n",
349 filename);
350
351 }
352
353
354 BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
355
356 Param<string> file;
357 Param<Range<Addr> > range;
358 Param<Tick> latency;
359
360 END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
361
362 BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
363
364 INIT_PARAM_DFLT(file, "memory mapped file", ""),
365 INIT_PARAM(range, "Device Address Range"),
366 INIT_PARAM(latency, "Memory access latency")
367
368 END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
369
370 CREATE_SIM_OBJECT(PhysicalMemory)
371 {
372
373 return new PhysicalMemory(getInstanceName(), latency);
374 }
375
376 REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)