abstract_mem.cc revision 9203:939077a54014
1/* 2 * Copyright (c) 2010-2012 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 * Andreas Hansson 43 */ 44 45#include <sys/mman.h> 46#include <sys/types.h> 47#include <sys/user.h> 48#include <fcntl.h> 49#include <unistd.h> 50#include <zlib.h> 51 52#include <cerrno> 53#include <cstdio> 54#include <climits> 55#include <iostream> 56#include <string> 57 58#include "arch/registers.hh" 59#include "config/the_isa.hh" 60#include "debug/LLSC.hh" 61#include "debug/MemoryAccess.hh" 62#include "mem/abstract_mem.hh" 63#include "mem/packet_access.hh" 64#include "sim/system.hh" 65 66using namespace std; 67 68AbstractMemory::AbstractMemory(const Params *p) : 69 MemObject(p), range(params()->range), pmemAddr(NULL), 70 confTableReported(p->conf_table_reported), inAddrMap(p->in_addr_map), 71 _system(NULL) 72{ 73 if (size() % TheISA::PageBytes != 0) 74 panic("Memory Size not divisible by page size\n"); 75 76 if (params()->null) 77 return; 78 79 if (params()->file == "") { 80 int map_flags = MAP_ANON | MAP_PRIVATE; 81 pmemAddr = (uint8_t *)mmap(NULL, size(), 82 PROT_READ | PROT_WRITE, map_flags, -1, 0); 83 } else { 84 int map_flags = MAP_PRIVATE; 85 int fd = open(params()->file.c_str(), O_RDONLY); 86 long _size = lseek(fd, 0, SEEK_END); 87 if (_size != range.size()) { 88 warn("Specified size %d does not match file %s %d\n", range.size(), 89 params()->file, _size); 90 range = RangeSize(range.start, _size); 91 } 92 lseek(fd, 0, SEEK_SET); 93 pmemAddr = (uint8_t *)mmap(NULL, roundUp(_size, sysconf(_SC_PAGESIZE)), 94 PROT_READ | PROT_WRITE, map_flags, fd, 0); 95 } 96 97 if (pmemAddr == (void *)MAP_FAILED) { 98 perror("mmap"); 99 if (params()->file == "") 100 fatal("Could not mmap!\n"); 101 else 102 fatal("Could not find file: %s\n", params()->file); 103 } 104 105 //If requested, initialize all the memory to 0 106 if (p->zero) 107 memset(pmemAddr, 0, size()); 108} 109 110 111AbstractMemory::~AbstractMemory() 112{ 113 if (pmemAddr) 114 munmap((char*)pmemAddr, size()); 115} 116 117void 118AbstractMemory::regStats() 119{ 120 using namespace Stats; 121 122 assert(system()); 123 124 bytesRead 125 .init(system()->maxMasters()) 126 .name(name() + ".bytes_read") 127 .desc("Number of bytes read from this memory") 128 .flags(total | nozero | nonan) 129 ; 130 for (int i = 0; i < system()->maxMasters(); i++) { 131 bytesRead.subname(i, system()->getMasterName(i)); 132 } 133 bytesInstRead 134 .init(system()->maxMasters()) 135 .name(name() + ".bytes_inst_read") 136 .desc("Number of instructions bytes read from this memory") 137 .flags(total | nozero | nonan) 138 ; 139 for (int i = 0; i < system()->maxMasters(); i++) { 140 bytesInstRead.subname(i, system()->getMasterName(i)); 141 } 142 bytesWritten 143 .init(system()->maxMasters()) 144 .name(name() + ".bytes_written") 145 .desc("Number of bytes written to this memory") 146 .flags(total | nozero | nonan) 147 ; 148 for (int i = 0; i < system()->maxMasters(); i++) { 149 bytesWritten.subname(i, system()->getMasterName(i)); 150 } 151 numReads 152 .init(system()->maxMasters()) 153 .name(name() + ".num_reads") 154 .desc("Number of read requests responded to by this memory") 155 .flags(total | nozero | nonan) 156 ; 157 for (int i = 0; i < system()->maxMasters(); i++) { 158 numReads.subname(i, system()->getMasterName(i)); 159 } 160 numWrites 161 .init(system()->maxMasters()) 162 .name(name() + ".num_writes") 163 .desc("Number of write requests responded to by this memory") 164 .flags(total | nozero | nonan) 165 ; 166 for (int i = 0; i < system()->maxMasters(); i++) { 167 numWrites.subname(i, system()->getMasterName(i)); 168 } 169 numOther 170 .init(system()->maxMasters()) 171 .name(name() + ".num_other") 172 .desc("Number of other requests responded to by this memory") 173 .flags(total | nozero | nonan) 174 ; 175 for (int i = 0; i < system()->maxMasters(); i++) { 176 numOther.subname(i, system()->getMasterName(i)); 177 } 178 bwRead 179 .name(name() + ".bw_read") 180 .desc("Total read bandwidth from this memory (bytes/s)") 181 .precision(0) 182 .prereq(bytesRead) 183 .flags(total | nozero | nonan) 184 ; 185 for (int i = 0; i < system()->maxMasters(); i++) { 186 bwRead.subname(i, system()->getMasterName(i)); 187 } 188 189 bwInstRead 190 .name(name() + ".bw_inst_read") 191 .desc("Instruction read bandwidth from this memory (bytes/s)") 192 .precision(0) 193 .prereq(bytesInstRead) 194 .flags(total | nozero | nonan) 195 ; 196 for (int i = 0; i < system()->maxMasters(); i++) { 197 bwInstRead.subname(i, system()->getMasterName(i)); 198 } 199 bwWrite 200 .name(name() + ".bw_write") 201 .desc("Write bandwidth from this memory (bytes/s)") 202 .precision(0) 203 .prereq(bytesWritten) 204 .flags(total | nozero | nonan) 205 ; 206 for (int i = 0; i < system()->maxMasters(); i++) { 207 bwWrite.subname(i, system()->getMasterName(i)); 208 } 209 bwTotal 210 .name(name() + ".bw_total") 211 .desc("Total bandwidth to/from this memory (bytes/s)") 212 .precision(0) 213 .prereq(bwTotal) 214 .flags(total | nozero | nonan) 215 ; 216 for (int i = 0; i < system()->maxMasters(); i++) { 217 bwTotal.subname(i, system()->getMasterName(i)); 218 } 219 bwRead = bytesRead / simSeconds; 220 bwInstRead = bytesInstRead / simSeconds; 221 bwWrite = bytesWritten / simSeconds; 222 bwTotal = (bytesRead + bytesWritten) / simSeconds; 223} 224 225Range<Addr> 226AbstractMemory::getAddrRange() const 227{ 228 return range; 229} 230 231// Add load-locked to tracking list. Should only be called if the 232// operation is a load and the LLSC flag is set. 233void 234AbstractMemory::trackLoadLocked(PacketPtr pkt) 235{ 236 Request *req = pkt->req; 237 Addr paddr = LockedAddr::mask(req->getPaddr()); 238 239 // first we check if we already have a locked addr for this 240 // xc. Since each xc only gets one, we just update the 241 // existing record with the new address. 242 list<LockedAddr>::iterator i; 243 244 for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) { 245 if (i->matchesContext(req)) { 246 DPRINTF(LLSC, "Modifying lock record: context %d addr %#x\n", 247 req->contextId(), paddr); 248 i->addr = paddr; 249 return; 250 } 251 } 252 253 // no record for this xc: need to allocate a new one 254 DPRINTF(LLSC, "Adding lock record: context %d addr %#x\n", 255 req->contextId(), paddr); 256 lockedAddrList.push_front(LockedAddr(req)); 257} 258 259 260// Called on *writes* only... both regular stores and 261// store-conditional operations. Check for conventional stores which 262// conflict with locked addresses, and for success/failure of store 263// conditionals. 264bool 265AbstractMemory::checkLockedAddrList(PacketPtr pkt) 266{ 267 Request *req = pkt->req; 268 Addr paddr = LockedAddr::mask(req->getPaddr()); 269 bool isLLSC = pkt->isLLSC(); 270 271 // Initialize return value. Non-conditional stores always 272 // succeed. Assume conditional stores will fail until proven 273 // otherwise. 274 bool allowStore = !isLLSC; 275 276 // Iterate over list. Note that there could be multiple matching records, 277 // as more than one context could have done a load locked to this location. 278 // Only remove records when we succeed in finding a record for (xc, addr); 279 // then, remove all records with this address. Failed store-conditionals do 280 // not blow unrelated reservations. 281 list<LockedAddr>::iterator i = lockedAddrList.begin(); 282 283 if (isLLSC) { 284 while (i != lockedAddrList.end()) { 285 if (i->addr == paddr && i->matchesContext(req)) { 286 // it's a store conditional, and as far as the memory system can 287 // tell, the requesting context's lock is still valid. 288 DPRINTF(LLSC, "StCond success: context %d addr %#x\n", 289 req->contextId(), paddr); 290 allowStore = true; 291 break; 292 } 293 // If we didn't find a match, keep searching! Someone else may well 294 // have a reservation on this line here but we may find ours in just 295 // a little while. 296 i++; 297 } 298 req->setExtraData(allowStore ? 1 : 0); 299 } 300 // LLSCs that succeeded AND non-LLSC stores both fall into here: 301 if (allowStore) { 302 // We write address paddr. However, there may be several entries with a 303 // reservation on this address (for other contextIds) and they must all 304 // be removed. 305 i = lockedAddrList.begin(); 306 while (i != lockedAddrList.end()) { 307 if (i->addr == paddr) { 308 DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n", 309 i->contextId, paddr); 310 i = lockedAddrList.erase(i); 311 } else { 312 i++; 313 } 314 } 315 } 316 317 return allowStore; 318} 319 320 321#if TRACING_ON 322 323#define CASE(A, T) \ 324 case sizeof(T): \ 325 DPRINTF(MemoryAccess,"%s of size %i on address 0x%x data 0x%x\n", \ 326 A, pkt->getSize(), pkt->getAddr(), pkt->get<T>()); \ 327 break 328 329 330#define TRACE_PACKET(A) \ 331 do { \ 332 switch (pkt->getSize()) { \ 333 CASE(A, uint64_t); \ 334 CASE(A, uint32_t); \ 335 CASE(A, uint16_t); \ 336 CASE(A, uint8_t); \ 337 default: \ 338 DPRINTF(MemoryAccess, "%s of size %i on address 0x%x\n", \ 339 A, pkt->getSize(), pkt->getAddr()); \ 340 DDUMP(MemoryAccess, pkt->getPtr<uint8_t>(), pkt->getSize());\ 341 } \ 342 } while (0) 343 344#else 345 346#define TRACE_PACKET(A) 347 348#endif 349 350void 351AbstractMemory::access(PacketPtr pkt) 352{ 353 assert(pkt->getAddr() >= range.start && 354 (pkt->getAddr() + pkt->getSize() - 1) <= range.end); 355 356 if (pkt->memInhibitAsserted()) { 357 DPRINTF(MemoryAccess, "mem inhibited on 0x%x: not responding\n", 358 pkt->getAddr()); 359 return; 360 } 361 362 uint8_t *hostAddr = pmemAddr + pkt->getAddr() - range.start; 363 364 if (pkt->cmd == MemCmd::SwapReq) { 365 TheISA::IntReg overwrite_val; 366 bool overwrite_mem; 367 uint64_t condition_val64; 368 uint32_t condition_val32; 369 370 if (!pmemAddr) 371 panic("Swap only works if there is real memory (i.e. null=False)"); 372 assert(sizeof(TheISA::IntReg) >= pkt->getSize()); 373 374 overwrite_mem = true; 375 // keep a copy of our possible write value, and copy what is at the 376 // memory address into the packet 377 std::memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize()); 378 std::memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); 379 380 if (pkt->req->isCondSwap()) { 381 if (pkt->getSize() == sizeof(uint64_t)) { 382 condition_val64 = pkt->req->getExtraData(); 383 overwrite_mem = !std::memcmp(&condition_val64, hostAddr, 384 sizeof(uint64_t)); 385 } else if (pkt->getSize() == sizeof(uint32_t)) { 386 condition_val32 = (uint32_t)pkt->req->getExtraData(); 387 overwrite_mem = !std::memcmp(&condition_val32, hostAddr, 388 sizeof(uint32_t)); 389 } else 390 panic("Invalid size for conditional read/write\n"); 391 } 392 393 if (overwrite_mem) 394 std::memcpy(hostAddr, &overwrite_val, pkt->getSize()); 395 396 assert(!pkt->req->isInstFetch()); 397 TRACE_PACKET("Read/Write"); 398 numOther[pkt->req->masterId()]++; 399 } else if (pkt->isRead()) { 400 assert(!pkt->isWrite()); 401 if (pkt->isLLSC()) { 402 trackLoadLocked(pkt); 403 } 404 if (pmemAddr) 405 memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); 406 TRACE_PACKET(pkt->req->isInstFetch() ? "IFetch" : "Read"); 407 numReads[pkt->req->masterId()]++; 408 bytesRead[pkt->req->masterId()] += pkt->getSize(); 409 if (pkt->req->isInstFetch()) 410 bytesInstRead[pkt->req->masterId()] += pkt->getSize(); 411 } else if (pkt->isWrite()) { 412 if (writeOK(pkt)) { 413 if (pmemAddr) 414 memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); 415 assert(!pkt->req->isInstFetch()); 416 TRACE_PACKET("Write"); 417 numWrites[pkt->req->masterId()]++; 418 bytesWritten[pkt->req->masterId()] += pkt->getSize(); 419 } 420 } else if (pkt->isInvalidate()) { 421 // no need to do anything 422 } else { 423 panic("unimplemented"); 424 } 425 426 if (pkt->needsResponse()) { 427 pkt->makeResponse(); 428 } 429} 430 431void 432AbstractMemory::functionalAccess(PacketPtr pkt) 433{ 434 assert(pkt->getAddr() >= range.start && 435 (pkt->getAddr() + pkt->getSize() - 1) <= range.end); 436 437 uint8_t *hostAddr = pmemAddr + pkt->getAddr() - range.start; 438 439 if (pkt->isRead()) { 440 if (pmemAddr) 441 memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize()); 442 TRACE_PACKET("Read"); 443 pkt->makeResponse(); 444 } else if (pkt->isWrite()) { 445 if (pmemAddr) 446 memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize()); 447 TRACE_PACKET("Write"); 448 pkt->makeResponse(); 449 } else if (pkt->isPrint()) { 450 Packet::PrintReqState *prs = 451 dynamic_cast<Packet::PrintReqState*>(pkt->senderState); 452 assert(prs); 453 // Need to call printLabels() explicitly since we're not going 454 // through printObj(). 455 prs->printLabels(); 456 // Right now we just print the single byte at the specified address. 457 ccprintf(prs->os, "%s%#x\n", prs->curPrefix(), *hostAddr); 458 } else { 459 panic("AbstractMemory: unimplemented functional command %s", 460 pkt->cmdString()); 461 } 462} 463 464void 465AbstractMemory::serialize(ostream &os) 466{ 467 if (!pmemAddr) 468 return; 469 470 gzFile compressedMem; 471 string filename = name() + ".physmem"; 472 long _size = range.size(); 473 474 SERIALIZE_SCALAR(filename); 475 SERIALIZE_SCALAR(_size); 476 477 // write memory file 478 string thefile = Checkpoint::dir() + "/" + filename.c_str(); 479 int fd = creat(thefile.c_str(), 0664); 480 if (fd < 0) { 481 perror("creat"); 482 fatal("Can't open physical memory checkpoint file '%s'\n", filename); 483 } 484 485 compressedMem = gzdopen(fd, "wb"); 486 if (compressedMem == NULL) 487 fatal("Insufficient memory to allocate compression state for %s\n", 488 filename); 489 490 uint64_t pass_size = 0; 491 // gzwrite fails if (int)len < 0 (gzwrite returns int) 492 for (uint64_t written = 0; written < size(); written += pass_size) { 493 pass_size = (uint64_t)INT_MAX < (size() - written) ? 494 (uint64_t)INT_MAX : (size() - written); 495 496 if (gzwrite(compressedMem, pmemAddr + written, 497 (unsigned int) pass_size) != (int)pass_size) { 498 fatal("Write failed on physical memory checkpoint file '%s'\n", 499 filename); 500 } 501 } 502 503 if (gzclose(compressedMem)) 504 fatal("Close failed on physical memory checkpoint file '%s'\n", 505 filename); 506 507 list<LockedAddr>::iterator i = lockedAddrList.begin(); 508 509 vector<Addr> lal_addr; 510 vector<int> lal_cid; 511 while (i != lockedAddrList.end()) { 512 lal_addr.push_back(i->addr); 513 lal_cid.push_back(i->contextId); 514 i++; 515 } 516 arrayParamOut(os, "lal_addr", lal_addr); 517 arrayParamOut(os, "lal_cid", lal_cid); 518} 519 520void 521AbstractMemory::unserialize(Checkpoint *cp, const string §ion) 522{ 523 if (!pmemAddr) 524 return; 525 526 gzFile compressedMem; 527 long *tempPage; 528 long *pmem_current; 529 uint64_t curSize; 530 uint32_t bytesRead; 531 const uint32_t chunkSize = 16384; 532 533 string filename; 534 535 UNSERIALIZE_SCALAR(filename); 536 537 filename = cp->cptDir + "/" + filename; 538 539 // mmap memoryfile 540 int fd = open(filename.c_str(), O_RDONLY); 541 if (fd < 0) { 542 perror("open"); 543 fatal("Can't open physical memory checkpoint file '%s'", filename); 544 } 545 546 compressedMem = gzdopen(fd, "rb"); 547 if (compressedMem == NULL) 548 fatal("Insufficient memory to allocate compression state for %s\n", 549 filename); 550 551 // unmap file that was mmapped in the constructor 552 // This is done here to make sure that gzip and open don't muck with our 553 // nice large space of memory before we reallocate it 554 munmap((char*)pmemAddr, size()); 555 556 long _size; 557 UNSERIALIZE_SCALAR(_size); 558 if (_size > params()->range.size()) 559 fatal("Memory size has changed! size %lld, param size %lld\n", 560 _size, params()->range.size()); 561 562 pmemAddr = (uint8_t *)mmap(NULL, size(), 563 PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); 564 565 if (pmemAddr == (void *)MAP_FAILED) { 566 perror("mmap"); 567 fatal("Could not mmap physical memory!\n"); 568 } 569 570 curSize = 0; 571 tempPage = (long*)malloc(chunkSize); 572 if (tempPage == NULL) 573 fatal("Unable to malloc memory to read file %s\n", filename); 574 575 /* Only copy bytes that are non-zero, so we don't give the VM system hell */ 576 while (curSize < size()) { 577 bytesRead = gzread(compressedMem, tempPage, chunkSize); 578 if (bytesRead == 0) 579 break; 580 581 assert(bytesRead % sizeof(long) == 0); 582 583 for (uint32_t x = 0; x < bytesRead / sizeof(long); x++) 584 { 585 if (*(tempPage+x) != 0) { 586 pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long)); 587 *pmem_current = *(tempPage+x); 588 } 589 } 590 curSize += bytesRead; 591 } 592 593 free(tempPage); 594 595 if (gzclose(compressedMem)) 596 fatal("Close failed on physical memory checkpoint file '%s'\n", 597 filename); 598 599 vector<Addr> lal_addr; 600 vector<int> lal_cid; 601 arrayParamIn(cp, section, "lal_addr", lal_addr); 602 arrayParamIn(cp, section, "lal_cid", lal_cid); 603 for(int i = 0; i < lal_addr.size(); i++) 604 lockedAddrList.push_front(LockedAddr(lal_addr[i], lal_cid[i])); 605} 606