1/* 2 * Copyright (c) 2010-2011 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2001-2005 The Regents of The University of Michigan 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution; 24 * neither the name of the copyright holders nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Ron Dreslinski 41 * Ali Saidi 42 */ 43 44#include <sys/mman.h> 45#include <sys/types.h> 46#include <sys/user.h> 47#include <fcntl.h> 48#include <unistd.h> 49#include <zlib.h> 50 51#include <cerrno> 52#include <cstdio> 53#include <iostream> 54#include <string> 55 56#include "arch/isa_traits.hh" 57#include "arch/registers.hh" 58#include "base/intmath.hh" 59#include "base/misc.hh" 60#include "base/random.hh" 61#include "base/types.hh" 62#include "config/the_isa.hh" 63#include "debug/LLSC.hh" 64#include "debug/MemoryAccess.hh" 65#include "mem/packet_access.hh" 66#include "mem/physical.hh" 67#include "sim/eventq.hh" 68 69using namespace std; 70using namespace TheISA; 71 72PhysicalMemory::PhysicalMemory(const Params *p) 73 : MemObject(p), pmemAddr(NULL), lat(p->latency), lat_var(p->latency_var), 74 _size(params()->range.size()), _start(params()->range.start) 75{ 76 if (size() % TheISA::PageBytes != 0) 77 panic("Memory Size not divisible by page size\n"); 78 79 // create the appropriate number of ports 80 for (int i = 0; i < p->port_port_connection_count; ++i) { 81 ports.push_back(new MemoryPort(csprintf("%s-port%d", name(), i), 82 this)); 83 } 84 85 if (params()->null) 86 return; 87 88 89 if (params()->file == "") { 90 int map_flags = MAP_ANON | MAP_PRIVATE; 91 pmemAddr = (uint8_t *)mmap(NULL, size(), 92 PROT_READ | PROT_WRITE, map_flags, -1, 0); 93 } else { 94 int map_flags = MAP_PRIVATE; 95 int fd = open(params()->file.c_str(), O_RDONLY); 96 _size = lseek(fd, 0, SEEK_END); 97 lseek(fd, 0, SEEK_SET); 98 pmemAddr = (uint8_t *)mmap(NULL, roundUp(size(), sysconf(_SC_PAGESIZE)), 99 PROT_READ | PROT_WRITE, map_flags, fd, 0); 100 } 101 102 if (pmemAddr == (void *)MAP_FAILED) { 103 perror("mmap"); 104 if (params()->file == "") 105 fatal("Could not mmap!\n"); 106 else 107 fatal("Could not find file: %s\n", params()->file); 108 } 109 110 //If requested, initialize all the memory to 0 111 if (p->zero) 112 memset(pmemAddr, 0, size()); 113} 114 115void 116PhysicalMemory::init() 117{
| 1/* 2 * Copyright (c) 2010-2011 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2001-2005 The Regents of The University of Michigan 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution; 24 * neither the name of the copyright holders nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Ron Dreslinski 41 * Ali Saidi 42 */ 43 44#include <sys/mman.h> 45#include <sys/types.h> 46#include <sys/user.h> 47#include <fcntl.h> 48#include <unistd.h> 49#include <zlib.h> 50 51#include <cerrno> 52#include <cstdio> 53#include <iostream> 54#include <string> 55 56#include "arch/isa_traits.hh" 57#include "arch/registers.hh" 58#include "base/intmath.hh" 59#include "base/misc.hh" 60#include "base/random.hh" 61#include "base/types.hh" 62#include "config/the_isa.hh" 63#include "debug/LLSC.hh" 64#include "debug/MemoryAccess.hh" 65#include "mem/packet_access.hh" 66#include "mem/physical.hh" 67#include "sim/eventq.hh" 68 69using namespace std; 70using namespace TheISA; 71 72PhysicalMemory::PhysicalMemory(const Params *p) 73 : MemObject(p), pmemAddr(NULL), lat(p->latency), lat_var(p->latency_var), 74 _size(params()->range.size()), _start(params()->range.start) 75{ 76 if (size() % TheISA::PageBytes != 0) 77 panic("Memory Size not divisible by page size\n"); 78 79 // create the appropriate number of ports 80 for (int i = 0; i < p->port_port_connection_count; ++i) { 81 ports.push_back(new MemoryPort(csprintf("%s-port%d", name(), i), 82 this)); 83 } 84 85 if (params()->null) 86 return; 87 88 89 if (params()->file == "") { 90 int map_flags = MAP_ANON | MAP_PRIVATE; 91 pmemAddr = (uint8_t *)mmap(NULL, size(), 92 PROT_READ | PROT_WRITE, map_flags, -1, 0); 93 } else { 94 int map_flags = MAP_PRIVATE; 95 int fd = open(params()->file.c_str(), O_RDONLY); 96 _size = lseek(fd, 0, SEEK_END); 97 lseek(fd, 0, SEEK_SET); 98 pmemAddr = (uint8_t *)mmap(NULL, roundUp(size(), sysconf(_SC_PAGESIZE)), 99 PROT_READ | PROT_WRITE, map_flags, fd, 0); 100 } 101 102 if (pmemAddr == (void *)MAP_FAILED) { 103 perror("mmap"); 104 if (params()->file == "") 105 fatal("Could not mmap!\n"); 106 else 107 fatal("Could not find file: %s\n", params()->file); 108 } 109 110 //If requested, initialize all the memory to 0 111 if (p->zero) 112 memset(pmemAddr, 0, size()); 113} 114 115void 116PhysicalMemory::init() 117{
|
125} 126 127PhysicalMemory::~PhysicalMemory() 128{ 129 if (pmemAddr) 130 munmap((char*)pmemAddr, size()); 131} 132 133void 134PhysicalMemory::regStats() 135{ 136 using namespace Stats; 137 138 bytesRead 139 .name(name() + ".bytes_read") 140 .desc("Number of bytes read from this memory") 141 ; 142 bytesInstRead 143 .name(name() + ".bytes_inst_read") 144 .desc("Number of instructions bytes read from this memory") 145 ; 146 bytesWritten 147 .name(name() + ".bytes_written") 148 .desc("Number of bytes written to this memory") 149 ; 150 numReads 151 .name(name() + ".num_reads") 152 .desc("Number of read requests responded to by this memory") 153 ; 154 numWrites 155 .name(name() + ".num_writes") 156 .desc("Number of write requests responded to by this memory") 157 ; 158 numOther 159 .name(name() + ".num_other") 160 .desc("Number of other requests responded to by this memory") 161 ; 162 bwRead 163 .name(name() + ".bw_read") 164 .desc("Total read bandwidth from this memory (bytes/s)") 165 .precision(0) 166 .prereq(bytesRead) 167 ; 168 bwInstRead 169 .name(name() + ".bw_inst_read") 170 .desc("Instruction read bandwidth from this memory (bytes/s)") 171 .precision(0) 172 .prereq(bytesInstRead) 173 ; 174 bwWrite 175 .name(name() + ".bw_write") 176 .desc("Write bandwidth from this memory (bytes/s)") 177 .precision(0) 178 .prereq(bytesWritten) 179 ; 180 bwTotal 181 .name(name() + ".bw_total") 182 .desc("Total bandwidth to/from this memory (bytes/s)") 183 .precision(0) 184 .prereq(bwTotal) 185 ; 186 bwRead = bytesRead / simSeconds; 187 bwInstRead = bytesInstRead / simSeconds; 188 bwWrite = bytesWritten / simSeconds; 189 bwTotal = (bytesRead + bytesWritten) / simSeconds; 190} 191 192unsigned 193PhysicalMemory::deviceBlockSize() const 194{ 195 //Can accept anysize request 196 return 0; 197} 198 199Tick 200PhysicalMemory::calculateLatency(PacketPtr pkt) 201{ 202 Tick latency = lat; 203 if (lat_var != 0) 204 latency += random_mt.random<Tick>(0, lat_var); 205 return latency; 206} 207 208 209 210// Add load-locked to tracking list. Should only be called if the 211// operation is a load and the LLSC flag is set. 212void 213PhysicalMemory::trackLoadLocked(PacketPtr pkt) 214{ 215 Request *req = pkt->req; 216 Addr paddr = LockedAddr::mask(req->getPaddr()); 217 218 // first we check if we already have a locked addr for this 219 // xc. Since each xc only gets one, we just update the 220 // existing record with the new address. 221 list<LockedAddr>::iterator i; 222 223 for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) { 224 if (i->matchesContext(req)) { 225 DPRINTF(LLSC, "Modifying lock record: context %d addr %#x\n", 226 req->contextId(), paddr); 227 i->addr = paddr; 228 return; 229 } 230 } 231 232 // no record for this xc: need to allocate a new one 233 DPRINTF(LLSC, "Adding lock record: context %d addr %#x\n", 234 req->contextId(), paddr); 235 lockedAddrList.push_front(LockedAddr(req)); 236} 237 238 239// Called on *writes* only... both regular stores and 240// store-conditional operations. Check for conventional stores which 241// conflict with locked addresses, and for success/failure of store 242// conditionals. 243bool 244PhysicalMemory::checkLockedAddrList(PacketPtr pkt) 245{ 246 Request *req = pkt->req; 247 Addr paddr = LockedAddr::mask(req->getPaddr()); 248 bool isLLSC = pkt->isLLSC(); 249 250 // Initialize return value. Non-conditional stores always 251 // succeed. Assume conditional stores will fail until proven 252 // otherwise. 253 bool success = !isLLSC; 254 255 // Iterate over list. Note that there could be multiple matching 256 // records, as more than one context could have done a load locked 257 // to this location. 258 list<LockedAddr>::iterator i = lockedAddrList.begin(); 259 260 while (i != lockedAddrList.end()) { 261 262 if (i->addr == paddr) { 263 // we have a matching address 264 265 if (isLLSC && i->matchesContext(req)) { 266 // it's a store conditional, and as far as the memory 267 // system can tell, the requesting context's lock is 268 // still valid. 269 DPRINTF(LLSC, "StCond success: context %d addr %#x\n", 270 req->contextId(), paddr); 271 success = true; 272 } 273 274 // Get rid of our record of this lock and advance to next 275 DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n", 276 i->contextId, paddr); 277 i = lockedAddrList.erase(i); 278 } 279 else { 280 // no match: advance to next record 281 ++i; 282 } 283 } 284 285 if (isLLSC) { 286 req->setExtraData(success ? 1 : 0); 287 } 288 289 return success; 290} 291 292 293#if TRACING_ON 294 295#define CASE(A, T) \ 296 case sizeof(T): \ 297 DPRINTF(MemoryAccess,"%s of size %i on address 0x%x data 0x%x\n", \ 298 A, pkt->getSize(), pkt->getAddr(), pkt->get<T>()); \ 299 break 300 301 302#define TRACE_PACKET(A) \ 303 do { \ 304 switch (pkt->getSize()) { \ 305 CASE(A, uint64_t); \ 306 CASE(A, uint32_t); \ 307 CASE(A, uint16_t); \ 308 CASE(A, uint8_t); \ 309 default: \ 310 DPRINTF(MemoryAccess, "%s of size %i on address 0x%x\n", \ 311 A, pkt->getSize(), pkt->getAddr()); \ 312 DDUMP(MemoryAccess, pkt->getPtr<uint8_t>(), pkt->getSize());\ 313 } \ 314 } while (0) 315 316#else 317 318#define TRACE_PACKET(A) 319 320#endif 321 322Tick 323PhysicalMemory::doAtomicAccess(PacketPtr pkt) 324{ 325 assert(pkt->getAddr() >= start() && 326 pkt->getAddr() + pkt->getSize() <= start() + size()); 327 328 if (pkt->memInhibitAsserted()) { 329 DPRINTF(MemoryAccess, "mem inhibited on 0x%x: not responding\n", 330 pkt->getAddr()); 331 return 0; 332 } 333 334 uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start(); 335 336 if (pkt->cmd == MemCmd::SwapReq) { 337 IntReg overwrite_val; 338 bool overwrite_mem; 339 uint64_t condition_val64; 340 uint32_t condition_val32; 341 342 if (!pmemAddr) 343 panic("Swap only works if there is real memory (i.e. null=False)"); 344 assert(sizeof(IntReg) >= pkt->getSize()); 345 346 overwrite_mem = true; 347 // keep a copy of our possible write value, and copy what is at the 348 // memory address into the packet 349 std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize()); 350 std::memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); 351 352 if (pkt->req->isCondSwap()) { 353 if (pkt->getSize() == sizeof(uint64_t)) { 354 condition_val64 = pkt->req->getExtraData(); 355 overwrite_mem = !std::memcmp(&condition_val64, hostAddr, 356 sizeof(uint64_t)); 357 } else if (pkt->getSize() == sizeof(uint32_t)) { 358 condition_val32 = (uint32_t)pkt->req->getExtraData(); 359 overwrite_mem = !std::memcmp(&condition_val32, hostAddr, 360 sizeof(uint32_t)); 361 } else 362 panic("Invalid size for conditional read/write\n"); 363 } 364 365 if (overwrite_mem) 366 std::memcpy(hostAddr, &overwrite_val, pkt->getSize()); 367 368 assert(!pkt->req->isInstFetch()); 369 TRACE_PACKET("Read/Write"); 370 numOther++; 371 } else if (pkt->isRead()) { 372 assert(!pkt->isWrite()); 373 if (pkt->isLLSC()) { 374 trackLoadLocked(pkt); 375 } 376 if (pmemAddr) 377 memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); 378 TRACE_PACKET(pkt->req->isInstFetch() ? "IFetch" : "Read"); 379 numReads++; 380 bytesRead += pkt->getSize(); 381 if (pkt->req->isInstFetch()) 382 bytesInstRead += pkt->getSize(); 383 } else if (pkt->isWrite()) { 384 if (writeOK(pkt)) { 385 if (pmemAddr) 386 memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); 387 assert(!pkt->req->isInstFetch()); 388 TRACE_PACKET("Write"); 389 numWrites++; 390 bytesWritten += pkt->getSize(); 391 } 392 } else if (pkt->isInvalidate()) { 393 //upgrade or invalidate 394 if (pkt->needsResponse()) { 395 pkt->makeAtomicResponse(); 396 } 397 } else { 398 panic("unimplemented"); 399 } 400 401 if (pkt->needsResponse()) { 402 pkt->makeAtomicResponse(); 403 } 404 return calculateLatency(pkt); 405} 406 407 408void 409PhysicalMemory::doFunctionalAccess(PacketPtr pkt) 410{ 411 assert(pkt->getAddr() >= start() && 412 pkt->getAddr() + pkt->getSize() <= start() + size()); 413 414 415 uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start(); 416 417 if (pkt->isRead()) { 418 if (pmemAddr) 419 memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); 420 TRACE_PACKET("Read"); 421 pkt->makeAtomicResponse(); 422 } else if (pkt->isWrite()) { 423 if (pmemAddr) 424 memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); 425 TRACE_PACKET("Write"); 426 pkt->makeAtomicResponse(); 427 } else if (pkt->isPrint()) { 428 Packet::PrintReqState *prs = 429 dynamic_cast<Packet::PrintReqState*>(pkt->senderState); 430 // Need to call printLabels() explicitly since we're not going 431 // through printObj(). 432 prs->printLabels(); 433 // Right now we just print the single byte at the specified address. 434 ccprintf(prs->os, "%s%#x\n", prs->curPrefix(), *hostAddr); 435 } else { 436 panic("PhysicalMemory: unimplemented functional command %s", 437 pkt->cmdString()); 438 } 439} 440 441 442SlavePort & 443PhysicalMemory::getSlavePort(const std::string &if_name, int idx) 444{ 445 if (if_name != "port") { 446 return MemObject::getSlavePort(if_name, idx); 447 } else { 448 if (idx >= static_cast<int>(ports.size())) { 449 fatal("PhysicalMemory::getSlavePort: unknown index %d\n", idx); 450 } 451 452 return *ports[idx]; 453 } 454} 455 456PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, 457 PhysicalMemory *_memory) 458 : SimpleTimingPort(_name, _memory), memory(_memory) 459{ } 460 461AddrRangeList 462PhysicalMemory::MemoryPort::getAddrRanges() 463{ 464 return memory->getAddrRanges(); 465} 466 467AddrRangeList 468PhysicalMemory::getAddrRanges() 469{ 470 AddrRangeList ranges; 471 ranges.push_back(RangeSize(start(), size())); 472 return ranges; 473} 474 475unsigned 476PhysicalMemory::MemoryPort::deviceBlockSize() const 477{ 478 return memory->deviceBlockSize(); 479} 480 481Tick 482PhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt) 483{ 484 return memory->doAtomicAccess(pkt); 485} 486 487void 488PhysicalMemory::MemoryPort::recvFunctional(PacketPtr pkt) 489{ 490 pkt->pushLabel(memory->name()); 491 492 if (!queue.checkFunctional(pkt)) { 493 // Default implementation of SimpleTimingPort::recvFunctional() 494 // calls recvAtomic() and throws away the latency; we can save a 495 // little here by just not calculating the latency. 496 memory->doFunctionalAccess(pkt); 497 } 498 499 pkt->popLabel(); 500} 501 502unsigned int 503PhysicalMemory::drain(Event *de) 504{ 505 int count = 0; 506 for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) { 507 count += (*pi)->drain(de); 508 } 509 510 if (count) 511 changeState(Draining); 512 else 513 changeState(Drained); 514 return count; 515} 516 517void 518PhysicalMemory::serialize(ostream &os) 519{ 520 if (!pmemAddr) 521 return; 522 523 gzFile compressedMem; 524 string filename = name() + ".physmem"; 525 526 SERIALIZE_SCALAR(filename); 527 SERIALIZE_SCALAR(_size); 528 529 // write memory file 530 string thefile = Checkpoint::dir() + "/" + filename.c_str(); 531 int fd = creat(thefile.c_str(), 0664); 532 if (fd < 0) { 533 perror("creat"); 534 fatal("Can't open physical memory checkpoint file '%s'\n", filename); 535 } 536 537 compressedMem = gzdopen(fd, "wb"); 538 if (compressedMem == NULL) 539 fatal("Insufficient memory to allocate compression state for %s\n", 540 filename); 541 542 if (gzwrite(compressedMem, pmemAddr, size()) != (int)size()) { 543 fatal("Write failed on physical memory checkpoint file '%s'\n", 544 filename); 545 } 546 547 if (gzclose(compressedMem)) 548 fatal("Close failed on physical memory checkpoint file '%s'\n", 549 filename); 550 551 list<LockedAddr>::iterator i = lockedAddrList.begin(); 552 553 vector<Addr> lal_addr; 554 vector<int> lal_cid; 555 while (i != lockedAddrList.end()) { 556 lal_addr.push_back(i->addr); 557 lal_cid.push_back(i->contextId); 558 i++; 559 } 560 arrayParamOut(os, "lal_addr", lal_addr); 561 arrayParamOut(os, "lal_cid", lal_cid); 562} 563 564void 565PhysicalMemory::unserialize(Checkpoint *cp, const string §ion) 566{ 567 if (!pmemAddr) 568 return; 569 570 gzFile compressedMem; 571 long *tempPage; 572 long *pmem_current; 573 uint64_t curSize; 574 uint32_t bytesRead; 575 const uint32_t chunkSize = 16384; 576 577 string filename; 578 579 UNSERIALIZE_SCALAR(filename); 580 581 filename = cp->cptDir + "/" + filename; 582 583 // mmap memoryfile 584 int fd = open(filename.c_str(), O_RDONLY); 585 if (fd < 0) { 586 perror("open"); 587 fatal("Can't open physical memory checkpoint file '%s'", filename); 588 } 589 590 compressedMem = gzdopen(fd, "rb"); 591 if (compressedMem == NULL) 592 fatal("Insufficient memory to allocate compression state for %s\n", 593 filename); 594 595 // unmap file that was mmapped in the constructor 596 // This is done here to make sure that gzip and open don't muck with our 597 // nice large space of memory before we reallocate it 598 munmap((char*)pmemAddr, size()); 599 600 UNSERIALIZE_SCALAR(_size); 601 if (size() > params()->range.size()) 602 fatal("Memory size has changed! size %lld, param size %lld\n", 603 size(), params()->range.size()); 604 605 pmemAddr = (uint8_t *)mmap(NULL, size(), 606 PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); 607 608 if (pmemAddr == (void *)MAP_FAILED) { 609 perror("mmap"); 610 fatal("Could not mmap physical memory!\n"); 611 } 612 613 curSize = 0; 614 tempPage = (long*)malloc(chunkSize); 615 if (tempPage == NULL) 616 fatal("Unable to malloc memory to read file %s\n", filename); 617 618 /* Only copy bytes that are non-zero, so we don't give the VM system hell */ 619 while (curSize < size()) { 620 bytesRead = gzread(compressedMem, tempPage, chunkSize); 621 if (bytesRead == 0) 622 break; 623 624 assert(bytesRead % sizeof(long) == 0); 625 626 for (uint32_t x = 0; x < bytesRead / sizeof(long); x++) 627 { 628 if (*(tempPage+x) != 0) { 629 pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long)); 630 *pmem_current = *(tempPage+x); 631 } 632 } 633 curSize += bytesRead; 634 } 635 636 free(tempPage); 637 638 if (gzclose(compressedMem)) 639 fatal("Close failed on physical memory checkpoint file '%s'\n", 640 filename); 641 642 vector<Addr> lal_addr; 643 vector<int> lal_cid; 644 arrayParamIn(cp, section, "lal_addr", lal_addr); 645 arrayParamIn(cp, section, "lal_cid", lal_cid); 646 for(int i = 0; i < lal_addr.size(); i++) 647 lockedAddrList.push_front(LockedAddr(lal_addr[i], lal_cid[i])); 648} 649 650PhysicalMemory * 651PhysicalMemoryParams::create() 652{ 653 return new PhysicalMemory(this); 654}
| 125} 126 127PhysicalMemory::~PhysicalMemory() 128{ 129 if (pmemAddr) 130 munmap((char*)pmemAddr, size()); 131} 132 133void 134PhysicalMemory::regStats() 135{ 136 using namespace Stats; 137 138 bytesRead 139 .name(name() + ".bytes_read") 140 .desc("Number of bytes read from this memory") 141 ; 142 bytesInstRead 143 .name(name() + ".bytes_inst_read") 144 .desc("Number of instructions bytes read from this memory") 145 ; 146 bytesWritten 147 .name(name() + ".bytes_written") 148 .desc("Number of bytes written to this memory") 149 ; 150 numReads 151 .name(name() + ".num_reads") 152 .desc("Number of read requests responded to by this memory") 153 ; 154 numWrites 155 .name(name() + ".num_writes") 156 .desc("Number of write requests responded to by this memory") 157 ; 158 numOther 159 .name(name() + ".num_other") 160 .desc("Number of other requests responded to by this memory") 161 ; 162 bwRead 163 .name(name() + ".bw_read") 164 .desc("Total read bandwidth from this memory (bytes/s)") 165 .precision(0) 166 .prereq(bytesRead) 167 ; 168 bwInstRead 169 .name(name() + ".bw_inst_read") 170 .desc("Instruction read bandwidth from this memory (bytes/s)") 171 .precision(0) 172 .prereq(bytesInstRead) 173 ; 174 bwWrite 175 .name(name() + ".bw_write") 176 .desc("Write bandwidth from this memory (bytes/s)") 177 .precision(0) 178 .prereq(bytesWritten) 179 ; 180 bwTotal 181 .name(name() + ".bw_total") 182 .desc("Total bandwidth to/from this memory (bytes/s)") 183 .precision(0) 184 .prereq(bwTotal) 185 ; 186 bwRead = bytesRead / simSeconds; 187 bwInstRead = bytesInstRead / simSeconds; 188 bwWrite = bytesWritten / simSeconds; 189 bwTotal = (bytesRead + bytesWritten) / simSeconds; 190} 191 192unsigned 193PhysicalMemory::deviceBlockSize() const 194{ 195 //Can accept anysize request 196 return 0; 197} 198 199Tick 200PhysicalMemory::calculateLatency(PacketPtr pkt) 201{ 202 Tick latency = lat; 203 if (lat_var != 0) 204 latency += random_mt.random<Tick>(0, lat_var); 205 return latency; 206} 207 208 209 210// Add load-locked to tracking list. Should only be called if the 211// operation is a load and the LLSC flag is set. 212void 213PhysicalMemory::trackLoadLocked(PacketPtr pkt) 214{ 215 Request *req = pkt->req; 216 Addr paddr = LockedAddr::mask(req->getPaddr()); 217 218 // first we check if we already have a locked addr for this 219 // xc. Since each xc only gets one, we just update the 220 // existing record with the new address. 221 list<LockedAddr>::iterator i; 222 223 for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) { 224 if (i->matchesContext(req)) { 225 DPRINTF(LLSC, "Modifying lock record: context %d addr %#x\n", 226 req->contextId(), paddr); 227 i->addr = paddr; 228 return; 229 } 230 } 231 232 // no record for this xc: need to allocate a new one 233 DPRINTF(LLSC, "Adding lock record: context %d addr %#x\n", 234 req->contextId(), paddr); 235 lockedAddrList.push_front(LockedAddr(req)); 236} 237 238 239// Called on *writes* only... both regular stores and 240// store-conditional operations. Check for conventional stores which 241// conflict with locked addresses, and for success/failure of store 242// conditionals. 243bool 244PhysicalMemory::checkLockedAddrList(PacketPtr pkt) 245{ 246 Request *req = pkt->req; 247 Addr paddr = LockedAddr::mask(req->getPaddr()); 248 bool isLLSC = pkt->isLLSC(); 249 250 // Initialize return value. Non-conditional stores always 251 // succeed. Assume conditional stores will fail until proven 252 // otherwise. 253 bool success = !isLLSC; 254 255 // Iterate over list. Note that there could be multiple matching 256 // records, as more than one context could have done a load locked 257 // to this location. 258 list<LockedAddr>::iterator i = lockedAddrList.begin(); 259 260 while (i != lockedAddrList.end()) { 261 262 if (i->addr == paddr) { 263 // we have a matching address 264 265 if (isLLSC && i->matchesContext(req)) { 266 // it's a store conditional, and as far as the memory 267 // system can tell, the requesting context's lock is 268 // still valid. 269 DPRINTF(LLSC, "StCond success: context %d addr %#x\n", 270 req->contextId(), paddr); 271 success = true; 272 } 273 274 // Get rid of our record of this lock and advance to next 275 DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n", 276 i->contextId, paddr); 277 i = lockedAddrList.erase(i); 278 } 279 else { 280 // no match: advance to next record 281 ++i; 282 } 283 } 284 285 if (isLLSC) { 286 req->setExtraData(success ? 1 : 0); 287 } 288 289 return success; 290} 291 292 293#if TRACING_ON 294 295#define CASE(A, T) \ 296 case sizeof(T): \ 297 DPRINTF(MemoryAccess,"%s of size %i on address 0x%x data 0x%x\n", \ 298 A, pkt->getSize(), pkt->getAddr(), pkt->get<T>()); \ 299 break 300 301 302#define TRACE_PACKET(A) \ 303 do { \ 304 switch (pkt->getSize()) { \ 305 CASE(A, uint64_t); \ 306 CASE(A, uint32_t); \ 307 CASE(A, uint16_t); \ 308 CASE(A, uint8_t); \ 309 default: \ 310 DPRINTF(MemoryAccess, "%s of size %i on address 0x%x\n", \ 311 A, pkt->getSize(), pkt->getAddr()); \ 312 DDUMP(MemoryAccess, pkt->getPtr<uint8_t>(), pkt->getSize());\ 313 } \ 314 } while (0) 315 316#else 317 318#define TRACE_PACKET(A) 319 320#endif 321 322Tick 323PhysicalMemory::doAtomicAccess(PacketPtr pkt) 324{ 325 assert(pkt->getAddr() >= start() && 326 pkt->getAddr() + pkt->getSize() <= start() + size()); 327 328 if (pkt->memInhibitAsserted()) { 329 DPRINTF(MemoryAccess, "mem inhibited on 0x%x: not responding\n", 330 pkt->getAddr()); 331 return 0; 332 } 333 334 uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start(); 335 336 if (pkt->cmd == MemCmd::SwapReq) { 337 IntReg overwrite_val; 338 bool overwrite_mem; 339 uint64_t condition_val64; 340 uint32_t condition_val32; 341 342 if (!pmemAddr) 343 panic("Swap only works if there is real memory (i.e. null=False)"); 344 assert(sizeof(IntReg) >= pkt->getSize()); 345 346 overwrite_mem = true; 347 // keep a copy of our possible write value, and copy what is at the 348 // memory address into the packet 349 std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize()); 350 std::memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); 351 352 if (pkt->req->isCondSwap()) { 353 if (pkt->getSize() == sizeof(uint64_t)) { 354 condition_val64 = pkt->req->getExtraData(); 355 overwrite_mem = !std::memcmp(&condition_val64, hostAddr, 356 sizeof(uint64_t)); 357 } else if (pkt->getSize() == sizeof(uint32_t)) { 358 condition_val32 = (uint32_t)pkt->req->getExtraData(); 359 overwrite_mem = !std::memcmp(&condition_val32, hostAddr, 360 sizeof(uint32_t)); 361 } else 362 panic("Invalid size for conditional read/write\n"); 363 } 364 365 if (overwrite_mem) 366 std::memcpy(hostAddr, &overwrite_val, pkt->getSize()); 367 368 assert(!pkt->req->isInstFetch()); 369 TRACE_PACKET("Read/Write"); 370 numOther++; 371 } else if (pkt->isRead()) { 372 assert(!pkt->isWrite()); 373 if (pkt->isLLSC()) { 374 trackLoadLocked(pkt); 375 } 376 if (pmemAddr) 377 memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); 378 TRACE_PACKET(pkt->req->isInstFetch() ? "IFetch" : "Read"); 379 numReads++; 380 bytesRead += pkt->getSize(); 381 if (pkt->req->isInstFetch()) 382 bytesInstRead += pkt->getSize(); 383 } else if (pkt->isWrite()) { 384 if (writeOK(pkt)) { 385 if (pmemAddr) 386 memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); 387 assert(!pkt->req->isInstFetch()); 388 TRACE_PACKET("Write"); 389 numWrites++; 390 bytesWritten += pkt->getSize(); 391 } 392 } else if (pkt->isInvalidate()) { 393 //upgrade or invalidate 394 if (pkt->needsResponse()) { 395 pkt->makeAtomicResponse(); 396 } 397 } else { 398 panic("unimplemented"); 399 } 400 401 if (pkt->needsResponse()) { 402 pkt->makeAtomicResponse(); 403 } 404 return calculateLatency(pkt); 405} 406 407 408void 409PhysicalMemory::doFunctionalAccess(PacketPtr pkt) 410{ 411 assert(pkt->getAddr() >= start() && 412 pkt->getAddr() + pkt->getSize() <= start() + size()); 413 414 415 uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start(); 416 417 if (pkt->isRead()) { 418 if (pmemAddr) 419 memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); 420 TRACE_PACKET("Read"); 421 pkt->makeAtomicResponse(); 422 } else if (pkt->isWrite()) { 423 if (pmemAddr) 424 memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); 425 TRACE_PACKET("Write"); 426 pkt->makeAtomicResponse(); 427 } else if (pkt->isPrint()) { 428 Packet::PrintReqState *prs = 429 dynamic_cast<Packet::PrintReqState*>(pkt->senderState); 430 // Need to call printLabels() explicitly since we're not going 431 // through printObj(). 432 prs->printLabels(); 433 // Right now we just print the single byte at the specified address. 434 ccprintf(prs->os, "%s%#x\n", prs->curPrefix(), *hostAddr); 435 } else { 436 panic("PhysicalMemory: unimplemented functional command %s", 437 pkt->cmdString()); 438 } 439} 440 441 442SlavePort & 443PhysicalMemory::getSlavePort(const std::string &if_name, int idx) 444{ 445 if (if_name != "port") { 446 return MemObject::getSlavePort(if_name, idx); 447 } else { 448 if (idx >= static_cast<int>(ports.size())) { 449 fatal("PhysicalMemory::getSlavePort: unknown index %d\n", idx); 450 } 451 452 return *ports[idx]; 453 } 454} 455 456PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, 457 PhysicalMemory *_memory) 458 : SimpleTimingPort(_name, _memory), memory(_memory) 459{ } 460 461AddrRangeList 462PhysicalMemory::MemoryPort::getAddrRanges() 463{ 464 return memory->getAddrRanges(); 465} 466 467AddrRangeList 468PhysicalMemory::getAddrRanges() 469{ 470 AddrRangeList ranges; 471 ranges.push_back(RangeSize(start(), size())); 472 return ranges; 473} 474 475unsigned 476PhysicalMemory::MemoryPort::deviceBlockSize() const 477{ 478 return memory->deviceBlockSize(); 479} 480 481Tick 482PhysicalMemory::MemoryPort::recvAtomic(PacketPtr pkt) 483{ 484 return memory->doAtomicAccess(pkt); 485} 486 487void 488PhysicalMemory::MemoryPort::recvFunctional(PacketPtr pkt) 489{ 490 pkt->pushLabel(memory->name()); 491 492 if (!queue.checkFunctional(pkt)) { 493 // Default implementation of SimpleTimingPort::recvFunctional() 494 // calls recvAtomic() and throws away the latency; we can save a 495 // little here by just not calculating the latency. 496 memory->doFunctionalAccess(pkt); 497 } 498 499 pkt->popLabel(); 500} 501 502unsigned int 503PhysicalMemory::drain(Event *de) 504{ 505 int count = 0; 506 for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) { 507 count += (*pi)->drain(de); 508 } 509 510 if (count) 511 changeState(Draining); 512 else 513 changeState(Drained); 514 return count; 515} 516 517void 518PhysicalMemory::serialize(ostream &os) 519{ 520 if (!pmemAddr) 521 return; 522 523 gzFile compressedMem; 524 string filename = name() + ".physmem"; 525 526 SERIALIZE_SCALAR(filename); 527 SERIALIZE_SCALAR(_size); 528 529 // write memory file 530 string thefile = Checkpoint::dir() + "/" + filename.c_str(); 531 int fd = creat(thefile.c_str(), 0664); 532 if (fd < 0) { 533 perror("creat"); 534 fatal("Can't open physical memory checkpoint file '%s'\n", filename); 535 } 536 537 compressedMem = gzdopen(fd, "wb"); 538 if (compressedMem == NULL) 539 fatal("Insufficient memory to allocate compression state for %s\n", 540 filename); 541 542 if (gzwrite(compressedMem, pmemAddr, size()) != (int)size()) { 543 fatal("Write failed on physical memory checkpoint file '%s'\n", 544 filename); 545 } 546 547 if (gzclose(compressedMem)) 548 fatal("Close failed on physical memory checkpoint file '%s'\n", 549 filename); 550 551 list<LockedAddr>::iterator i = lockedAddrList.begin(); 552 553 vector<Addr> lal_addr; 554 vector<int> lal_cid; 555 while (i != lockedAddrList.end()) { 556 lal_addr.push_back(i->addr); 557 lal_cid.push_back(i->contextId); 558 i++; 559 } 560 arrayParamOut(os, "lal_addr", lal_addr); 561 arrayParamOut(os, "lal_cid", lal_cid); 562} 563 564void 565PhysicalMemory::unserialize(Checkpoint *cp, const string §ion) 566{ 567 if (!pmemAddr) 568 return; 569 570 gzFile compressedMem; 571 long *tempPage; 572 long *pmem_current; 573 uint64_t curSize; 574 uint32_t bytesRead; 575 const uint32_t chunkSize = 16384; 576 577 string filename; 578 579 UNSERIALIZE_SCALAR(filename); 580 581 filename = cp->cptDir + "/" + filename; 582 583 // mmap memoryfile 584 int fd = open(filename.c_str(), O_RDONLY); 585 if (fd < 0) { 586 perror("open"); 587 fatal("Can't open physical memory checkpoint file '%s'", filename); 588 } 589 590 compressedMem = gzdopen(fd, "rb"); 591 if (compressedMem == NULL) 592 fatal("Insufficient memory to allocate compression state for %s\n", 593 filename); 594 595 // unmap file that was mmapped in the constructor 596 // This is done here to make sure that gzip and open don't muck with our 597 // nice large space of memory before we reallocate it 598 munmap((char*)pmemAddr, size()); 599 600 UNSERIALIZE_SCALAR(_size); 601 if (size() > params()->range.size()) 602 fatal("Memory size has changed! size %lld, param size %lld\n", 603 size(), params()->range.size()); 604 605 pmemAddr = (uint8_t *)mmap(NULL, size(), 606 PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); 607 608 if (pmemAddr == (void *)MAP_FAILED) { 609 perror("mmap"); 610 fatal("Could not mmap physical memory!\n"); 611 } 612 613 curSize = 0; 614 tempPage = (long*)malloc(chunkSize); 615 if (tempPage == NULL) 616 fatal("Unable to malloc memory to read file %s\n", filename); 617 618 /* Only copy bytes that are non-zero, so we don't give the VM system hell */ 619 while (curSize < size()) { 620 bytesRead = gzread(compressedMem, tempPage, chunkSize); 621 if (bytesRead == 0) 622 break; 623 624 assert(bytesRead % sizeof(long) == 0); 625 626 for (uint32_t x = 0; x < bytesRead / sizeof(long); x++) 627 { 628 if (*(tempPage+x) != 0) { 629 pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long)); 630 *pmem_current = *(tempPage+x); 631 } 632 } 633 curSize += bytesRead; 634 } 635 636 free(tempPage); 637 638 if (gzclose(compressedMem)) 639 fatal("Close failed on physical memory checkpoint file '%s'\n", 640 filename); 641 642 vector<Addr> lal_addr; 643 vector<int> lal_cid; 644 arrayParamIn(cp, section, "lal_addr", lal_addr); 645 arrayParamIn(cp, section, "lal_cid", lal_cid); 646 for(int i = 0; i < lal_addr.size(); i++) 647 lockedAddrList.push_front(LockedAddr(lal_addr[i], lal_cid[i])); 648} 649 650PhysicalMemory * 651PhysicalMemoryParams::create() 652{ 653 return new PhysicalMemory(this); 654}
|