abstract_mem.cc revision 13892
1/* 2 * Copyright (c) 2010-2012,2017 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 "mem/abstract_mem.hh" 46 47#include <vector> 48 49#include "arch/locked_mem.hh" 50#include "cpu/base.hh" 51#include "cpu/thread_context.hh" 52#include "debug/LLSC.hh" 53#include "debug/MemoryAccess.hh" 54#include "mem/packet_access.hh" 55#include "sim/system.hh" 56 57using namespace std; 58 59AbstractMemory::AbstractMemory(const Params *p) : 60 ClockedObject(p), range(params()->range), pmemAddr(NULL), 61 backdoor(params()->range, nullptr, 62 (MemBackdoor::Flags)(MemBackdoor::Readable | 63 MemBackdoor::Writeable)), 64 confTableReported(p->conf_table_reported), inAddrMap(p->in_addr_map), 65 kvmMap(p->kvm_map), _system(NULL) 66{ 67} 68 69void 70AbstractMemory::init() 71{ 72 assert(system()); 73 74 if (size() % _system->getPageBytes() != 0) 75 panic("Memory Size not divisible by page size\n"); 76} 77 78void 79AbstractMemory::setBackingStore(uint8_t* pmem_addr) 80{ 81 // If there was an existing backdoor, let everybody know it's going away. 82 if (backdoor.ptr()) 83 backdoor.invalidate(); 84 85 // The back door can't handle interleaved memory. 86 backdoor.ptr(range.interleaved() ? nullptr : pmem_addr); 87 88 pmemAddr = pmem_addr; 89} 90 91void 92AbstractMemory::regStats() 93{ 94 ClockedObject::regStats(); 95 96 using namespace Stats; 97 98 assert(system()); 99 100 bytesRead 101 .init(system()->maxMasters()) 102 .name(name() + ".bytes_read") 103 .desc("Number of bytes read from this memory") 104 .flags(total | nozero | nonan) 105 ; 106 for (int i = 0; i < system()->maxMasters(); i++) { 107 bytesRead.subname(i, system()->getMasterName(i)); 108 } 109 bytesInstRead 110 .init(system()->maxMasters()) 111 .name(name() + ".bytes_inst_read") 112 .desc("Number of instructions bytes read from this memory") 113 .flags(total | nozero | nonan) 114 ; 115 for (int i = 0; i < system()->maxMasters(); i++) { 116 bytesInstRead.subname(i, system()->getMasterName(i)); 117 } 118 bytesWritten 119 .init(system()->maxMasters()) 120 .name(name() + ".bytes_written") 121 .desc("Number of bytes written to this memory") 122 .flags(total | nozero | nonan) 123 ; 124 for (int i = 0; i < system()->maxMasters(); i++) { 125 bytesWritten.subname(i, system()->getMasterName(i)); 126 } 127 numReads 128 .init(system()->maxMasters()) 129 .name(name() + ".num_reads") 130 .desc("Number of read requests responded to by this memory") 131 .flags(total | nozero | nonan) 132 ; 133 for (int i = 0; i < system()->maxMasters(); i++) { 134 numReads.subname(i, system()->getMasterName(i)); 135 } 136 numWrites 137 .init(system()->maxMasters()) 138 .name(name() + ".num_writes") 139 .desc("Number of write requests responded to by this memory") 140 .flags(total | nozero | nonan) 141 ; 142 for (int i = 0; i < system()->maxMasters(); i++) { 143 numWrites.subname(i, system()->getMasterName(i)); 144 } 145 numOther 146 .init(system()->maxMasters()) 147 .name(name() + ".num_other") 148 .desc("Number of other requests responded to by this memory") 149 .flags(total | nozero | nonan) 150 ; 151 for (int i = 0; i < system()->maxMasters(); i++) { 152 numOther.subname(i, system()->getMasterName(i)); 153 } 154 bwRead 155 .name(name() + ".bw_read") 156 .desc("Total read bandwidth from this memory (bytes/s)") 157 .precision(0) 158 .prereq(bytesRead) 159 .flags(total | nozero | nonan) 160 ; 161 for (int i = 0; i < system()->maxMasters(); i++) { 162 bwRead.subname(i, system()->getMasterName(i)); 163 } 164 165 bwInstRead 166 .name(name() + ".bw_inst_read") 167 .desc("Instruction read bandwidth from this memory (bytes/s)") 168 .precision(0) 169 .prereq(bytesInstRead) 170 .flags(total | nozero | nonan) 171 ; 172 for (int i = 0; i < system()->maxMasters(); i++) { 173 bwInstRead.subname(i, system()->getMasterName(i)); 174 } 175 bwWrite 176 .name(name() + ".bw_write") 177 .desc("Write bandwidth from this memory (bytes/s)") 178 .precision(0) 179 .prereq(bytesWritten) 180 .flags(total | nozero | nonan) 181 ; 182 for (int i = 0; i < system()->maxMasters(); i++) { 183 bwWrite.subname(i, system()->getMasterName(i)); 184 } 185 bwTotal 186 .name(name() + ".bw_total") 187 .desc("Total bandwidth to/from this memory (bytes/s)") 188 .precision(0) 189 .prereq(bwTotal) 190 .flags(total | nozero | nonan) 191 ; 192 for (int i = 0; i < system()->maxMasters(); i++) { 193 bwTotal.subname(i, system()->getMasterName(i)); 194 } 195 bwRead = bytesRead / simSeconds; 196 bwInstRead = bytesInstRead / simSeconds; 197 bwWrite = bytesWritten / simSeconds; 198 bwTotal = (bytesRead + bytesWritten) / simSeconds; 199} 200 201AddrRange 202AbstractMemory::getAddrRange() const 203{ 204 return range; 205} 206 207// Add load-locked to tracking list. Should only be called if the 208// operation is a load and the LLSC flag is set. 209void 210AbstractMemory::trackLoadLocked(PacketPtr pkt) 211{ 212 const RequestPtr &req = pkt->req; 213 Addr paddr = LockedAddr::mask(req->getPaddr()); 214 215 // first we check if we already have a locked addr for this 216 // xc. Since each xc only gets one, we just update the 217 // existing record with the new address. 218 list<LockedAddr>::iterator i; 219 220 for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) { 221 if (i->matchesContext(req)) { 222 DPRINTF(LLSC, "Modifying lock record: context %d addr %#x\n", 223 req->contextId(), paddr); 224 i->addr = paddr; 225 return; 226 } 227 } 228 229 // no record for this xc: need to allocate a new one 230 DPRINTF(LLSC, "Adding lock record: context %d addr %#x\n", 231 req->contextId(), paddr); 232 lockedAddrList.push_front(LockedAddr(req)); 233} 234 235 236// Called on *writes* only... both regular stores and 237// store-conditional operations. Check for conventional stores which 238// conflict with locked addresses, and for success/failure of store 239// conditionals. 240bool 241AbstractMemory::checkLockedAddrList(PacketPtr pkt) 242{ 243 const RequestPtr &req = pkt->req; 244 Addr paddr = LockedAddr::mask(req->getPaddr()); 245 bool isLLSC = pkt->isLLSC(); 246 247 // Initialize return value. Non-conditional stores always 248 // succeed. Assume conditional stores will fail until proven 249 // otherwise. 250 bool allowStore = !isLLSC; 251 252 // Iterate over list. Note that there could be multiple matching records, 253 // as more than one context could have done a load locked to this location. 254 // Only remove records when we succeed in finding a record for (xc, addr); 255 // then, remove all records with this address. Failed store-conditionals do 256 // not blow unrelated reservations. 257 list<LockedAddr>::iterator i = lockedAddrList.begin(); 258 259 if (isLLSC) { 260 while (i != lockedAddrList.end()) { 261 if (i->addr == paddr && i->matchesContext(req)) { 262 // it's a store conditional, and as far as the memory system can 263 // tell, the requesting context's lock is still valid. 264 DPRINTF(LLSC, "StCond success: context %d addr %#x\n", 265 req->contextId(), paddr); 266 allowStore = true; 267 break; 268 } 269 // If we didn't find a match, keep searching! Someone else may well 270 // have a reservation on this line here but we may find ours in just 271 // a little while. 272 i++; 273 } 274 req->setExtraData(allowStore ? 1 : 0); 275 } 276 // LLSCs that succeeded AND non-LLSC stores both fall into here: 277 if (allowStore) { 278 // We write address paddr. However, there may be several entries with a 279 // reservation on this address (for other contextIds) and they must all 280 // be removed. 281 i = lockedAddrList.begin(); 282 while (i != lockedAddrList.end()) { 283 if (i->addr == paddr) { 284 DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n", 285 i->contextId, paddr); 286 ContextID owner_cid = i->contextId; 287 ContextID requester_cid = pkt->req->contextId(); 288 if (owner_cid != requester_cid) { 289 ThreadContext* ctx = system()->getThreadContext(owner_cid); 290 TheISA::globalClearExclusive(ctx); 291 } 292 i = lockedAddrList.erase(i); 293 } else { 294 i++; 295 } 296 } 297 } 298 299 return allowStore; 300} 301 302#if TRACING_ON 303static inline void 304tracePacket(System *sys, const char *label, PacketPtr pkt) 305{ 306 int size = pkt->getSize(); 307#if THE_ISA != NULL_ISA 308 if (size == 1 || size == 2 || size == 4 || size == 8) { 309 DPRINTF(MemoryAccess,"%s from %s of size %i on address %#x data " 310 "%#x %c\n", label, sys->getMasterName(pkt->req->masterId()), 311 size, pkt->getAddr(), pkt->getUintX(TheISA::GuestByteOrder), 312 pkt->req->isUncacheable() ? 'U' : 'C'); 313 return; 314 } 315#endif 316 DPRINTF(MemoryAccess, "%s from %s of size %i on address %#x %c\n", 317 label, sys->getMasterName(pkt->req->masterId()), 318 size, pkt->getAddr(), pkt->req->isUncacheable() ? 'U' : 'C'); 319 DDUMP(MemoryAccess, pkt->getConstPtr<uint8_t>(), pkt->getSize()); 320} 321 322# define TRACE_PACKET(A) tracePacket(system(), A, pkt) 323#else 324# define TRACE_PACKET(A) 325#endif 326 327void 328AbstractMemory::access(PacketPtr pkt) 329{ 330 if (pkt->cacheResponding()) { 331 DPRINTF(MemoryAccess, "Cache responding to %#llx: not responding\n", 332 pkt->getAddr()); 333 return; 334 } 335 336 if (pkt->cmd == MemCmd::CleanEvict || pkt->cmd == MemCmd::WritebackClean) { 337 DPRINTF(MemoryAccess, "CleanEvict on 0x%x: not responding\n", 338 pkt->getAddr()); 339 return; 340 } 341 342 assert(pkt->getAddrRange().isSubset(range)); 343 344 uint8_t *hostAddr = pmemAddr + pkt->getAddr() - range.start(); 345 346 if (pkt->cmd == MemCmd::SwapReq) { 347 if (pkt->isAtomicOp()) { 348 if (pmemAddr) { 349 pkt->setData(hostAddr); 350 (*(pkt->getAtomicOp()))(hostAddr); 351 } 352 } else { 353 std::vector<uint8_t> overwrite_val(pkt->getSize()); 354 uint64_t condition_val64; 355 uint32_t condition_val32; 356 357 panic_if(!pmemAddr, "Swap only works if there is real memory " \ 358 "(i.e. null=False)"); 359 360 bool overwrite_mem = true; 361 // keep a copy of our possible write value, and copy what is at the 362 // memory address into the packet 363 pkt->writeData(&overwrite_val[0]); 364 pkt->setData(hostAddr); 365 366 if (pkt->req->isCondSwap()) { 367 if (pkt->getSize() == sizeof(uint64_t)) { 368 condition_val64 = pkt->req->getExtraData(); 369 overwrite_mem = !std::memcmp(&condition_val64, hostAddr, 370 sizeof(uint64_t)); 371 } else if (pkt->getSize() == sizeof(uint32_t)) { 372 condition_val32 = (uint32_t)pkt->req->getExtraData(); 373 overwrite_mem = !std::memcmp(&condition_val32, hostAddr, 374 sizeof(uint32_t)); 375 } else 376 panic("Invalid size for conditional read/write\n"); 377 } 378 379 if (overwrite_mem) 380 std::memcpy(hostAddr, &overwrite_val[0], pkt->getSize()); 381 382 assert(!pkt->req->isInstFetch()); 383 TRACE_PACKET("Read/Write"); 384 numOther[pkt->req->masterId()]++; 385 } 386 } else if (pkt->isRead()) { 387 assert(!pkt->isWrite()); 388 if (pkt->isLLSC()) { 389 assert(!pkt->fromCache()); 390 // if the packet is not coming from a cache then we have 391 // to do the LL/SC tracking here 392 trackLoadLocked(pkt); 393 } 394 if (pmemAddr) { 395 pkt->setData(hostAddr); 396 } 397 TRACE_PACKET(pkt->req->isInstFetch() ? "IFetch" : "Read"); 398 numReads[pkt->req->masterId()]++; 399 bytesRead[pkt->req->masterId()] += pkt->getSize(); 400 if (pkt->req->isInstFetch()) 401 bytesInstRead[pkt->req->masterId()] += pkt->getSize(); 402 } else if (pkt->isInvalidate() || pkt->isClean()) { 403 assert(!pkt->isWrite()); 404 // in a fastmem system invalidating and/or cleaning packets 405 // can be seen due to cache maintenance requests 406 407 // no need to do anything 408 } else if (pkt->isWrite()) { 409 if (writeOK(pkt)) { 410 if (pmemAddr) { 411 pkt->writeData(hostAddr); 412 DPRINTF(MemoryAccess, "%s wrote %i bytes to address %x\n", 413 __func__, pkt->getSize(), pkt->getAddr()); 414 } 415 assert(!pkt->req->isInstFetch()); 416 TRACE_PACKET("Write"); 417 numWrites[pkt->req->masterId()]++; 418 bytesWritten[pkt->req->masterId()] += pkt->getSize(); 419 } 420 } else { 421 panic("Unexpected packet %s", pkt->print()); 422 } 423 424 if (pkt->needsResponse()) { 425 pkt->makeResponse(); 426 } 427} 428 429void 430AbstractMemory::functionalAccess(PacketPtr pkt) 431{ 432 assert(pkt->getAddrRange().isSubset(range)); 433 434 uint8_t *hostAddr = pmemAddr + pkt->getAddr() - range.start(); 435 436 if (pkt->isRead()) { 437 if (pmemAddr) { 438 pkt->setData(hostAddr); 439 } 440 TRACE_PACKET("Read"); 441 pkt->makeResponse(); 442 } else if (pkt->isWrite()) { 443 if (pmemAddr) { 444 pkt->writeData(hostAddr); 445 } 446 TRACE_PACKET("Write"); 447 pkt->makeResponse(); 448 } else if (pkt->isPrint()) { 449 Packet::PrintReqState *prs = 450 dynamic_cast<Packet::PrintReqState*>(pkt->senderState); 451 assert(prs); 452 // Need to call printLabels() explicitly since we're not going 453 // through printObj(). 454 prs->printLabels(); 455 // Right now we just print the single byte at the specified address. 456 ccprintf(prs->os, "%s%#x\n", prs->curPrefix(), *hostAddr); 457 } else { 458 panic("AbstractMemory: unimplemented functional command %s", 459 pkt->cmdString()); 460 } 461} 462