abstract_mem.cc revision 13486
16899SN/A/* 26899SN/A * Copyright (c) 2010-2012,2017 ARM Limited 37553SN/A * All rights reserved 46899SN/A * 56899SN/A * The license below extends only to copyright in the software and shall 66899SN/A * not be construed as granting a license to any other intellectual 76899SN/A * property including but not limited to intellectual property relating 86899SN/A * to a hardware implementation of the functionality of the software 96899SN/A * licensed hereunder. You may use the software subject to the license 106899SN/A * terms below provided that you ensure that this notice is replicated 116899SN/A * unmodified and in its entirety in all distributions of the software, 126899SN/A * modified or unmodified, in source code or in binary form. 136899SN/A * 146899SN/A * Copyright (c) 2001-2005 The Regents of The University of Michigan 156899SN/A * All rights reserved. 166899SN/A * 176899SN/A * Redistribution and use in source and binary forms, with or without 186899SN/A * modification, are permitted provided that the following conditions are 196899SN/A * met: redistributions of source code must retain the above copyright 206899SN/A * notice, this list of conditions and the following disclaimer; 216899SN/A * redistributions in binary form must reproduce the above copyright 226899SN/A * notice, this list of conditions and the following disclaimer in the 236899SN/A * documentation and/or other materials provided with the distribution; 246899SN/A * neither the name of the copyright holders nor the names of its 256899SN/A * contributors may be used to endorse or promote products derived from 266899SN/A * this software without specific prior written permission. 276899SN/A * 286899SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 296899SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 307553SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 317553SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 326899SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 337055SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 348229Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 357454SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 367055SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 377053SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 386899SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 397053SN/A * 406899SN/A * Authors: Ron Dreslinski 418229Snate@binkert.org * Ali Saidi 428229Snate@binkert.org * Andreas Hansson 437553SN/A */ 446899SN/A 457553SN/A#include "mem/abstract_mem.hh" 467553SN/A 477553SN/A#include <vector> 486899SN/A 497053SN/A#include "arch/locked_mem.hh" 508854Sandreas.hansson@arm.com#include "cpu/base.hh" 517053SN/A#include "cpu/thread_context.hh" 527053SN/A#include "debug/LLSC.hh" 537553SN/A#include "debug/MemoryAccess.hh" 546899SN/A#include "mem/packet_access.hh" 557053SN/A#include "sim/system.hh" 568854Sandreas.hansson@arm.com 578854Sandreas.hansson@arm.comusing namespace std; 588854Sandreas.hansson@arm.com 597053SN/AAbstractMemory::AbstractMemory(const Params *p) : 606899SN/A MemObject(p), range(params()->range), pmemAddr(NULL), 618655Sandreas.hansson@arm.com confTableReported(p->conf_table_reported), inAddrMap(p->in_addr_map), 626899SN/A kvmMap(p->kvm_map), _system(NULL) 637053SN/A{ 647053SN/A} 657053SN/A 668854Sandreas.hansson@arm.comvoid 678854Sandreas.hansson@arm.comAbstractMemory::init() 687053SN/A{ 696899SN/A assert(system()); 707553SN/A 717553SN/A if (size() % _system->getPageBytes() != 0) 727553SN/A panic("Memory Size not divisible by page size\n"); 736899SN/A} 747053SN/A 756899SN/Avoid 767053SN/AAbstractMemory::setBackingStore(uint8_t* pmem_addr) 776899SN/A{ 787053SN/A pmemAddr = pmem_addr; 796899SN/A} 807053SN/A 816899SN/Avoid 827553SN/AAbstractMemory::regStats() 836899SN/A{ 847055SN/A MemObject::regStats(); 857053SN/A 867055SN/A using namespace Stats; 876899SN/A 887055SN/A assert(system()); 896899SN/A 907053SN/A bytesRead 917553SN/A .init(system()->maxMasters()) 927053SN/A .name(name() + ".bytes_read") 937053SN/A .desc("Number of bytes read from this memory") 947553SN/A .flags(total | nozero | nonan) 956899SN/A ; 967053SN/A for (int i = 0; i < system()->maxMasters(); i++) { 977553SN/A bytesRead.subname(i, system()->getMasterName(i)); 987053SN/A } 997053SN/A bytesInstRead 1007053SN/A .init(system()->maxMasters()) 1017553SN/A .name(name() + ".bytes_inst_read") 1027053SN/A .desc("Number of instructions bytes read from this memory") 1037053SN/A .flags(total | nozero | nonan) 1047553SN/A ; 1057053SN/A for (int i = 0; i < system()->maxMasters(); i++) { 1066899SN/A bytesInstRead.subname(i, system()->getMasterName(i)); 1077553SN/A } 1086899SN/A bytesWritten 1097053SN/A .init(system()->maxMasters()) 1106899SN/A .name(name() + ".bytes_written") 1117053SN/A .desc("Number of bytes written to this memory") 1127553SN/A .flags(total | nozero | nonan) 1137553SN/A ; 1146899SN/A for (int i = 0; i < system()->maxMasters(); i++) { 1157553SN/A bytesWritten.subname(i, system()->getMasterName(i)); 1167053SN/A } 1177553SN/A numReads 1187553SN/A .init(system()->maxMasters()) 1196899SN/A .name(name() + ".num_reads") 1206899SN/A .desc("Number of read requests responded to by this memory") 1217553SN/A .flags(total | nozero | nonan) 122 ; 123 for (int i = 0; i < system()->maxMasters(); i++) { 124 numReads.subname(i, system()->getMasterName(i)); 125 } 126 numWrites 127 .init(system()->maxMasters()) 128 .name(name() + ".num_writes") 129 .desc("Number of write requests responded to by this memory") 130 .flags(total | nozero | nonan) 131 ; 132 for (int i = 0; i < system()->maxMasters(); i++) { 133 numWrites.subname(i, system()->getMasterName(i)); 134 } 135 numOther 136 .init(system()->maxMasters()) 137 .name(name() + ".num_other") 138 .desc("Number of other requests responded to by this memory") 139 .flags(total | nozero | nonan) 140 ; 141 for (int i = 0; i < system()->maxMasters(); i++) { 142 numOther.subname(i, system()->getMasterName(i)); 143 } 144 bwRead 145 .name(name() + ".bw_read") 146 .desc("Total read bandwidth from this memory (bytes/s)") 147 .precision(0) 148 .prereq(bytesRead) 149 .flags(total | nozero | nonan) 150 ; 151 for (int i = 0; i < system()->maxMasters(); i++) { 152 bwRead.subname(i, system()->getMasterName(i)); 153 } 154 155 bwInstRead 156 .name(name() + ".bw_inst_read") 157 .desc("Instruction read bandwidth from this memory (bytes/s)") 158 .precision(0) 159 .prereq(bytesInstRead) 160 .flags(total | nozero | nonan) 161 ; 162 for (int i = 0; i < system()->maxMasters(); i++) { 163 bwInstRead.subname(i, system()->getMasterName(i)); 164 } 165 bwWrite 166 .name(name() + ".bw_write") 167 .desc("Write bandwidth from this memory (bytes/s)") 168 .precision(0) 169 .prereq(bytesWritten) 170 .flags(total | nozero | nonan) 171 ; 172 for (int i = 0; i < system()->maxMasters(); i++) { 173 bwWrite.subname(i, system()->getMasterName(i)); 174 } 175 bwTotal 176 .name(name() + ".bw_total") 177 .desc("Total bandwidth to/from this memory (bytes/s)") 178 .precision(0) 179 .prereq(bwTotal) 180 .flags(total | nozero | nonan) 181 ; 182 for (int i = 0; i < system()->maxMasters(); i++) { 183 bwTotal.subname(i, system()->getMasterName(i)); 184 } 185 bwRead = bytesRead / simSeconds; 186 bwInstRead = bytesInstRead / simSeconds; 187 bwWrite = bytesWritten / simSeconds; 188 bwTotal = (bytesRead + bytesWritten) / simSeconds; 189} 190 191AddrRange 192AbstractMemory::getAddrRange() const 193{ 194 return range; 195} 196 197// Add load-locked to tracking list. Should only be called if the 198// operation is a load and the LLSC flag is set. 199void 200AbstractMemory::trackLoadLocked(PacketPtr pkt) 201{ 202 const RequestPtr &req = pkt->req; 203 Addr paddr = LockedAddr::mask(req->getPaddr()); 204 205 // first we check if we already have a locked addr for this 206 // xc. Since each xc only gets one, we just update the 207 // existing record with the new address. 208 list<LockedAddr>::iterator i; 209 210 for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) { 211 if (i->matchesContext(req)) { 212 DPRINTF(LLSC, "Modifying lock record: context %d addr %#x\n", 213 req->contextId(), paddr); 214 i->addr = paddr; 215 return; 216 } 217 } 218 219 // no record for this xc: need to allocate a new one 220 DPRINTF(LLSC, "Adding lock record: context %d addr %#x\n", 221 req->contextId(), paddr); 222 lockedAddrList.push_front(LockedAddr(req)); 223} 224 225 226// Called on *writes* only... both regular stores and 227// store-conditional operations. Check for conventional stores which 228// conflict with locked addresses, and for success/failure of store 229// conditionals. 230bool 231AbstractMemory::checkLockedAddrList(PacketPtr pkt) 232{ 233 const RequestPtr &req = pkt->req; 234 Addr paddr = LockedAddr::mask(req->getPaddr()); 235 bool isLLSC = pkt->isLLSC(); 236 237 // Initialize return value. Non-conditional stores always 238 // succeed. Assume conditional stores will fail until proven 239 // otherwise. 240 bool allowStore = !isLLSC; 241 242 // Iterate over list. Note that there could be multiple matching records, 243 // as more than one context could have done a load locked to this location. 244 // Only remove records when we succeed in finding a record for (xc, addr); 245 // then, remove all records with this address. Failed store-conditionals do 246 // not blow unrelated reservations. 247 list<LockedAddr>::iterator i = lockedAddrList.begin(); 248 249 if (isLLSC) { 250 while (i != lockedAddrList.end()) { 251 if (i->addr == paddr && i->matchesContext(req)) { 252 // it's a store conditional, and as far as the memory system can 253 // tell, the requesting context's lock is still valid. 254 DPRINTF(LLSC, "StCond success: context %d addr %#x\n", 255 req->contextId(), paddr); 256 allowStore = true; 257 break; 258 } 259 // If we didn't find a match, keep searching! Someone else may well 260 // have a reservation on this line here but we may find ours in just 261 // a little while. 262 i++; 263 } 264 req->setExtraData(allowStore ? 1 : 0); 265 } 266 // LLSCs that succeeded AND non-LLSC stores both fall into here: 267 if (allowStore) { 268 // We write address paddr. However, there may be several entries with a 269 // reservation on this address (for other contextIds) and they must all 270 // be removed. 271 i = lockedAddrList.begin(); 272 while (i != lockedAddrList.end()) { 273 if (i->addr == paddr) { 274 DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n", 275 i->contextId, paddr); 276 ContextID owner_cid = i->contextId; 277 ContextID requester_cid = pkt->req->contextId(); 278 if (owner_cid != requester_cid) { 279 ThreadContext* ctx = system()->getThreadContext(owner_cid); 280 TheISA::globalClearExclusive(ctx); 281 } 282 i = lockedAddrList.erase(i); 283 } else { 284 i++; 285 } 286 } 287 } 288 289 return allowStore; 290} 291 292#if TRACING_ON 293static inline void 294tracePacket(System *sys, const char *label, PacketPtr pkt) 295{ 296 int size = pkt->getSize(); 297#if THE_ISA != NULL_ISA 298 if (size == 1 || size == 2 || size == 4 || size == 8) { 299 DPRINTF(MemoryAccess,"%s from %s of size %i on address %#x data " 300 "%#x %c\n", label, sys->getMasterName(pkt->req->masterId()), 301 size, pkt->getAddr(), pkt->getUintX(TheISA::GuestByteOrder), 302 pkt->req->isUncacheable() ? 'U' : 'C'); 303 return; 304 } 305#endif 306 DPRINTF(MemoryAccess, "%s from %s of size %i on address %#x %c\n", 307 label, sys->getMasterName(pkt->req->masterId()), 308 size, pkt->getAddr(), pkt->req->isUncacheable() ? 'U' : 'C'); 309 DDUMP(MemoryAccess, pkt->getConstPtr<uint8_t>(), pkt->getSize()); 310} 311 312# define TRACE_PACKET(A) tracePacket(system(), A, pkt) 313#else 314# define TRACE_PACKET(A) 315#endif 316 317void 318AbstractMemory::access(PacketPtr pkt) 319{ 320 if (pkt->cacheResponding()) { 321 DPRINTF(MemoryAccess, "Cache responding to %#llx: not responding\n", 322 pkt->getAddr()); 323 return; 324 } 325 326 if (pkt->cmd == MemCmd::CleanEvict || pkt->cmd == MemCmd::WritebackClean) { 327 DPRINTF(MemoryAccess, "CleanEvict on 0x%x: not responding\n", 328 pkt->getAddr()); 329 return; 330 } 331 332 assert(AddrRange(pkt->getAddr(), 333 pkt->getAddr() + (pkt->getSize() - 1)).isSubset(range)); 334 335 uint8_t *hostAddr = pmemAddr + pkt->getAddr() - range.start(); 336 337 if (pkt->cmd == MemCmd::SwapReq) { 338 if (pkt->isAtomicOp()) { 339 if (pmemAddr) { 340 pkt->setData(hostAddr); 341 (*(pkt->getAtomicOp()))(hostAddr); 342 } 343 } else { 344 std::vector<uint8_t> overwrite_val(pkt->getSize()); 345 uint64_t condition_val64; 346 uint32_t condition_val32; 347 348 panic_if(!pmemAddr, "Swap only works if there is real memory " \ 349 "(i.e. null=False)"); 350 351 bool overwrite_mem = true; 352 // keep a copy of our possible write value, and copy what is at the 353 // memory address into the packet 354 pkt->writeData(&overwrite_val[0]); 355 pkt->setData(hostAddr); 356 357 if (pkt->req->isCondSwap()) { 358 if (pkt->getSize() == sizeof(uint64_t)) { 359 condition_val64 = pkt->req->getExtraData(); 360 overwrite_mem = !std::memcmp(&condition_val64, hostAddr, 361 sizeof(uint64_t)); 362 } else if (pkt->getSize() == sizeof(uint32_t)) { 363 condition_val32 = (uint32_t)pkt->req->getExtraData(); 364 overwrite_mem = !std::memcmp(&condition_val32, hostAddr, 365 sizeof(uint32_t)); 366 } else 367 panic("Invalid size for conditional read/write\n"); 368 } 369 370 if (overwrite_mem) 371 std::memcpy(hostAddr, &overwrite_val[0], pkt->getSize()); 372 373 assert(!pkt->req->isInstFetch()); 374 TRACE_PACKET("Read/Write"); 375 numOther[pkt->req->masterId()]++; 376 } 377 } else if (pkt->isRead()) { 378 assert(!pkt->isWrite()); 379 if (pkt->isLLSC()) { 380 assert(!pkt->fromCache()); 381 // if the packet is not coming from a cache then we have 382 // to do the LL/SC tracking here 383 trackLoadLocked(pkt); 384 } 385 if (pmemAddr) { 386 pkt->setData(hostAddr); 387 } 388 TRACE_PACKET(pkt->req->isInstFetch() ? "IFetch" : "Read"); 389 numReads[pkt->req->masterId()]++; 390 bytesRead[pkt->req->masterId()] += pkt->getSize(); 391 if (pkt->req->isInstFetch()) 392 bytesInstRead[pkt->req->masterId()] += pkt->getSize(); 393 } else if (pkt->isInvalidate() || pkt->isClean()) { 394 assert(!pkt->isWrite()); 395 // in a fastmem system invalidating and/or cleaning packets 396 // can be seen due to cache maintenance requests 397 398 // no need to do anything 399 } else if (pkt->isWrite()) { 400 if (writeOK(pkt)) { 401 if (pmemAddr) { 402 pkt->writeData(hostAddr); 403 DPRINTF(MemoryAccess, "%s wrote %i bytes to address %x\n", 404 __func__, pkt->getSize(), pkt->getAddr()); 405 } 406 assert(!pkt->req->isInstFetch()); 407 TRACE_PACKET("Write"); 408 numWrites[pkt->req->masterId()]++; 409 bytesWritten[pkt->req->masterId()] += pkt->getSize(); 410 } 411 } else { 412 panic("Unexpected packet %s", pkt->print()); 413 } 414 415 if (pkt->needsResponse()) { 416 pkt->makeResponse(); 417 } 418} 419 420void 421AbstractMemory::functionalAccess(PacketPtr pkt) 422{ 423 assert(AddrRange(pkt->getAddr(), 424 pkt->getAddr() + pkt->getSize() - 1).isSubset(range)); 425 426 uint8_t *hostAddr = pmemAddr + pkt->getAddr() - range.start(); 427 428 if (pkt->isRead()) { 429 if (pmemAddr) { 430 pkt->setData(hostAddr); 431 } 432 TRACE_PACKET("Read"); 433 pkt->makeResponse(); 434 } else if (pkt->isWrite()) { 435 if (pmemAddr) { 436 pkt->writeData(hostAddr); 437 } 438 TRACE_PACKET("Write"); 439 pkt->makeResponse(); 440 } else if (pkt->isPrint()) { 441 Packet::PrintReqState *prs = 442 dynamic_cast<Packet::PrintReqState*>(pkt->senderState); 443 assert(prs); 444 // Need to call printLabels() explicitly since we're not going 445 // through printObj(). 446 prs->printLabels(); 447 // Right now we just print the single byte at the specified address. 448 ccprintf(prs->os, "%s%#x\n", prs->curPrefix(), *hostAddr); 449 } else { 450 panic("AbstractMemory: unimplemented functional command %s", 451 pkt->cmdString()); 452 } 453} 454