pseudo_inst.cc revision 9659
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) 2011 Advanced Micro Devices, Inc. 15 * Copyright (c) 2003-2006 The Regents of The University of Michigan 16 * All rights reserved. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions are 20 * met: redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer; 22 * redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution; 25 * neither the name of the copyright holders nor the names of its 26 * contributors may be used to endorse or promote products derived from 27 * this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 * 41 * Authors: Nathan Binkert 42 */ 43 44#include <fcntl.h> 45#include <unistd.h> 46 47#include <cerrno> 48#include <fstream> 49#include <string> 50#include <vector> 51 52#include "arch/kernel_stats.hh" 53#include "arch/utility.hh" 54#include "arch/vtophys.hh" 55#include "base/debug.hh" 56#include "base/output.hh" 57#include "config/the_isa.hh" 58#include "cpu/base.hh" 59#include "cpu/quiesce_event.hh" 60#include "cpu/thread_context.hh" 61#include "debug/Loader.hh" 62#include "debug/Quiesce.hh" 63#include "debug/WorkItems.hh" 64#include "params/BaseCPU.hh" 65#include "sim/full_system.hh" 66#include "sim/pseudo_inst.hh" 67#include "sim/serialize.hh" 68#include "sim/sim_events.hh" 69#include "sim/sim_exit.hh" 70#include "sim/stat_control.hh" 71#include "sim/stats.hh" 72#include "sim/system.hh" 73#include "sim/vptr.hh" 74 75using namespace std; 76 77using namespace Stats; 78using namespace TheISA; 79 80namespace PseudoInst { 81 82static inline void 83panicFsOnlyPseudoInst(const char *name) 84{ 85 panic("Pseudo inst \"%s\" is only available in Full System mode."); 86} 87 88uint64_t 89pseudoInst(ThreadContext *tc, uint8_t func, uint8_t subfunc) 90{ 91 uint64_t args[4]; 92 93 // We need to do this in a slightly convoluted way since 94 // getArgument() might have side-effects on arg_num. We could have 95 // used the Argument class, but due to the possible side effects 96 // from getArgument, it'd most likely break. 97 int arg_num(0); 98 for (int i = 0; i < sizeof(args) / sizeof(*args); ++i) 99 args[arg_num++] = getArgument(tc, arg_num, sizeof(uint64_t), false); 100 101 switch (func) { 102 case 0x00: // arm_func 103 arm(tc); 104 break; 105 106 case 0x01: // quiesce_func 107 quiesce(tc); 108 break; 109 110 case 0x02: // quiescens_func 111 quiesceSkip(tc); 112 break; 113 114 case 0x03: // quiescecycle_func 115 quiesceNs(tc, args[0]); 116 break; 117 118 case 0x04: // quiescetime_func 119 return quiesceTime(tc); 120 121 case 0x07: // rpns_func 122 return rpns(tc); 123 124 case 0x09: // wakecpu_func 125 wakeCPU(tc, args[0]); 126 break; 127 128 case 0x21: // exit_func 129 m5exit(tc, args[0]); 130 break; 131 132 case 0x30: // initparam_func 133 return initParam(tc); 134 135 case 0x31: // loadsymbol_func 136 loadsymbol(tc); 137 break; 138 139 case 0x40: // resetstats_func 140 resetstats(tc, args[0], args[1]); 141 break; 142 143 case 0x41: // dumpstats_func 144 dumpstats(tc, args[0], args[1]); 145 break; 146 147 case 0x42: // dumprststats_func 148 dumpresetstats(tc, args[0], args[1]); 149 break; 150 151 case 0x43: // ckpt_func 152 m5checkpoint(tc, args[0], args[1]); 153 break; 154 155 case 0x4f: // writefile_func 156 return writefile(tc, args[0], args[1], args[2], args[3]); 157 158 case 0x50: // readfile_func 159 return readfile(tc, args[0], args[1], args[2]); 160 161 case 0x51: // debugbreak_func 162 debugbreak(tc); 163 break; 164 165 case 0x52: // switchcpu_func 166 switchcpu(tc); 167 break; 168 169 case 0x53: // addsymbol_func 170 addsymbol(tc, args[0], args[1]); 171 break; 172 173 case 0x54: // panic_func 174 panic("M5 panic instruction called at %s\n", tc->pcState()); 175 176 case 0x5a: // work_begin_func 177 workbegin(tc, args[0], args[1]); 178 break; 179 180 case 0x5b: // work_end_func 181 workend(tc, args[0], args[1]); 182 break; 183 184 case 0x55: // annotate_func 185 case 0x56: // reserved2_func 186 case 0x57: // reserved3_func 187 case 0x58: // reserved4_func 188 case 0x59: // reserved5_func 189 warn("Unimplemented m5 op (0x%x)\n", func); 190 break; 191 192 default: 193 warn("Unhandled m5 op: 0x%x\n", func); 194 break; 195 } 196 197 return 0; 198} 199 200void 201arm(ThreadContext *tc) 202{ 203 if (!FullSystem) 204 panicFsOnlyPseudoInst("arm"); 205 206 if (tc->getKernelStats()) 207 tc->getKernelStats()->arm(); 208} 209 210void 211quiesce(ThreadContext *tc) 212{ 213 if (!FullSystem) 214 panicFsOnlyPseudoInst("quiesce"); 215 216 if (!tc->getCpuPtr()->params()->do_quiesce) 217 return; 218 219 DPRINTF(Quiesce, "%s: quiesce()\n", tc->getCpuPtr()->name()); 220 221 tc->suspend(); 222 if (tc->getKernelStats()) 223 tc->getKernelStats()->quiesce(); 224} 225 226void 227quiesceSkip(ThreadContext *tc) 228{ 229 if (!FullSystem) 230 panicFsOnlyPseudoInst("quiesceSkip"); 231 232 BaseCPU *cpu = tc->getCpuPtr(); 233 234 if (!cpu->params()->do_quiesce) 235 return; 236 237 EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); 238 239 Tick resume = curTick() + 1; 240 241 cpu->reschedule(quiesceEvent, resume, true); 242 243 DPRINTF(Quiesce, "%s: quiesceSkip() until %d\n", 244 cpu->name(), resume); 245 246 tc->suspend(); 247 if (tc->getKernelStats()) 248 tc->getKernelStats()->quiesce(); 249} 250 251void 252quiesceNs(ThreadContext *tc, uint64_t ns) 253{ 254 if (!FullSystem) 255 panicFsOnlyPseudoInst("quiesceNs"); 256 257 BaseCPU *cpu = tc->getCpuPtr(); 258 259 if (!cpu->params()->do_quiesce || ns == 0) 260 return; 261 262 EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); 263 264 Tick resume = curTick() + SimClock::Int::ns * ns; 265 266 cpu->reschedule(quiesceEvent, resume, true); 267 268 DPRINTF(Quiesce, "%s: quiesceNs(%d) until %d\n", 269 cpu->name(), ns, resume); 270 271 tc->suspend(); 272 if (tc->getKernelStats()) 273 tc->getKernelStats()->quiesce(); 274} 275 276void 277quiesceCycles(ThreadContext *tc, uint64_t cycles) 278{ 279 if (!FullSystem) 280 panicFsOnlyPseudoInst("quiesceCycles"); 281 282 BaseCPU *cpu = tc->getCpuPtr(); 283 284 if (!cpu->params()->do_quiesce || cycles == 0) 285 return; 286 287 EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); 288 289 Tick resume = cpu->clockEdge(Cycles(cycles)); 290 291 cpu->reschedule(quiesceEvent, resume, true); 292 293 DPRINTF(Quiesce, "%s: quiesceCycles(%d) until %d\n", 294 cpu->name(), cycles, resume); 295 296 tc->suspend(); 297 if (tc->getKernelStats()) 298 tc->getKernelStats()->quiesce(); 299} 300 301uint64_t 302quiesceTime(ThreadContext *tc) 303{ 304 if (!FullSystem) { 305 panicFsOnlyPseudoInst("quiesceTime"); 306 return 0; 307 } 308 309 return (tc->readLastActivate() - tc->readLastSuspend()) / 310 SimClock::Int::ns; 311} 312 313uint64_t 314rpns(ThreadContext *tc) 315{ 316 return curTick() / SimClock::Int::ns; 317} 318 319void 320wakeCPU(ThreadContext *tc, uint64_t cpuid) 321{ 322 System *sys = tc->getSystemPtr(); 323 ThreadContext *other_tc = sys->threadContexts[cpuid]; 324 if (other_tc->status() == ThreadContext::Suspended) 325 other_tc->activate(); 326} 327 328void 329m5exit(ThreadContext *tc, Tick delay) 330{ 331 Tick when = curTick() + delay * SimClock::Int::ns; 332 exitSimLoop("m5_exit instruction encountered", 0, when); 333} 334 335void 336m5fail(ThreadContext *tc, Tick delay, uint64_t code) 337{ 338 Tick when = curTick() + delay * SimClock::Int::ns; 339 exitSimLoop("m5_fail instruction encountered", code, when); 340} 341 342void 343loadsymbol(ThreadContext *tc) 344{ 345 if (!FullSystem) 346 panicFsOnlyPseudoInst("loadsymbol"); 347 348 const string &filename = tc->getCpuPtr()->system->params()->symbolfile; 349 if (filename.empty()) { 350 return; 351 } 352 353 std::string buffer; 354 ifstream file(filename.c_str()); 355 356 if (!file) 357 fatal("file error: Can't open symbol table file %s\n", filename); 358 359 while (!file.eof()) { 360 getline(file, buffer); 361 362 if (buffer.empty()) 363 continue; 364 365 string::size_type idx = buffer.find(' '); 366 if (idx == string::npos) 367 continue; 368 369 string address = "0x" + buffer.substr(0, idx); 370 eat_white(address); 371 if (address.empty()) 372 continue; 373 374 // Skip over letter and space 375 string symbol = buffer.substr(idx + 3); 376 eat_white(symbol); 377 if (symbol.empty()) 378 continue; 379 380 Addr addr; 381 if (!to_number(address, addr)) 382 continue; 383 384 if (!tc->getSystemPtr()->kernelSymtab->insert(addr, symbol)) 385 continue; 386 387 388 DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); 389 } 390 file.close(); 391} 392 393void 394addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr) 395{ 396 if (!FullSystem) 397 panicFsOnlyPseudoInst("addSymbol"); 398 399 char symb[100]; 400 CopyStringOut(tc, symb, symbolAddr, 100); 401 std::string symbol(symb); 402 403 DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); 404 405 tc->getSystemPtr()->kernelSymtab->insert(addr,symbol); 406 debugSymbolTable->insert(addr,symbol); 407} 408 409uint64_t 410initParam(ThreadContext *tc) 411{ 412 if (!FullSystem) { 413 panicFsOnlyPseudoInst("initParam"); 414 return 0; 415 } 416 417 return tc->getCpuPtr()->system->init_param; 418} 419 420 421void 422resetstats(ThreadContext *tc, Tick delay, Tick period) 423{ 424 if (!tc->getCpuPtr()->params()->do_statistics_insts) 425 return; 426 427 428 Tick when = curTick() + delay * SimClock::Int::ns; 429 Tick repeat = period * SimClock::Int::ns; 430 431 Stats::schedStatEvent(false, true, when, repeat); 432} 433 434void 435dumpstats(ThreadContext *tc, Tick delay, Tick period) 436{ 437 if (!tc->getCpuPtr()->params()->do_statistics_insts) 438 return; 439 440 441 Tick when = curTick() + delay * SimClock::Int::ns; 442 Tick repeat = period * SimClock::Int::ns; 443 444 Stats::schedStatEvent(true, false, when, repeat); 445} 446 447void 448dumpresetstats(ThreadContext *tc, Tick delay, Tick period) 449{ 450 if (!tc->getCpuPtr()->params()->do_statistics_insts) 451 return; 452 453 454 Tick when = curTick() + delay * SimClock::Int::ns; 455 Tick repeat = period * SimClock::Int::ns; 456 457 Stats::schedStatEvent(true, true, when, repeat); 458} 459 460void 461m5checkpoint(ThreadContext *tc, Tick delay, Tick period) 462{ 463 if (!tc->getCpuPtr()->params()->do_checkpoint_insts) 464 return; 465 466 Tick when = curTick() + delay * SimClock::Int::ns; 467 Tick repeat = period * SimClock::Int::ns; 468 469 exitSimLoop("checkpoint", 0, when, repeat); 470} 471 472uint64_t 473readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset) 474{ 475 if (!FullSystem) { 476 panicFsOnlyPseudoInst("readfile"); 477 return 0; 478 } 479 480 const string &file = tc->getSystemPtr()->params()->readfile; 481 if (file.empty()) { 482 return ULL(0); 483 } 484 485 uint64_t result = 0; 486 487 int fd = ::open(file.c_str(), O_RDONLY, 0); 488 if (fd < 0) 489 panic("could not open file %s\n", file); 490 491 if (::lseek(fd, offset, SEEK_SET) < 0) 492 panic("could not seek: %s", strerror(errno)); 493 494 char *buf = new char[len]; 495 char *p = buf; 496 while (len > 0) { 497 int bytes = ::read(fd, p, len); 498 if (bytes <= 0) 499 break; 500 501 p += bytes; 502 result += bytes; 503 len -= bytes; 504 } 505 506 close(fd); 507 CopyIn(tc, vaddr, buf, result); 508 delete [] buf; 509 return result; 510} 511 512uint64_t 513writefile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset, 514 Addr filename_addr) 515{ 516 ostream *os; 517 518 // copy out target filename 519 char fn[100]; 520 std::string filename; 521 CopyStringOut(tc, fn, filename_addr, 100); 522 filename = std::string(fn); 523 524 if (offset == 0) { 525 // create a new file (truncate) 526 os = simout.create(filename, true); 527 } else { 528 // do not truncate file if offset is non-zero 529 // (ios::in flag is required as well to keep the existing data 530 // intact, otherwise existing data will be zeroed out.) 531 os = simout.openFile(simout.directory() + filename, 532 ios::in | ios::out | ios::binary); 533 } 534 if (!os) 535 panic("could not open file %s\n", filename); 536 537 // seek to offset 538 os->seekp(offset); 539 540 // copy out data and write to file 541 char *buf = new char[len]; 542 CopyOut(tc, buf, vaddr, len); 543 os->write(buf, len); 544 if (os->fail() || os->bad()) 545 panic("Error while doing writefile!\n"); 546 547 simout.close(os); 548 549 delete [] buf; 550 551 return len; 552} 553 554void 555debugbreak(ThreadContext *tc) 556{ 557 Debug::breakpoint(); 558} 559 560void 561switchcpu(ThreadContext *tc) 562{ 563 exitSimLoop("switchcpu"); 564} 565 566// 567// This function is executed when annotated work items begin. Depending on 568// what the user specified at the command line, the simulation may exit and/or 569// take a checkpoint when a certain work item begins. 570// 571void 572workbegin(ThreadContext *tc, uint64_t workid, uint64_t threadid) 573{ 574 tc->getCpuPtr()->workItemBegin(); 575 System *sys = tc->getSystemPtr(); 576 const System::Params *params = sys->params(); 577 sys->workItemBegin(threadid, workid); 578 579 DPRINTF(WorkItems, "Work Begin workid: %d, threadid %d\n", workid, 580 threadid); 581 582 // 583 // If specified, determine if this is the specific work item the user 584 // identified 585 // 586 if (params->work_item_id == -1 || params->work_item_id == workid) { 587 588 uint64_t systemWorkBeginCount = sys->incWorkItemsBegin(); 589 int cpuId = tc->getCpuPtr()->cpuId(); 590 591 if (params->work_cpus_ckpt_count != 0 && 592 sys->markWorkItem(cpuId) >= params->work_cpus_ckpt_count) { 593 // 594 // If active cpus equals checkpoint count, create checkpoint 595 // 596 exitSimLoop("checkpoint"); 597 } 598 599 if (systemWorkBeginCount == params->work_begin_ckpt_count) { 600 // 601 // Note: the string specified as the cause of the exit event must 602 // exactly equal "checkpoint" inorder to create a checkpoint 603 // 604 exitSimLoop("checkpoint"); 605 } 606 607 if (systemWorkBeginCount == params->work_begin_exit_count) { 608 // 609 // If a certain number of work items started, exit simulation 610 // 611 exitSimLoop("work started count reach"); 612 } 613 614 if (cpuId == params->work_begin_cpu_id_exit) { 615 // 616 // If work started on the cpu id specified, exit simulation 617 // 618 exitSimLoop("work started on specific cpu"); 619 } 620 } 621} 622 623// 624// This function is executed when annotated work items end. Depending on 625// what the user specified at the command line, the simulation may exit and/or 626// take a checkpoint when a certain work item ends. 627// 628void 629workend(ThreadContext *tc, uint64_t workid, uint64_t threadid) 630{ 631 tc->getCpuPtr()->workItemEnd(); 632 System *sys = tc->getSystemPtr(); 633 const System::Params *params = sys->params(); 634 sys->workItemEnd(threadid, workid); 635 636 DPRINTF(WorkItems, "Work End workid: %d, threadid %d\n", workid, threadid); 637 638 // 639 // If specified, determine if this is the specific work item the user 640 // identified 641 // 642 if (params->work_item_id == -1 || params->work_item_id == workid) { 643 644 uint64_t systemWorkEndCount = sys->incWorkItemsEnd(); 645 int cpuId = tc->getCpuPtr()->cpuId(); 646 647 if (params->work_cpus_ckpt_count != 0 && 648 sys->markWorkItem(cpuId) >= params->work_cpus_ckpt_count) { 649 // 650 // If active cpus equals checkpoint count, create checkpoint 651 // 652 exitSimLoop("checkpoint"); 653 } 654 655 if (params->work_end_ckpt_count != 0 && 656 systemWorkEndCount == params->work_end_ckpt_count) { 657 // 658 // If total work items completed equals checkpoint count, create 659 // checkpoint 660 // 661 exitSimLoop("checkpoint"); 662 } 663 664 if (params->work_end_exit_count != 0 && 665 systemWorkEndCount == params->work_end_exit_count) { 666 // 667 // If total work items completed equals exit count, exit simulation 668 // 669 exitSimLoop("work items exit count reached"); 670 } 671 } 672} 673 674} // namespace PseudoInst 675