From 8dd7700482b8ad7fa5e96469b23f0c917f5e3599 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 28 Jul 2007 20:30:43 -0700 Subject: Turn the instruction tracing code into pluggable sim objects. These need to be refined a little still and given parameters. --HG-- extra : convert_revision : 9a8f5a7bd9dacbebbbd2c235cd890c49a81040d7 --- src/cpu/BaseCPU.py | 6 + src/cpu/ExeTracer.py | 36 +++ src/cpu/IntelTrace.py | 36 +++ src/cpu/LegionTrace.py | 36 +++ src/cpu/NativeTrace.py | 36 +++ src/cpu/SConscript | 11 + src/cpu/base.cc | 2 + src/cpu/base.hh | 8 + src/cpu/exetrace.cc | 788 ++++------------------------------------------- src/cpu/exetrace.hh | 135 ++------ src/cpu/inteltrace.cc | 70 +++++ src/cpu/inteltrace.hh | 84 +++++ src/cpu/legiontrace.cc | 600 ++++++++++++++++++++++++++++++++++++ src/cpu/legiontrace.hh | 77 +++++ src/cpu/nativetrace.cc | 188 +++++++++++ src/cpu/nativetrace.hh | 96 ++++++ src/cpu/o3/fetch_impl.hh | 5 +- src/cpu/simple/atomic.cc | 1 + src/cpu/simple/base.cc | 2 +- src/cpu/simple/timing.cc | 1 + src/sim/InstTracer.py | 35 +++ src/sim/SConscript | 1 + src/sim/insttracer.hh | 146 +++++++++ 23 files changed, 1549 insertions(+), 851 deletions(-) create mode 100644 src/cpu/ExeTracer.py create mode 100644 src/cpu/IntelTrace.py create mode 100644 src/cpu/LegionTrace.py create mode 100644 src/cpu/NativeTrace.py create mode 100644 src/cpu/inteltrace.cc create mode 100644 src/cpu/inteltrace.hh create mode 100644 src/cpu/legiontrace.cc create mode 100644 src/cpu/legiontrace.hh create mode 100644 src/cpu/nativetrace.cc create mode 100644 src/cpu/nativetrace.hh create mode 100644 src/sim/InstTracer.py create mode 100644 src/sim/insttracer.hh (limited to 'src') diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py index 6c2aace51..8be84392d 100644 --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -31,8 +31,12 @@ from m5.params import * from m5.proxy import * from m5 import build_env from Bus import Bus +from InstTracer import InstTracer +from ExeTracer import ExeTracer import sys +default_tracer = ExeTracer() + if build_env['FULL_SYSTEM']: if build_env['TARGET_ISA'] == 'alpha': from AlphaTLB import AlphaDTB, AlphaITB @@ -83,6 +87,8 @@ class BaseCPU(SimObject): clock = Param.Clock('1t', "clock speed") phase = Param.Latency('0ns', "clock phase") + tracer = Param.InstTracer(default_tracer, "Instruction tracer") + _mem_ports = [] def connectMemPorts(self, bus): diff --git a/src/cpu/ExeTracer.py b/src/cpu/ExeTracer.py new file mode 100644 index 000000000..e904f9e7d --- /dev/null +++ b/src/cpu/ExeTracer.py @@ -0,0 +1,36 @@ +# Copyright (c) 2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.SimObject import SimObject +from m5.params import * +from InstTracer import InstTracer + +class ExeTracer(InstTracer): + type = 'ExeTracer' + cxx_namespace = 'Trace' + cxx_class = 'ExeTracer' diff --git a/src/cpu/IntelTrace.py b/src/cpu/IntelTrace.py new file mode 100644 index 000000000..6e8f567b3 --- /dev/null +++ b/src/cpu/IntelTrace.py @@ -0,0 +1,36 @@ +# Copyright (c) 2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.SimObject import SimObject +from m5.params import * +from InstTracer import InstTracer + +class IntelTrace(InstTracer): + type = 'IntelTrace' + cxx_namespace = 'Trace' + cxx_class = 'IntelTrace' diff --git a/src/cpu/LegionTrace.py b/src/cpu/LegionTrace.py new file mode 100644 index 000000000..f9b6470a6 --- /dev/null +++ b/src/cpu/LegionTrace.py @@ -0,0 +1,36 @@ +# Copyright (c) 2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.SimObject import SimObject +from m5.params import * +from InstTracer import InstTracer + +class LegionTrace(InstTracer): + type = 'LegionTrace' + cxx_namespace = 'Trace' + cxx_class = 'LegionTrace' diff --git a/src/cpu/NativeTrace.py b/src/cpu/NativeTrace.py new file mode 100644 index 000000000..96b4e991b --- /dev/null +++ b/src/cpu/NativeTrace.py @@ -0,0 +1,36 @@ +# Copyright (c) 2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.SimObject import SimObject +from m5.params import * +from InstTracer import InstTracer + +class NativeTrace(InstTracer): + type = 'NativeTrace' + cxx_namespace = 'Trace' + cxx_class = 'NativeTrace' diff --git a/src/cpu/SConscript b/src/cpu/SConscript index adf47fa4d..b686c0d95 100644 --- a/src/cpu/SConscript +++ b/src/cpu/SConscript @@ -105,12 +105,15 @@ CheckerSupportedCPUList = ['O3CPU', 'OzoneCPU'] SimObject('BaseCPU.py') SimObject('FuncUnit.py') +SimObject('ExeTracer.py') +SimObject('IntelTrace.py') Source('activity.cc') Source('base.cc') Source('cpuevent.cc') Source('exetrace.cc') Source('func_unit.cc') +Source('inteltrace.cc') Source('pc_event.cc') Source('quiesce_event.cc') Source('static_inst.cc') @@ -123,6 +126,14 @@ if env['FULL_SYSTEM']: Source('intr_control.cc') Source('profile.cc') + if env['TARGET_ISA'] == 'sparc': + SimObject('LegionTrace.py') + Source('legiontrace.cc') + +if env['TARGET_ISA'] == 'x86': + SimObject('NativeTrace.py') + Source('nativetrace.cc') + if env['USE_CHECKER']: Source('checker/cpu.cc') checker_supports = False diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 17c04907a..0fc3b4cea 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -188,6 +188,7 @@ BaseCPU::BaseCPU(Params *p) if (params->profile) profileEvent = new ProfileEvent(this, params->profile); #endif + tracer = params->tracer; } BaseCPU::Params::Params() @@ -196,6 +197,7 @@ BaseCPU::Params::Params() profile = false; #endif checker = NULL; + tracer = NULL; } void diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 4d8300186..76f6e4684 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -38,6 +38,7 @@ #include "base/statistics.hh" #include "config/full_system.hh" #include "sim/eventq.hh" +#include "sim/insttracer.hh" #include "mem/mem_object.hh" #if FULL_SYSTEM @@ -132,8 +133,13 @@ class BaseCPU : public MemObject std::vector threadContexts; std::vector predecoders; + Trace::InstTracer * tracer; + public: + /// Provide access to the tracer pointer + Trace::InstTracer * getTracer() { return tracer; } + /// Notify the CPU that the indicated context is now active. The /// delay parameter indicates the number of ticks to wait before /// executing (typically 0 or 1). @@ -169,6 +175,8 @@ class BaseCPU : public MemObject Tick functionTraceStart; System *system; int cpu_id; + Trace::InstTracer * tracer; + Tick phase; #if FULL_SYSTEM Tick profile; diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc index 25d41811e..38c22da94 100644 --- a/src/cpu/exetrace.cc +++ b/src/cpu/exetrace.cc @@ -31,772 +31,90 @@ * Steve Raasch */ -#include -#include #include -#include -#include -#include "arch/predecoder.hh" -#include "arch/regfile.hh" -#include "arch/utility.hh" #include "base/loader/symtab.hh" -#include "base/socket.hh" -#include "config/full_system.hh" #include "cpu/base.hh" #include "cpu/exetrace.hh" #include "cpu/static_inst.hh" +#include "cpu/thread_context.hh" #include "enums/OpClass.hh" -#include "sim/system.hh" - -#if FULL_SYSTEM -#include "arch/tlb.hh" -#endif - -//XXX This is temporary -#include "arch/isa_specific.hh" -#include "cpu/m5legion_interface.h" +#include "params/ExeTracer.hh" using namespace std; using namespace TheISA; -#if THE_ISA == SPARC_ISA && FULL_SYSTEM -static int diffcount = 0; -static bool wasMicro = false; -#endif - namespace Trace { -SharedData *shared_data = NULL; -ListenSocket *cosim_listener = NULL; void -setupSharedData() -{ - int shmfd = shmget('M' << 24 | getuid(), sizeof(SharedData), 0777); - if (shmfd < 0) - fatal("Couldn't get shared memory fd. Is Legion running?"); - - shared_data = (SharedData*)shmat(shmfd, NULL, SHM_RND); - if (shared_data == (SharedData*)-1) - fatal("Couldn't allocate shared memory"); - - if (shared_data->flags != OWN_M5) - fatal("Shared memory has invalid owner"); - - if (shared_data->version != VERSION) - fatal("Shared Data is wrong version! M5: %d Legion: %d", VERSION, - shared_data->version); - - // step legion forward one cycle so we can get register values - shared_data->flags = OWN_LEGION; -} - -//////////////////////////////////////////////////////////////////////// -// -// Methods for the InstRecord object -// - -#if THE_ISA == SPARC_ISA - -inline char * genCenteredLabel(int length, char * buffer, char * label) -{ - int labelLength = strlen(label); - assert(labelLength <= length); - int leftPad = (length - labelLength) / 2; - int rightPad = length - leftPad - labelLength; - char format[64]; - sprintf(format, "%%%ds%%s%%%ds", leftPad, rightPad); - sprintf(buffer, format, "", label, ""); - return buffer; -} - -inline void printRegPair(ostream & os, char const * title, uint64_t a, uint64_t b) -{ - ccprintf(os, " %16s | %#018x %s %#-018x \n", - title, a, (a == b) ? "|" : "X", b); -} - -inline void printColumnLabels(ostream & os) -{ - static char * regLabel = genCenteredLabel(16, new char[17], "Register"); - static char * m5Label = genCenteredLabel(18, new char[18], "M5"); - static char * legionLabel = genCenteredLabel(18, new char[18], "Legion"); - ccprintf(os, " %s | %s | %s \n", regLabel, m5Label, legionLabel); - ccprintf(os, "--------------------+-----------------------+-----------------------\n"); -} - -inline void printSectionHeader(ostream & os, char * name) -{ - char sectionString[70]; - genCenteredLabel(69, sectionString, name); - ccprintf(os, "====================================================================\n"); - ccprintf(os, "%69s\n", sectionString); - ccprintf(os, "====================================================================\n"); -} - -inline void printLevelHeader(ostream & os, int level) -{ - char sectionString[70]; - char levelName[70]; - sprintf(levelName, "Trap stack level %d", level); - genCenteredLabel(69, sectionString, levelName); - ccprintf(os, "====================================================================\n"); - ccprintf(os, "%69s\n", sectionString); - ccprintf(os, "====================================================================\n"); -} - -#endif - -void -Trace::InstRecord::dump() +Trace::ExeTracerRecord::dump() { ostream &outs = Trace::output(); - DPRINTF(Sparc, "Instruction: %#X\n", staticInst->machInst); - bool diff = true; - if (IsOn(ExecRegDelta)) - { - diff = false; -#ifndef NDEBUG -#if THE_ISA == SPARC_ISA - static int fd = 0; - //Don't print what happens for each micro-op, just print out - //once at the last op, and for regular instructions. - if(!staticInst->isMicroop() || staticInst->isLastMicroop()) - { - if(!cosim_listener) - { - int port = 8000; - cosim_listener = new ListenSocket(); - while(!cosim_listener->listen(port, true)) - { - DPRINTF(GDBMisc, "Can't bind port %d\n", port); - port++; - } - ccprintf(cerr, "Listening for cosimulator on port %d\n", port); - fd = cosim_listener->accept(); - } - char prefix[] = "goli"; - for(int p = 0; p < 4; p++) - { - for(int i = 0; i < 8; i++) - { - uint64_t regVal; - int res = read(fd, ®Val, sizeof(regVal)); - if(res < 0) - panic("First read call failed! %s\n", strerror(errno)); - regVal = TheISA::gtoh(regVal); - uint64_t realRegVal = thread->readIntReg(p * 8 + i); - if((regVal & 0xffffffffULL) != (realRegVal & 0xffffffffULL)) - { - DPRINTF(ExecRegDelta, "Register %s%d should be %#x but is %#x.\n", prefix[p], i, regVal, realRegVal); - diff = true; - } - //ccprintf(outs, "%s%d m5 = %#x statetrace = %#x\n", prefix[p], i, realRegVal, regVal); - } - } - /*for(int f = 0; f <= 62; f+=2) - { - uint64_t regVal; - int res = read(fd, ®Val, sizeof(regVal)); - if(res < 0) - panic("First read call failed! %s\n", strerror(errno)); - regVal = TheISA::gtoh(regVal); - uint64_t realRegVal = thread->readFloatRegBits(f, 64); - if(regVal != realRegVal) - { - DPRINTF(ExecRegDelta, "Register f%d should be %#x but is %#x.\n", f, regVal, realRegVal); - } - }*/ - uint64_t regVal; - int res = read(fd, ®Val, sizeof(regVal)); - if(res < 0) - panic("First read call failed! %s\n", strerror(errno)); - regVal = TheISA::gtoh(regVal); - uint64_t realRegVal = thread->readNextPC(); - if(regVal != realRegVal) - { - DPRINTF(ExecRegDelta, "Register pc should be %#x but is %#x.\n", regVal, realRegVal); - diff = true; - } - res = read(fd, ®Val, sizeof(regVal)); - if(res < 0) - panic("First read call failed! %s\n", strerror(errno)); - regVal = TheISA::gtoh(regVal); - realRegVal = thread->readNextNPC(); - if(regVal != realRegVal) - { - DPRINTF(ExecRegDelta, "Register npc should be %#x but is %#x.\n", regVal, realRegVal); - diff = true; - } - res = read(fd, ®Val, sizeof(regVal)); - if(res < 0) - panic("First read call failed! %s\n", strerror(errno)); - regVal = TheISA::gtoh(regVal); - realRegVal = thread->readIntReg(SparcISA::NumIntArchRegs + 2); - if((regVal & 0xF) != (realRegVal & 0xF)) - { - DPRINTF(ExecRegDelta, "Register ccr should be %#x but is %#x.\n", regVal, realRegVal); - diff = true; - } - } -#endif -#endif -#if 0 //THE_ISA == SPARC_ISA - //Don't print what happens for each micro-op, just print out - //once at the last op, and for regular instructions. - if(!staticInst->isMicroop() || staticInst->isLastMicroop()) - { - static uint64_t regs[32] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0}; - static uint64_t ccr = 0; - static uint64_t y = 0; - static uint64_t floats[32]; - uint64_t newVal; - static const char * prefixes[4] = {"G", "O", "L", "I"}; - - outs << hex; - outs << "PC = " << thread->readNextPC(); - outs << " NPC = " << thread->readNextNPC(); - newVal = thread->readIntReg(SparcISA::NumIntArchRegs + 2); - //newVal = thread->readMiscRegNoEffect(SparcISA::MISCREG_CCR); - if(newVal != ccr) - { - outs << " CCR = " << newVal; - ccr = newVal; - } - newVal = thread->readIntReg(SparcISA::NumIntArchRegs + 1); - //newVal = thread->readMiscRegNoEffect(SparcISA::MISCREG_Y); - if(newVal != y) - { - outs << " Y = " << newVal; - y = newVal; - } - for(int y = 0; y < 4; y++) - { - for(int x = 0; x < 8; x++) - { - int index = x + 8 * y; - newVal = thread->readIntReg(index); - if(regs[index] != newVal) - { - outs << " " << prefixes[y] << dec << x << " = " << hex << newVal; - regs[index] = newVal; - } - } - } - for(int y = 0; y < 32; y++) - { - newVal = thread->readFloatRegBits(2 * y, 64); - if(floats[y] != newVal) - { - outs << " F" << dec << (2 * y) << " = " << hex << newVal; - floats[y] = newVal; - } - } - outs << dec << endl; - } -#endif - } - if(!diff) { - } else if (IsOn(ExecIntel)) { - ccprintf(outs, "%7d ) ", when); - outs << "0x" << hex << PC << ":\t"; - if (staticInst->isLoad()) { - ccprintf(outs, "", addr); - } else if (staticInst->isStore()) { - ccprintf(outs, "", addr); - } - outs << endl; - } else { - if (IsOn(ExecTicks)) - ccprintf(outs, "%7d: ", when); - - outs << thread->getCpuPtr()->name() << " "; - - if (IsOn(ExecSpeculative)) - outs << (misspeculating ? "-" : "+") << " "; - - if (IsOn(ExecThread)) - outs << "T" << thread->getThreadNum() << " : "; - - - std::string sym_str; - Addr sym_addr; - if (debugSymbolTable - && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr) - && IsOn(ExecSymbol)) { - if (PC != sym_addr) - sym_str += csprintf("+%d", PC - sym_addr); - outs << "@" << sym_str << " : "; - } - else { - outs << "0x" << hex << PC << " : "; - } - - // - // Print decoded instruction - // - -#if defined(__GNUC__) && (__GNUC__ < 3) - // There's a bug in gcc 2.x library that prevents setw() - // from working properly on strings - string mc(staticInst->disassemble(PC, debugSymbolTable)); - while (mc.length() < 26) - mc += " "; - outs << mc; -#else - outs << setw(26) << left << staticInst->disassemble(PC, debugSymbolTable); -#endif - - outs << " : "; + if (IsOn(ExecTicks)) + ccprintf(outs, "%7d: ", when); - if (IsOn(ExecOpClass)) { - outs << Enums::OpClassStrings[staticInst->opClass()] << " : "; - } + outs << thread->getCpuPtr()->name() << " "; - if (IsOn(ExecResult) && data_status != DataInvalid) { - outs << " D="; -#if 0 - if (data_status == DataDouble) - ccprintf(outs, "%f", data.as_double); - else - ccprintf(outs, "%#018x", data.as_int); -#else - ccprintf(outs, "%#018x", data.as_int); -#endif - } + if (IsOn(ExecSpeculative)) + outs << (misspeculating ? "-" : "+") << " "; - if (IsOn(ExecEffAddr) && addr_valid) - outs << " A=0x" << hex << addr; + if (IsOn(ExecThread)) + outs << "T" << thread->getThreadNum() << " : "; - if (IsOn(ExecIntRegs) && regs_valid) { - for (int i = 0; i < TheISA::NumIntRegs;) - for (int j = i + 1; i <= j; i++) - ccprintf(outs, "r%02d = %#018x%s", i, - iregs->regs.readReg(i), - ((i == j) ? "\n" : " ")); - outs << "\n"; - } - if (IsOn(ExecFetchSeq) && fetch_seq_valid) - outs << " FetchSeq=" << dec << fetch_seq; - - if (IsOn(ExecCPSeq) && cp_seq_valid) - outs << " CPSeq=" << dec << cp_seq; - - // - // End of line... - // - outs << endl; + std::string sym_str; + Addr sym_addr; + if (debugSymbolTable + && IsOn(ExecSymbol) + && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr)) { + if (PC != sym_addr) + sym_str += csprintf("+%d", PC - sym_addr); + outs << "@" << sym_str << " : "; + } + else { + outs << "0x" << hex << PC << " : "; } -#if THE_ISA == SPARC_ISA && FULL_SYSTEM - static TheISA::Predecoder predecoder(NULL); - // Compare - if (IsOn(ExecLegion)) - { - bool compared = false; - bool diffPC = false; - bool diffCC = false; - bool diffInst = false; - bool diffIntRegs = false; - bool diffFpRegs = false; - bool diffTpc = false; - bool diffTnpc = false; - bool diffTstate = false; - bool diffTt = false; - bool diffTba = false; - bool diffHpstate = false; - bool diffHtstate = false; - bool diffHtba = false; - bool diffPstate = false; - bool diffY = false; - bool diffFsr = false; - bool diffCcr = false; - bool diffTl = false; - bool diffGl = false; - bool diffAsi = false; - bool diffPil = false; - bool diffCwp = false; - bool diffCansave = false; - bool diffCanrestore = false; - bool diffOtherwin = false; - bool diffCleanwin = false; - bool diffTlb = false; - Addr m5Pc, lgnPc; - - if (!shared_data) - setupSharedData(); - - // We took a trap on a micro-op... - if (wasMicro && !staticInst->isMicroop()) - { - // let's skip comparing this tick - while (!compared) - if (shared_data->flags == OWN_M5) { - shared_data->flags = OWN_LEGION; - compared = true; - } - compared = false; - wasMicro = false; - } - - if (staticInst->isLastMicroop()) - wasMicro = false; - else if (staticInst->isMicroop()) - wasMicro = true; - - - if(!staticInst->isMicroop() || staticInst->isLastMicroop()) { - while (!compared) { - if (shared_data->flags == OWN_M5) { - m5Pc = PC & TheISA::PAddrImplMask; - if (bits(shared_data->pstate,3,3)) { - m5Pc &= mask(32); - } - lgnPc = shared_data->pc & TheISA::PAddrImplMask; - if (lgnPc != m5Pc) - diffPC = true; - - if (shared_data->cycle_count != - thread->getCpuPtr()->instCount()) - diffCC = true; - - if (shared_data->instruction != - (SparcISA::MachInst)staticInst->machInst) { - diffInst = true; - } - // assume we have %g0 working correctly - for (int i = 1; i < TheISA::NumIntArchRegs; i++) { - if (thread->readIntReg(i) != shared_data->intregs[i]) { - diffIntRegs = true; - } - } - for (int i = 0; i < TheISA::NumFloatRegs/2; i++) { - if (thread->readFloatRegBits(i*2,FloatRegFile::DoubleWidth) != shared_data->fpregs[i]) { - diffFpRegs = true; - } - } - uint64_t oldTl = thread->readMiscRegNoEffect(MISCREG_TL); - if (oldTl != shared_data->tl) - diffTl = true; - for (int i = 1; i <= MaxTL; i++) { - thread->setMiscRegNoEffect(MISCREG_TL, i); - if (thread->readMiscRegNoEffect(MISCREG_TPC) != - shared_data->tpc[i-1]) - diffTpc = true; - if (thread->readMiscRegNoEffect(MISCREG_TNPC) != - shared_data->tnpc[i-1]) - diffTnpc = true; - if (thread->readMiscRegNoEffect(MISCREG_TSTATE) != - shared_data->tstate[i-1]) - diffTstate = true; - if (thread->readMiscRegNoEffect(MISCREG_TT) != - shared_data->tt[i-1]) - diffTt = true; - if (thread->readMiscRegNoEffect(MISCREG_HTSTATE) != - shared_data->htstate[i-1]) - diffHtstate = true; - } - thread->setMiscRegNoEffect(MISCREG_TL, oldTl); - - if(shared_data->tba != thread->readMiscRegNoEffect(MISCREG_TBA)) - diffTba = true; - //When the hpstate register is read by an instruction, - //legion has bit 11 set. When it's in storage, it doesn't. - //Since we don't directly support seperate interpretations - //of the registers like that, the bit is always set to 1 and - //we just don't compare it. It's not supposed to matter - //anyway. - if((shared_data->hpstate | (1 << 11)) != thread->readMiscRegNoEffect(MISCREG_HPSTATE)) - diffHpstate = true; - if(shared_data->htba != thread->readMiscRegNoEffect(MISCREG_HTBA)) - diffHtba = true; - if(shared_data->pstate != thread->readMiscRegNoEffect(MISCREG_PSTATE)) - diffPstate = true; - //if(shared_data->y != thread->readMiscRegNoEffect(MISCREG_Y)) - if(shared_data->y != - thread->readIntReg(NumIntArchRegs + 1)) - diffY = true; - if(shared_data->fsr != thread->readMiscRegNoEffect(MISCREG_FSR)) { - diffFsr = true; - if (mbits(shared_data->fsr, 63,10) == - mbits(thread->readMiscRegNoEffect(MISCREG_FSR), 63,10)) { - thread->setMiscRegNoEffect(MISCREG_FSR, shared_data->fsr); - diffFsr = false; - } - } - //if(shared_data->ccr != thread->readMiscRegNoEffect(MISCREG_CCR)) - if(shared_data->ccr != - thread->readIntReg(NumIntArchRegs + 2)) - diffCcr = true; - if(shared_data->gl != thread->readMiscRegNoEffect(MISCREG_GL)) - diffGl = true; - if(shared_data->asi != thread->readMiscRegNoEffect(MISCREG_ASI)) - diffAsi = true; - if(shared_data->pil != thread->readMiscRegNoEffect(MISCREG_PIL)) - diffPil = true; - if(shared_data->cwp != thread->readMiscRegNoEffect(MISCREG_CWP)) - diffCwp = true; - //if(shared_data->cansave != thread->readMiscRegNoEffect(MISCREG_CANSAVE)) - if(shared_data->cansave != - thread->readIntReg(NumIntArchRegs + 3)) - diffCansave = true; - //if(shared_data->canrestore != - // thread->readMiscRegNoEffect(MISCREG_CANRESTORE)) - if(shared_data->canrestore != - thread->readIntReg(NumIntArchRegs + 4)) - diffCanrestore = true; - //if(shared_data->otherwin != thread->readMiscRegNoEffect(MISCREG_OTHERWIN)) - if(shared_data->otherwin != - thread->readIntReg(NumIntArchRegs + 6)) - diffOtherwin = true; - //if(shared_data->cleanwin != thread->readMiscRegNoEffect(MISCREG_CLEANWIN)) - if(shared_data->cleanwin != - thread->readIntReg(NumIntArchRegs + 5)) - diffCleanwin = true; - - for (int i = 0; i < 64; i++) { - if (shared_data->itb[i] != thread->getITBPtr()->TteRead(i)) - diffTlb = true; - if (shared_data->dtb[i] != thread->getDTBPtr()->TteRead(i)) - diffTlb = true; - } - - if (diffPC || diffCC || diffInst || diffIntRegs || - diffFpRegs || diffTpc || diffTnpc || diffTstate || - diffTt || diffHpstate || diffHtstate || diffHtba || - diffPstate || diffY || diffCcr || diffTl || diffFsr || - diffGl || diffAsi || diffPil || diffCwp || diffCansave || - diffCanrestore || diffOtherwin || diffCleanwin || diffTlb) - { - - outs << "Differences found between M5 and Legion:"; - if (diffPC) - outs << " [PC]"; - if (diffCC) - outs << " [CC]"; - if (diffInst) - outs << " [Instruction]"; - if (diffIntRegs) - outs << " [IntRegs]"; - if (diffFpRegs) - outs << " [FpRegs]"; - if (diffTpc) - outs << " [Tpc]"; - if (diffTnpc) - outs << " [Tnpc]"; - if (diffTstate) - outs << " [Tstate]"; - if (diffTt) - outs << " [Tt]"; - if (diffHpstate) - outs << " [Hpstate]"; - if (diffHtstate) - outs << " [Htstate]"; - if (diffHtba) - outs << " [Htba]"; - if (diffPstate) - outs << " [Pstate]"; - if (diffY) - outs << " [Y]"; - if (diffFsr) - outs << " [FSR]"; - if (diffCcr) - outs << " [Ccr]"; - if (diffTl) - outs << " [Tl]"; - if (diffGl) - outs << " [Gl]"; - if (diffAsi) - outs << " [Asi]"; - if (diffPil) - outs << " [Pil]"; - if (diffCwp) - outs << " [Cwp]"; - if (diffCansave) - outs << " [Cansave]"; - if (diffCanrestore) - outs << " [Canrestore]"; - if (diffOtherwin) - outs << " [Otherwin]"; - if (diffCleanwin) - outs << " [Cleanwin]"; - if (diffTlb) - outs << " [Tlb]"; - outs << endl << endl; - - outs << right << setfill(' ') << setw(15) - << "M5 PC: " << "0x"<< setw(16) << setfill('0') - << hex << m5Pc << endl; - outs << setfill(' ') << setw(15) - << "Legion PC: " << "0x"<< setw(16) << setfill('0') << hex - << lgnPc << endl << endl; - - outs << right << setfill(' ') << setw(15) - << "M5 CC: " << "0x"<< setw(16) << setfill('0') - << hex << thread->getCpuPtr()->instCount() << endl; - outs << setfill(' ') << setw(15) - << "Legion CC: " << "0x"<< setw(16) << setfill('0') << hex - << shared_data->cycle_count << endl << endl; - outs << setfill(' ') << setw(15) - << "M5 Inst: " << "0x"<< setw(8) - << setfill('0') << hex << staticInst->machInst - << staticInst->disassemble(m5Pc, debugSymbolTable) - << endl; + // + // Print decoded instruction + // - predecoder.setTC(thread); - predecoder.moreBytes(m5Pc, m5Pc, - shared_data->instruction); + outs << setw(26) << left; + outs << staticInst->disassemble(PC, debugSymbolTable); + outs << " : "; - assert(predecoder.extMachInstReady()); + if (IsOn(ExecOpClass)) { + outs << Enums::OpClassStrings[staticInst->opClass()] << " : "; + } - StaticInstPtr legionInst = - StaticInst::decode(predecoder.getExtMachInst(), lgnPc); - outs << setfill(' ') << setw(15) - << " Legion Inst: " - << "0x" << setw(8) << setfill('0') << hex - << shared_data->instruction - << legionInst->disassemble(lgnPc, debugSymbolTable) - << endl << endl; + if (IsOn(ExecResult) && data_status != DataInvalid) { + ccprintf(outs, " D=%#018x", data.as_int); + } - printSectionHeader(outs, "General State"); - printColumnLabels(outs); - printRegPair(outs, "HPstate", - thread->readMiscRegNoEffect(MISCREG_HPSTATE), - shared_data->hpstate | (1 << 11)); - printRegPair(outs, "Htba", - thread->readMiscRegNoEffect(MISCREG_HTBA), - shared_data->htba); - printRegPair(outs, "Pstate", - thread->readMiscRegNoEffect(MISCREG_PSTATE), - shared_data->pstate); - printRegPair(outs, "Y", - //thread->readMiscRegNoEffect(MISCREG_Y), - thread->readIntReg(NumIntArchRegs + 1), - shared_data->y); - printRegPair(outs, "FSR", - thread->readMiscRegNoEffect(MISCREG_FSR), - shared_data->fsr); - printRegPair(outs, "Ccr", - //thread->readMiscRegNoEffect(MISCREG_CCR), - thread->readIntReg(NumIntArchRegs + 2), - shared_data->ccr); - printRegPair(outs, "Tl", - thread->readMiscRegNoEffect(MISCREG_TL), - shared_data->tl); - printRegPair(outs, "Gl", - thread->readMiscRegNoEffect(MISCREG_GL), - shared_data->gl); - printRegPair(outs, "Asi", - thread->readMiscRegNoEffect(MISCREG_ASI), - shared_data->asi); - printRegPair(outs, "Pil", - thread->readMiscRegNoEffect(MISCREG_PIL), - shared_data->pil); - printRegPair(outs, "Cwp", - thread->readMiscRegNoEffect(MISCREG_CWP), - shared_data->cwp); - printRegPair(outs, "Cansave", - //thread->readMiscRegNoEffect(MISCREG_CANSAVE), - thread->readIntReg(NumIntArchRegs + 3), - shared_data->cansave); - printRegPair(outs, "Canrestore", - //thread->readMiscRegNoEffect(MISCREG_CANRESTORE), - thread->readIntReg(NumIntArchRegs + 4), - shared_data->canrestore); - printRegPair(outs, "Otherwin", - //thread->readMiscRegNoEffect(MISCREG_OTHERWIN), - thread->readIntReg(NumIntArchRegs + 6), - shared_data->otherwin); - printRegPair(outs, "Cleanwin", - //thread->readMiscRegNoEffect(MISCREG_CLEANWIN), - thread->readIntReg(NumIntArchRegs + 5), - shared_data->cleanwin); - outs << endl; - for (int i = 1; i <= MaxTL; i++) { - printLevelHeader(outs, i); - printColumnLabels(outs); - thread->setMiscRegNoEffect(MISCREG_TL, i); - printRegPair(outs, "Tpc", - thread->readMiscRegNoEffect(MISCREG_TPC), - shared_data->tpc[i-1]); - printRegPair(outs, "Tnpc", - thread->readMiscRegNoEffect(MISCREG_TNPC), - shared_data->tnpc[i-1]); - printRegPair(outs, "Tstate", - thread->readMiscRegNoEffect(MISCREG_TSTATE), - shared_data->tstate[i-1]); - printRegPair(outs, "Tt", - thread->readMiscRegNoEffect(MISCREG_TT), - shared_data->tt[i-1]); - printRegPair(outs, "Htstate", - thread->readMiscRegNoEffect(MISCREG_HTSTATE), - shared_data->htstate[i-1]); - } - thread->setMiscRegNoEffect(MISCREG_TL, oldTl); - outs << endl; + if (IsOn(ExecEffAddr) && addr_valid) + outs << " A=0x" << hex << addr; - printSectionHeader(outs, "General Purpose Registers"); - static const char * regtypes[4] = {"%g", "%o", "%l", "%i"}; - for(int y = 0; y < 4; y++) { - for(int x = 0; x < 8; x++) { - char label[8]; - sprintf(label, "%s%d", regtypes[y], x); - printRegPair(outs, label, - thread->readIntReg(y*8+x), - shared_data->intregs[y*8+x]); - } - } - if (diffFpRegs) { - for (int x = 0; x < 32; x++) { - char label[8]; - sprintf(label, "%%f%d", x); - printRegPair(outs, label, - thread->readFloatRegBits(x*2,FloatRegFile::DoubleWidth), - shared_data->fpregs[x]); - } - } - if (diffTlb) { - printColumnLabels(outs); - char label[8]; - for (int x = 0; x < 64; x++) { - if (shared_data->itb[x] != ULL(0xFFFFFFFFFFFFFFFF) || - thread->getITBPtr()->TteRead(x) != ULL(0xFFFFFFFFFFFFFFFF)) { - sprintf(label, "I-TLB:%02d", x); - printRegPair(outs, label, thread->getITBPtr()->TteRead(x), - shared_data->itb[x]); - } - } - for (int x = 0; x < 64; x++) { - if (shared_data->dtb[x] != ULL(0xFFFFFFFFFFFFFFFF) || - thread->getDTBPtr()->TteRead(x) != ULL(0xFFFFFFFFFFFFFFFF)) { - sprintf(label, "D-TLB:%02d", x); - printRegPair(outs, label, thread->getDTBPtr()->TteRead(x), - shared_data->dtb[x]); - } - } - thread->getITBPtr()->dumpAll(); - thread->getDTBPtr()->dumpAll(); - } + if (IsOn(ExecFetchSeq) && fetch_seq_valid) + outs << " FetchSeq=" << dec << fetch_seq; - diffcount++; - if (diffcount > 3) - fatal("Differences found between Legion and M5\n"); - } else - diffcount = 0; + if (IsOn(ExecCPSeq) && cp_seq_valid) + outs << " CPSeq=" << dec << cp_seq; - compared = true; - shared_data->flags = OWN_LEGION; - } - } // while - } // if not microop - } -#endif + // + // End of line... + // + outs << endl; } /* namespace Trace */ } + +//////////////////////////////////////////////////////////////////////// +// +// ExeTracer Simulation Object +// +Trace::ExeTracer * +ExeTracerParams::create() +{ + return new Trace::ExeTracer(name); +}; diff --git a/src/cpu/exetrace.hh b/src/cpu/exetrace.hh index 8c0fa22cb..76907d955 100644 --- a/src/cpu/exetrace.hh +++ b/src/cpu/exetrace.hh @@ -32,141 +32,52 @@ #ifndef __EXETRACE_HH__ #define __EXETRACE_HH__ -#include -#include -#include - #include "base/trace.hh" -#include "cpu/inst_seq.hh" // for InstSeqNum #include "cpu/static_inst.hh" -#include "cpu/thread_context.hh" #include "sim/host.hh" +#include "sim/insttracer.hh" class ThreadContext; namespace Trace { -class InstRecord +class ExeTracerRecord : public InstRecord { - protected: - typedef TheISA::IntRegFile IntRegFile; - - Tick when; - - // The following fields are initialized by the constructor and - // thus guaranteed to be valid. - ThreadContext *thread; - // need to make this ref-counted so it doesn't go away before we - // dump the record - StaticInstPtr staticInst; - Addr PC; - bool misspeculating; - - // The remaining fields are only valid for particular instruction - // types (e.g, addresses for memory ops) or when particular - // options are enabled (e.g., tracing full register contents). - // Each data field has an associated valid flag to indicate - // whether the data field is valid. - Addr addr; - bool addr_valid; - - union { - uint64_t as_int; - double as_double; - } data; - enum { - DataInvalid = 0, - DataInt8 = 1, // set to equal number of bytes - DataInt16 = 2, - DataInt32 = 4, - DataInt64 = 8, - DataDouble = 3 - } data_status; - - InstSeqNum fetch_seq; - bool fetch_seq_valid; - - InstSeqNum cp_seq; - bool cp_seq_valid; - - struct iRegFile { - IntRegFile regs; - }; - iRegFile *iregs; - bool regs_valid; - public: - InstRecord(Tick _when, ThreadContext *_thread, - const StaticInstPtr &_staticInst, - Addr _pc, bool spec) - : when(_when), thread(_thread), - staticInst(_staticInst), PC(_pc), - misspeculating(spec) + ExeTracerRecord(Tick _when, ThreadContext *_thread, + const StaticInstPtr &_staticInst, Addr _pc, bool spec) + : InstRecord(_when, _thread, _staticInst, _pc, spec) { - data_status = DataInvalid; - addr_valid = false; - regs_valid = false; - - fetch_seq_valid = false; - cp_seq_valid = false; } - ~InstRecord() { } - - void setAddr(Addr a) { addr = a; addr_valid = true; } - - void setData(Twin64_t d) { data.as_int = d.a; data_status = DataInt64; } - void setData(Twin32_t d) { data.as_int = d.a; data_status = DataInt32; } - void setData(uint64_t d) { data.as_int = d; data_status = DataInt64; } - void setData(uint32_t d) { data.as_int = d; data_status = DataInt32; } - void setData(uint16_t d) { data.as_int = d; data_status = DataInt16; } - void setData(uint8_t d) { data.as_int = d; data_status = DataInt8; } - - void setData(int64_t d) { setData((uint64_t)d); } - void setData(int32_t d) { setData((uint32_t)d); } - void setData(int16_t d) { setData((uint16_t)d); } - void setData(int8_t d) { setData((uint8_t)d); } - - void setData(double d) { data.as_double = d; data_status = DataDouble; } - - void setFetchSeq(InstSeqNum seq) - { fetch_seq = seq; fetch_seq_valid = true; } - - void setCPSeq(InstSeqNum seq) - { cp_seq = seq; cp_seq_valid = true; } - - void setRegs(const IntRegFile ®s); - void dump(); }; - -inline void -InstRecord::setRegs(const IntRegFile ®s) +class ExeTracer : public InstTracer { - if (!iregs) - iregs = new iRegFile; + public: - std::memcpy(&iregs->regs, ®s, sizeof(IntRegFile)); - regs_valid = true; -} + ExeTracer(const std::string & name) : InstTracer(name) + {} -inline InstRecord * -getInstRecord(Tick when, ThreadContext *tc, const StaticInstPtr staticInst, - Addr pc) -{ - if (!IsOn(ExecEnable)) - return NULL; + InstRecord * + getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc) + { + if (!IsOn(ExecEnable)) + return NULL; - if (!Trace::enabled) - return NULL; + if (!Trace::enabled) + return NULL; - if (!IsOn(ExecSpeculative) && tc->misspeculating()) - return NULL; + if (!IsOn(ExecSpeculative) && tc->misspeculating()) + return NULL; - return new InstRecord(when, tc, staticInst, pc, tc->misspeculating()); -} + return new ExeTracerRecord(when, tc, + staticInst, pc, tc->misspeculating()); + } +}; /* namespace Trace */ } diff --git a/src/cpu/inteltrace.cc b/src/cpu/inteltrace.cc new file mode 100644 index 000000000..afa51b517 --- /dev/null +++ b/src/cpu/inteltrace.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Lisa Hsu + * Nathan Binkert + * Steve Raasch + */ + +#include + +#include "cpu/exetrace.hh" +#include "cpu/inteltrace.hh" +#include "cpu/static_inst.hh" +#include "params/IntelTrace.hh" + +using namespace std; +using namespace TheISA; + +namespace Trace { + +void +Trace::IntelTraceRecord::dump() +{ + ostream &outs = Trace::output(); + ccprintf(outs, "%7d ) ", when); + outs << "0x" << hex << PC << ":\t"; + if (staticInst->isLoad()) { + ccprintf(outs, "", addr); + } else if (staticInst->isStore()) { + ccprintf(outs, "", addr); + } + outs << endl; +} + +/* namespace Trace */ } + +//////////////////////////////////////////////////////////////////////// +// +// ExeTracer Simulation Object +// +Trace::IntelTrace * +IntelTraceParams::create() +{ + return new Trace::IntelTrace(name); +}; diff --git a/src/cpu/inteltrace.hh b/src/cpu/inteltrace.hh new file mode 100644 index 000000000..21afe0fc0 --- /dev/null +++ b/src/cpu/inteltrace.hh @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Nathan Binkert + */ + +#ifndef __INTELTRACE_HH__ +#define __INTELTRACE_HH__ + +#include "base/trace.hh" +#include "cpu/static_inst.hh" +#include "sim/host.hh" +#include "sim/insttracer.hh" + +class ThreadContext; + + +namespace Trace { + +class IntelTraceRecord : public InstRecord +{ + public: + IntelTraceRecord(Tick _when, ThreadContext *_thread, + const StaticInstPtr &_staticInst, Addr _pc, bool spec) + : InstRecord(_when, _thread, _staticInst, _pc, spec) + { + } + + void dump(); +}; + +class IntelTrace : public InstTracer +{ + public: + + IntelTrace(const std::string & name) : InstTracer(name) + {} + + IntelTraceRecord * + getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc) + { + if (!IsOn(ExecEnable)) + return NULL; + + if (!Trace::enabled) + return NULL; + + if (!IsOn(ExecSpeculative) && tc->misspeculating()) + return NULL; + + return new IntelTraceRecord(when, tc, + staticInst, pc, tc->misspeculating()); + } +}; + +/* namespace Trace */ } + +#endif // __EXETRACE_HH__ diff --git a/src/cpu/legiontrace.cc b/src/cpu/legiontrace.cc new file mode 100644 index 000000000..58181cb88 --- /dev/null +++ b/src/cpu/legiontrace.cc @@ -0,0 +1,600 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Lisa Hsu + * Nathan Binkert + * Steve Raasch + */ + +#include "arch/isa_specific.hh" +#if THE_ISA != SPARC_ISA + #error Legion tracing only works with SPARC simulations! +#endif + +#include "config/full_system.hh" +#if !FULL_SYSTEM + #error Legion tracing only works in full system! +#endif + +#include +#include +#include + +#include "arch/sparc/predecoder.hh" +#include "arch/sparc/regfile.hh" +#include "arch/sparc/utility.hh" +#include "base/socket.hh" +#include "cpu/base.hh" +#include "cpu/legiontrace.hh" +#include "cpu/static_inst.hh" +#include "cpu/thread_context.hh" +#include "params/LegionTrace.hh" +#include "sim/system.hh" + +#if FULL_SYSTEM +#include "arch/tlb.hh" +#endif + +//XXX This is temporary +#include "cpu/m5legion_interface.h" + +using namespace std; +using namespace TheISA; + +#if FULL_SYSTEM +static int diffcount = 0; +static bool wasMicro = false; +#endif + +namespace Trace { +SharedData *shared_data = NULL; + +void +setupSharedData() +{ + int shmfd = shmget('M' << 24 | getuid(), sizeof(SharedData), 0777); + if (shmfd < 0) + fatal("Couldn't get shared memory fd. Is Legion running?"); + + shared_data = (SharedData*)shmat(shmfd, NULL, SHM_RND); + if (shared_data == (SharedData*)-1) + fatal("Couldn't allocate shared memory"); + + if (shared_data->flags != OWN_M5) + fatal("Shared memory has invalid owner"); + + if (shared_data->version != VERSION) + fatal("Shared Data is wrong version! M5: %d Legion: %d", VERSION, + shared_data->version); + + // step legion forward one cycle so we can get register values + shared_data->flags = OWN_LEGION; +} + +//////////////////////////////////////////////////////////////////////// +// +// Utility methods for pretty printing a report about a difference +// + +inline char * genCenteredLabel(int length, char * buffer, char * label) +{ + int labelLength = strlen(label); + assert(labelLength <= length); + int leftPad = (length - labelLength) / 2; + int rightPad = length - leftPad - labelLength; + char format[64]; + sprintf(format, "%%%ds%%s%%%ds", leftPad, rightPad); + sprintf(buffer, format, "", label, ""); + return buffer; +} + +inline void printRegPair(ostream & os, char const * title, uint64_t a, uint64_t b) +{ + ccprintf(os, " %16s | %#018x %s %#-018x \n", + title, a, (a == b) ? "|" : "X", b); +} + +inline void printColumnLabels(ostream & os) +{ + static char * regLabel = genCenteredLabel(16, new char[17], "Register"); + static char * m5Label = genCenteredLabel(18, new char[18], "M5"); + static char * legionLabel = genCenteredLabel(18, new char[18], "Legion"); + ccprintf(os, " %s | %s | %s \n", regLabel, m5Label, legionLabel); + ccprintf(os, "--------------------+-----------------------+-----------------------\n"); +} + +inline void printSectionHeader(ostream & os, char * name) +{ + char sectionString[70]; + genCenteredLabel(69, sectionString, name); + ccprintf(os, "====================================================================\n"); + ccprintf(os, "%69s\n", sectionString); + ccprintf(os, "====================================================================\n"); +} + +inline void printLevelHeader(ostream & os, int level) +{ + char sectionString[70]; + char levelName[70]; + sprintf(levelName, "Trap stack level %d", level); + genCenteredLabel(69, sectionString, levelName); + ccprintf(os, "====================================================================\n"); + ccprintf(os, "%69s\n", sectionString); + ccprintf(os, "====================================================================\n"); +} + +void +Trace::LegionTraceRecord::dump() +{ + ostream &outs = Trace::output(); + + static TheISA::Predecoder predecoder(NULL); + // Compare + bool compared = false; + bool diffPC = false; + bool diffCC = false; + bool diffInst = false; + bool diffIntRegs = false; + bool diffFpRegs = false; + bool diffTpc = false; + bool diffTnpc = false; + bool diffTstate = false; + bool diffTt = false; + bool diffTba = false; + bool diffHpstate = false; + bool diffHtstate = false; + bool diffHtba = false; + bool diffPstate = false; + bool diffY = false; + bool diffFsr = false; + bool diffCcr = false; + bool diffTl = false; + bool diffGl = false; + bool diffAsi = false; + bool diffPil = false; + bool diffCwp = false; + bool diffCansave = false; + bool diffCanrestore = false; + bool diffOtherwin = false; + bool diffCleanwin = false; + bool diffTlb = false; + Addr m5Pc, lgnPc; + + if (!shared_data) + setupSharedData(); + + // We took a trap on a micro-op... + if (wasMicro && !staticInst->isMicroop()) + { + // let's skip comparing this tick + while (!compared) + if (shared_data->flags == OWN_M5) { + shared_data->flags = OWN_LEGION; + compared = true; + } + compared = false; + wasMicro = false; + } + + if (staticInst->isLastMicroop()) + wasMicro = false; + else if (staticInst->isMicroop()) + wasMicro = true; + + + if(!staticInst->isMicroop() || staticInst->isLastMicroop()) { + while (!compared) { + if (shared_data->flags == OWN_M5) { + m5Pc = PC & SparcISA::PAddrImplMask; + if (bits(shared_data->pstate,3,3)) { + m5Pc &= mask(32); + } + lgnPc = shared_data->pc & SparcISA::PAddrImplMask; + if (lgnPc != m5Pc) + diffPC = true; + + if (shared_data->cycle_count != + thread->getCpuPtr()->instCount()) + diffCC = true; + + if (shared_data->instruction != + (SparcISA::MachInst)staticInst->machInst) { + diffInst = true; + } + // assume we have %g0 working correctly + for (int i = 1; i < TheISA::NumIntArchRegs; i++) { + if (thread->readIntReg(i) != shared_data->intregs[i]) { + diffIntRegs = true; + } + } + for (int i = 0; i < TheISA::NumFloatRegs/2; i++) { + if (thread->readFloatRegBits(i*2, + FloatRegFile::DoubleWidth) != + shared_data->fpregs[i]) { + diffFpRegs = true; + } + } + uint64_t oldTl = + thread->readMiscRegNoEffect(MISCREG_TL); + if (oldTl != shared_data->tl) + diffTl = true; + for (int i = 1; i <= MaxTL; i++) { + thread->setMiscRegNoEffect(MISCREG_TL, i); + if (thread->readMiscRegNoEffect(MISCREG_TPC) != + shared_data->tpc[i-1]) + diffTpc = true; + if (thread->readMiscRegNoEffect(MISCREG_TNPC) != + shared_data->tnpc[i-1]) + diffTnpc = true; + if (thread->readMiscRegNoEffect(MISCREG_TSTATE) != + shared_data->tstate[i-1]) + diffTstate = true; + if (thread->readMiscRegNoEffect(MISCREG_TT) != + shared_data->tt[i-1]) + diffTt = true; + if (thread->readMiscRegNoEffect(MISCREG_HTSTATE) != + shared_data->htstate[i-1]) + diffHtstate = true; + } + thread->setMiscRegNoEffect(MISCREG_TL, oldTl); + + if(shared_data->tba != thread->readMiscRegNoEffect(MISCREG_TBA)) + diffTba = true; + //When the hpstate register is read by an instruction, + //legion has bit 11 set. When it's in storage, it doesn't. + //Since we don't directly support seperate interpretations + //of the registers like that, the bit is always set to 1 and + //we just don't compare it. It's not supposed to matter + //anyway. + if((shared_data->hpstate | (1 << 11)) != + thread->readMiscRegNoEffect(MISCREG_HPSTATE)) + diffHpstate = true; + if(shared_data->htba != + thread->readMiscRegNoEffect(MISCREG_HTBA)) + diffHtba = true; + if(shared_data->pstate != + thread->readMiscRegNoEffect(MISCREG_PSTATE)) + diffPstate = true; + //if(shared_data->y != + // thread->readMiscRegNoEffect(MISCREG_Y)) + if(shared_data->y != + thread->readIntReg(NumIntArchRegs + 1)) + diffY = true; + if(shared_data->fsr != + thread->readMiscRegNoEffect(MISCREG_FSR)) { + diffFsr = true; + if (mbits(shared_data->fsr, 63,10) == + mbits(thread->readMiscRegNoEffect(MISCREG_FSR), + 63,10)) { + thread->setMiscRegNoEffect(MISCREG_FSR, + shared_data->fsr); + diffFsr = false; + } + } + //if(shared_data->ccr != + // thread->readMiscRegNoEffect(MISCREG_CCR)) + if(shared_data->ccr != + thread->readIntReg(NumIntArchRegs + 2)) + diffCcr = true; + if(shared_data->gl != + thread->readMiscRegNoEffect(MISCREG_GL)) + diffGl = true; + if(shared_data->asi != + thread->readMiscRegNoEffect(MISCREG_ASI)) + diffAsi = true; + if(shared_data->pil != + thread->readMiscRegNoEffect(MISCREG_PIL)) + diffPil = true; + if(shared_data->cwp != + thread->readMiscRegNoEffect(MISCREG_CWP)) + diffCwp = true; + //if(shared_data->cansave != + // thread->readMiscRegNoEffect(MISCREG_CANSAVE)) + if(shared_data->cansave != + thread->readIntReg(NumIntArchRegs + 3)) + diffCansave = true; + //if(shared_data->canrestore != + // thread->readMiscRegNoEffect(MISCREG_CANRESTORE)) + if(shared_data->canrestore != + thread->readIntReg(NumIntArchRegs + 4)) + diffCanrestore = true; + //if(shared_data->otherwin != + // thread->readMiscRegNoEffect(MISCREG_OTHERWIN)) + if(shared_data->otherwin != + thread->readIntReg(NumIntArchRegs + 6)) + diffOtherwin = true; + //if(shared_data->cleanwin != + // thread->readMiscRegNoEffect(MISCREG_CLEANWIN)) + if(shared_data->cleanwin != + thread->readIntReg(NumIntArchRegs + 5)) + diffCleanwin = true; + + for (int i = 0; i < 64; i++) { + if (shared_data->itb[i] != + thread->getITBPtr()->TteRead(i)) + diffTlb = true; + if (shared_data->dtb[i] != + thread->getDTBPtr()->TteRead(i)) + diffTlb = true; + } + + if (diffPC || diffCC || diffInst || + diffIntRegs || diffFpRegs || + diffTpc || diffTnpc || diffTstate || diffTt || + diffHpstate || diffHtstate || diffHtba || + diffPstate || diffY || diffCcr || diffTl || diffFsr || + diffGl || diffAsi || diffPil || diffCwp || + diffCansave || diffCanrestore || + diffOtherwin || diffCleanwin || diffTlb) { + + outs << "Differences found between M5 and Legion:"; + if (diffPC) + outs << " [PC]"; + if (diffCC) + outs << " [CC]"; + if (diffInst) + outs << " [Instruction]"; + if (diffIntRegs) + outs << " [IntRegs]"; + if (diffFpRegs) + outs << " [FpRegs]"; + if (diffTpc) + outs << " [Tpc]"; + if (diffTnpc) + outs << " [Tnpc]"; + if (diffTstate) + outs << " [Tstate]"; + if (diffTt) + outs << " [Tt]"; + if (diffHpstate) + outs << " [Hpstate]"; + if (diffHtstate) + outs << " [Htstate]"; + if (diffHtba) + outs << " [Htba]"; + if (diffPstate) + outs << " [Pstate]"; + if (diffY) + outs << " [Y]"; + if (diffFsr) + outs << " [FSR]"; + if (diffCcr) + outs << " [Ccr]"; + if (diffTl) + outs << " [Tl]"; + if (diffGl) + outs << " [Gl]"; + if (diffAsi) + outs << " [Asi]"; + if (diffPil) + outs << " [Pil]"; + if (diffCwp) + outs << " [Cwp]"; + if (diffCansave) + outs << " [Cansave]"; + if (diffCanrestore) + outs << " [Canrestore]"; + if (diffOtherwin) + outs << " [Otherwin]"; + if (diffCleanwin) + outs << " [Cleanwin]"; + if (diffTlb) + outs << " [Tlb]"; + outs << endl << endl; + + outs << right << setfill(' ') << setw(15) + << "M5 PC: " << "0x"<< setw(16) << setfill('0') + << hex << m5Pc << endl; + outs << setfill(' ') << setw(15) + << "Legion PC: " << "0x" + << setw(16) << setfill('0') << hex + << lgnPc << endl << endl; + + outs << right << setfill(' ') << setw(15) + << "M5 CC: " << "0x" + << setw(16) << setfill('0') << hex + << thread->getCpuPtr()->instCount() << endl; + outs << setfill(' ') << setw(15) + << "Legion CC: " << "0x" + << setw(16) << setfill('0') << hex + << shared_data->cycle_count << endl << endl; + + outs << setfill(' ') << setw(15) + << "M5 Inst: " << "0x" + << setw(8) << setfill('0') << hex + << staticInst->machInst + << staticInst->disassemble(m5Pc, debugSymbolTable) + << endl; + + predecoder.setTC(thread); + predecoder.moreBytes(m5Pc, m5Pc, + shared_data->instruction); + + assert(predecoder.extMachInstReady()); + + StaticInstPtr legionInst = + StaticInst::decode(predecoder.getExtMachInst(), lgnPc); + outs << setfill(' ') << setw(15) + << " Legion Inst: " + << "0x" << setw(8) << setfill('0') << hex + << shared_data->instruction + << legionInst->disassemble(lgnPc, debugSymbolTable) + << endl << endl; + + printSectionHeader(outs, "General State"); + printColumnLabels(outs); + printRegPair(outs, "HPstate", + thread->readMiscRegNoEffect(MISCREG_HPSTATE), + shared_data->hpstate | (1 << 11)); + printRegPair(outs, "Htba", + thread->readMiscRegNoEffect(MISCREG_HTBA), + shared_data->htba); + printRegPair(outs, "Pstate", + thread->readMiscRegNoEffect(MISCREG_PSTATE), + shared_data->pstate); + printRegPair(outs, "Y", + //thread->readMiscRegNoEffect(MISCREG_Y), + thread->readIntReg(NumIntArchRegs + 1), + shared_data->y); + printRegPair(outs, "FSR", + thread->readMiscRegNoEffect(MISCREG_FSR), + shared_data->fsr); + printRegPair(outs, "Ccr", + //thread->readMiscRegNoEffect(MISCREG_CCR), + thread->readIntReg(NumIntArchRegs + 2), + shared_data->ccr); + printRegPair(outs, "Tl", + thread->readMiscRegNoEffect(MISCREG_TL), + shared_data->tl); + printRegPair(outs, "Gl", + thread->readMiscRegNoEffect(MISCREG_GL), + shared_data->gl); + printRegPair(outs, "Asi", + thread->readMiscRegNoEffect(MISCREG_ASI), + shared_data->asi); + printRegPair(outs, "Pil", + thread->readMiscRegNoEffect(MISCREG_PIL), + shared_data->pil); + printRegPair(outs, "Cwp", + thread->readMiscRegNoEffect(MISCREG_CWP), + shared_data->cwp); + printRegPair(outs, "Cansave", + //thread->readMiscRegNoEffect(MISCREG_CANSAVE), + thread->readIntReg(NumIntArchRegs + 3), + shared_data->cansave); + printRegPair(outs, "Canrestore", + //thread->readMiscRegNoEffect(MISCREG_CANRESTORE), + thread->readIntReg(NumIntArchRegs + 4), + shared_data->canrestore); + printRegPair(outs, "Otherwin", + //thread->readMiscRegNoEffect(MISCREG_OTHERWIN), + thread->readIntReg(NumIntArchRegs + 6), + shared_data->otherwin); + printRegPair(outs, "Cleanwin", + //thread->readMiscRegNoEffect(MISCREG_CLEANWIN), + thread->readIntReg(NumIntArchRegs + 5), + shared_data->cleanwin); + outs << endl; + for (int i = 1; i <= MaxTL; i++) { + printLevelHeader(outs, i); + printColumnLabels(outs); + thread->setMiscRegNoEffect(MISCREG_TL, i); + printRegPair(outs, "Tpc", + thread->readMiscRegNoEffect(MISCREG_TPC), + shared_data->tpc[i-1]); + printRegPair(outs, "Tnpc", + thread->readMiscRegNoEffect(MISCREG_TNPC), + shared_data->tnpc[i-1]); + printRegPair(outs, "Tstate", + thread->readMiscRegNoEffect(MISCREG_TSTATE), + shared_data->tstate[i-1]); + printRegPair(outs, "Tt", + thread->readMiscRegNoEffect(MISCREG_TT), + shared_data->tt[i-1]); + printRegPair(outs, "Htstate", + thread->readMiscRegNoEffect(MISCREG_HTSTATE), + shared_data->htstate[i-1]); + } + thread->setMiscRegNoEffect(MISCREG_TL, oldTl); + outs << endl; + + printSectionHeader(outs, "General Purpose Registers"); + static const char * regtypes[4] = + {"%g", "%o", "%l", "%i"}; + for(int y = 0; y < 4; y++) { + for(int x = 0; x < 8; x++) { + char label[8]; + sprintf(label, "%s%d", regtypes[y], x); + printRegPair(outs, label, + thread->readIntReg(y*8+x), + shared_data->intregs[y*8+x]); + } + } + if (diffFpRegs) { + for (int x = 0; x < 32; x++) { + char label[8]; + sprintf(label, "%%f%d", x); + printRegPair(outs, label, + thread->readFloatRegBits(x*2, + FloatRegFile::DoubleWidth), + shared_data->fpregs[x]); + } + } + if (diffTlb) { + printColumnLabels(outs); + char label[8]; + for (int x = 0; x < 64; x++) { + if (shared_data->itb[x] != + ULL(0xFFFFFFFFFFFFFFFF) || + thread->getITBPtr()->TteRead(x) != + ULL(0xFFFFFFFFFFFFFFFF)) { + sprintf(label, "I-TLB:%02d", x); + printRegPair(outs, label, + thread->getITBPtr()->TteRead(x), + shared_data->itb[x]); + } + } + for (int x = 0; x < 64; x++) { + if (shared_data->dtb[x] != + ULL(0xFFFFFFFFFFFFFFFF) || + thread->getDTBPtr()->TteRead(x) != + ULL(0xFFFFFFFFFFFFFFFF)) { + sprintf(label, "D-TLB:%02d", x); + printRegPair(outs, label, + thread->getDTBPtr()->TteRead(x), + shared_data->dtb[x]); + } + } + thread->getITBPtr()->dumpAll(); + thread->getDTBPtr()->dumpAll(); + } + + diffcount++; + if (diffcount > 3) + fatal("Differences found between Legion and M5\n"); + } else + diffcount = 0; + + compared = true; + shared_data->flags = OWN_LEGION; + } + } // while + } // if not microop +} + +/* namespace Trace */ } + +//////////////////////////////////////////////////////////////////////// +// +// ExeTracer Simulation Object +// +Trace::LegionTrace * +LegionTraceParams::create() +{ + return new Trace::LegionTrace(name); +}; diff --git a/src/cpu/legiontrace.hh b/src/cpu/legiontrace.hh new file mode 100644 index 000000000..55c05e7ae --- /dev/null +++ b/src/cpu/legiontrace.hh @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Nathan Binkert + */ + +#ifndef __LEGIONTRACE_HH__ +#define __LEGIONTRACE_HH__ + +#include "base/trace.hh" +#include "cpu/static_inst.hh" +#include "sim/host.hh" +#include "sim/insttracer.hh" + +class ThreadContext; + +namespace Trace { + +class LegionTraceRecord : public InstRecord +{ + public: + LegionTraceRecord(Tick _when, ThreadContext *_thread, + const StaticInstPtr &_staticInst, Addr _pc, bool spec) + : InstRecord(_when, _thread, _staticInst, _pc, spec) + { + } + + void dump(); +}; + +class LegionTrace : public InstTracer +{ + public: + + LegionTrace(const std::string & name) : InstTracer(name) + {} + + LegionTraceRecord * + getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc) + { + if (tc->misspeculating()) + return NULL; + + return new LegionTraceRecord(when, tc, + staticInst, pc, tc->misspeculating()); + } +}; + +/* namespace Trace */ } + +#endif // __LEGIONTRACE_HH__ diff --git a/src/cpu/nativetrace.cc b/src/cpu/nativetrace.cc new file mode 100644 index 000000000..57304c79b --- /dev/null +++ b/src/cpu/nativetrace.cc @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Lisa Hsu + * Nathan Binkert + * Steve Raasch + */ + +#include + +#include "arch/regfile.hh" +#include "arch/utility.hh" +#include "base/loader/symtab.hh" +#include "base/socket.hh" +#include "cpu/nativetrace.hh" +#include "cpu/static_inst.hh" +#include "cpu/thread_context.hh" +#include "params/NativeTrace.hh" + +//XXX This is temporary +#include "arch/isa_specific.hh" + +using namespace std; +using namespace TheISA; + +namespace Trace { + +NativeTrace::NativeTrace(const std::string & _name) : InstTracer(_name) +{ + int port = 8000; + while(!native_listener.listen(port, true)) + { + DPRINTF(GDBMisc, "Can't bind port %d\n", port); + port++; + } + ccprintf(cerr, "Listening for native process on port %d\n", port); + fd = native_listener.accept(); +} + +bool +NativeTraceRecord::checkIntReg(const char * regName, int index, int size) +{ + uint64_t regVal; + int res = read(parent->fd, ®Val, size); + if(res < 0) + panic("Read call failed! %s\n", strerror(errno)); + regVal = TheISA::gtoh(regVal); + uint64_t realRegVal = thread->readIntReg(index); + if(regVal != realRegVal) + { + DPRINTFN("Register %s should be %#x but is %#x.\n", + regName, regVal, realRegVal); + return false; + } + return true; +} + +bool NativeTraceRecord::checkPC(const char * regName, int size) +{ + uint64_t regVal; + int res = read(parent->fd, ®Val, size); + if(res < 0) + panic("Read call failed! %s\n", strerror(errno)); + regVal = TheISA::gtoh(regVal); + uint64_t realRegVal = thread->readNextPC(); + if(regVal != realRegVal) + { + DPRINTFN("%s should be %#x but is %#x.\n", + regName, regVal, realRegVal); + return false; + } + return true; +} + +void +Trace::NativeTraceRecord::dump() +{ +// ostream &outs = Trace::output(); + + //Don't print what happens for each micro-op, just print out + //once at the last op, and for regular instructions. + if(!staticInst->isMicroop() || staticInst->isLastMicroop()) + { + checkIntReg("rax", INTREG_RAX, sizeof(uint64_t)); + checkIntReg("rbx", INTREG_RBX, sizeof(uint64_t)); + checkIntReg("rcx", INTREG_RCX, sizeof(uint64_t)); + checkIntReg("rdx", INTREG_RDX, sizeof(uint64_t)); + checkIntReg("rsp", INTREG_RSP, sizeof(uint64_t)); + checkIntReg("rbp", INTREG_RBP, sizeof(uint64_t)); + checkIntReg("rsi", INTREG_RSI, sizeof(uint64_t)); + checkIntReg("rdi", INTREG_RDI, sizeof(uint64_t)); + checkIntReg("r8", INTREG_R8, sizeof(uint64_t)); + checkIntReg("r9", INTREG_R9, sizeof(uint64_t)); + checkIntReg("r10", INTREG_R10, sizeof(uint64_t)); + checkIntReg("r11", INTREG_R11, sizeof(uint64_t)); + checkIntReg("r12", INTREG_R12, sizeof(uint64_t)); + checkIntReg("r13", INTREG_R13, sizeof(uint64_t)); + checkIntReg("r14", INTREG_R14, sizeof(uint64_t)); + checkIntReg("r15", INTREG_R15, sizeof(uint64_t)); + checkPC("rip", sizeof(uint64_t)); +#if THE_ISA == SPARC_ISA + /*for(int f = 0; f <= 62; f+=2) + { + uint64_t regVal; + int res = read(fd, ®Val, sizeof(regVal)); + if(res < 0) + panic("First read call failed! %s\n", strerror(errno)); + regVal = TheISA::gtoh(regVal); + uint64_t realRegVal = thread->readFloatRegBits(f, 64); + if(regVal != realRegVal) + { + DPRINTF(ExecRegDelta, "Register f%d should be %#x but is %#x.\n", f, regVal, realRegVal); + } + }*/ + uint64_t regVal; + int res = read(fd, ®Val, sizeof(regVal)); + if(res < 0) + panic("First read call failed! %s\n", strerror(errno)); + regVal = TheISA::gtoh(regVal); + uint64_t realRegVal = thread->readNextPC(); + if(regVal != realRegVal) + { + DPRINTF(ExecRegDelta, + "Register pc should be %#x but is %#x.\n", + regVal, realRegVal); + } + res = read(fd, ®Val, sizeof(regVal)); + if(res < 0) + panic("First read call failed! %s\n", strerror(errno)); + regVal = TheISA::gtoh(regVal); + realRegVal = thread->readNextNPC(); + if(regVal != realRegVal) + { + DPRINTF(ExecRegDelta, + "Register npc should be %#x but is %#x.\n", + regVal, realRegVal); + } + res = read(fd, ®Val, sizeof(regVal)); + if(res < 0) + panic("First read call failed! %s\n", strerror(errno)); + regVal = TheISA::gtoh(regVal); + realRegVal = thread->readIntReg(SparcISA::NumIntArchRegs + 2); + if((regVal & 0xF) != (realRegVal & 0xF)) + { + DPRINTF(ExecRegDelta, + "Register ccr should be %#x but is %#x.\n", + regVal, realRegVal); + } +#endif + } +} + +/* namespace Trace */ } + +//////////////////////////////////////////////////////////////////////// +// +// ExeTracer Simulation Object +// +Trace::NativeTrace * +NativeTraceParams::create() +{ + return new Trace::NativeTrace(name); +}; diff --git a/src/cpu/nativetrace.hh b/src/cpu/nativetrace.hh new file mode 100644 index 000000000..48395792d --- /dev/null +++ b/src/cpu/nativetrace.hh @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Nathan Binkert + */ + +#ifndef __NATIVETRACE_HH__ +#define __NATIVETRACE_HH__ + +#include "base/trace.hh" +#include "cpu/static_inst.hh" +#include "sim/host.hh" +#include "sim/insttracer.hh" + +class ThreadContext; + + +namespace Trace { + +class NativeTrace; + +class NativeTraceRecord : public InstRecord +{ + protected: + NativeTrace * parent; + + bool + checkIntReg(const char * regName, int index, int size); + + bool + checkPC(const char * regName, int size); + + public: + NativeTraceRecord(NativeTrace * _parent, + Tick _when, ThreadContext *_thread, + const StaticInstPtr &_staticInst, Addr _pc, bool spec) + : InstRecord(_when, _thread, _staticInst, _pc, spec), parent(_parent) + { + } + + void dump(); +}; + +class NativeTrace : public InstTracer +{ + protected: + int fd; + + ListenSocket native_listener; + + public: + + NativeTrace(const std::string & name); + + NativeTraceRecord * + getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc) + { + if (tc->misspeculating()) + return NULL; + + return new NativeTraceRecord(this, when, tc, + staticInst, pc, tc->misspeculating()); + } + + friend class NativeTraceRecord; +}; + +/* namespace Trace */ } + +#endif // __EXETRACE_HH__ diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 01e9b5b31..d1c660258 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -1156,9 +1156,8 @@ DefaultFetch::fetch(bool &status_change) #if TRACING_ON instruction->traceData = - Trace::getInstRecord(curTick, cpu->tcBase(tid), - instruction->staticInst, - instruction->readPC()); + cpu->getTracer()->getInstRecord(curTick, cpu->tcBase(tid), + instruction->staticInst, instruction->readPC()); #else instruction->traceData = NULL; #endif diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index b2c24daad..888ef4960 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -590,6 +590,7 @@ AtomicSimpleCPUParams::create() params->simulate_stalls = simulate_stalls; params->system = system; params->cpu_id = cpu_id; + params->tracer = tracer; #if FULL_SYSTEM params->itb = itb; diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 4359ebebf..d2dd52b64 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -417,7 +417,7 @@ BaseSimpleCPU::preExecute() if(curStaticInst) { #if TRACING_ON - traceData = Trace::getInstRecord(curTick, tc, curStaticInst, + traceData = tracer->getInstRecord(curTick, tc, curStaticInst, thread->readPC()); DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n", diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 754bd8c5f..855aaab59 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -719,6 +719,7 @@ TimingSimpleCPUParams::create() params->functionTraceStart = function_trace_start; params->system = system; params->cpu_id = cpu_id; + params->tracer = tracer; #if FULL_SYSTEM params->itb = itb; diff --git a/src/sim/InstTracer.py b/src/sim/InstTracer.py new file mode 100644 index 000000000..f7500f1e8 --- /dev/null +++ b/src/sim/InstTracer.py @@ -0,0 +1,35 @@ +# Copyright (c) 2007 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black + +from m5.SimObject import SimObject +from m5.params import * + +class InstTracer(SimObject): + type = 'InstTracer' + cxx_namespace = 'Trace' + abstract = True diff --git a/src/sim/SConscript b/src/sim/SConscript index 455e5678a..6bd53e205 100644 --- a/src/sim/SConscript +++ b/src/sim/SConscript @@ -32,6 +32,7 @@ Import('*') SimObject('Root.py') SimObject('System.py') +SimObject('InstTracer.py') Source('async.cc') Source('core.cc') diff --git a/src/sim/insttracer.hh b/src/sim/insttracer.hh new file mode 100644 index 000000000..ebeae1fe9 --- /dev/null +++ b/src/sim/insttracer.hh @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2001-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Steve Reinhardt + * Nathan Binkert + */ + +#ifndef __INSTRECORD_HH__ +#define __INSTRECORD_HH__ + +#include "base/trace.hh" +#include "cpu/inst_seq.hh" // for InstSeqNum +#include "cpu/static_inst.hh" +#include "sim/host.hh" +#include "sim/sim_object.hh" + +class ThreadContext; + +namespace Trace { + +class InstRecord +{ + protected: + Tick when; + + // The following fields are initialized by the constructor and + // thus guaranteed to be valid. + ThreadContext *thread; + // need to make this ref-counted so it doesn't go away before we + // dump the record + StaticInstPtr staticInst; + Addr PC; + bool misspeculating; + + // The remaining fields are only valid for particular instruction + // types (e.g, addresses for memory ops) or when particular + // options are enabled (e.g., tracing full register contents). + // Each data field has an associated valid flag to indicate + // whether the data field is valid. + Addr addr; + bool addr_valid; + + union { + uint64_t as_int; + double as_double; + } data; + enum { + DataInvalid = 0, + DataInt8 = 1, // set to equal number of bytes + DataInt16 = 2, + DataInt32 = 4, + DataInt64 = 8, + DataDouble = 3 + } data_status; + + InstSeqNum fetch_seq; + bool fetch_seq_valid; + + InstSeqNum cp_seq; + bool cp_seq_valid; + + public: + InstRecord(Tick _when, ThreadContext *_thread, + const StaticInstPtr &_staticInst, + Addr _pc, bool spec) + : when(_when), thread(_thread), + staticInst(_staticInst), PC(_pc), + misspeculating(spec) + { + data_status = DataInvalid; + addr_valid = false; + + fetch_seq_valid = false; + cp_seq_valid = false; + } + + virtual ~InstRecord() { } + + void setAddr(Addr a) { addr = a; addr_valid = true; } + + void setData(Twin64_t d) { data.as_int = d.a; data_status = DataInt64; } + void setData(Twin32_t d) { data.as_int = d.a; data_status = DataInt32; } + void setData(uint64_t d) { data.as_int = d; data_status = DataInt64; } + void setData(uint32_t d) { data.as_int = d; data_status = DataInt32; } + void setData(uint16_t d) { data.as_int = d; data_status = DataInt16; } + void setData(uint8_t d) { data.as_int = d; data_status = DataInt8; } + + void setData(int64_t d) { setData((uint64_t)d); } + void setData(int32_t d) { setData((uint32_t)d); } + void setData(int16_t d) { setData((uint16_t)d); } + void setData(int8_t d) { setData((uint8_t)d); } + + void setData(double d) { data.as_double = d; data_status = DataDouble; } + + void setFetchSeq(InstSeqNum seq) + { fetch_seq = seq; fetch_seq_valid = true; } + + void setCPSeq(InstSeqNum seq) + { cp_seq = seq; cp_seq_valid = true; } + + virtual void dump() = 0; +}; + +class InstTracer : public SimObject +{ + public: + InstTracer(const std::string & name) : SimObject(name) + {} + + virtual ~InstTracer() + {}; + + virtual InstRecord * + getInstRecord(Tick when, ThreadContext *tc, + const StaticInstPtr staticInst, Addr pc) = 0; +}; + + + +}; // namespace Trace + +#endif // __INSTRECORD_HH__ -- cgit v1.2.3 From e996ff74978c09eda4903dc491ed5261b5def789 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 28 Jul 2007 20:33:42 -0700 Subject: X86: Fix up auxiliary vectors. The type constants should go into an architecture independent spot since they are universal to all Linux elf binaries. The right value for some of the vectors needs to be determined. Also, x86 does not store argc or argv_array_base in registers like some other architectures. --HG-- extra : convert_revision : 8d3f6a3e028d881d3c41e8ddf4f29d25738b529c --- src/arch/x86/process.cc | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc index 09962fdb6..713e5d0a2 100644 --- a/src/arch/x86/process.cc +++ b/src/arch/x86/process.cc @@ -187,7 +187,14 @@ X86LiveProcess::argsInit(int intSize, int pageSize) X86_AT_UID = 11, X86_AT_EUID = 12, X86_AT_GID = 13, - X86_AT_EGID = 14 + X86_AT_EGID = 14, + X86_AT_PLATFORM = 15, + X86_AT_HWCAP = 16, + X86_AT_CLKTCK = 17, + + X86_AT_SECURE = 13, + + X86_AT_VECTOR_SIZE = 44 }; //Setup the auxilliary vectors. These will already have endian conversion. @@ -195,36 +202,39 @@ X86LiveProcess::argsInit(int intSize, int pageSize) ElfObject * elfObject = dynamic_cast(objFile); if(elfObject) { - /* //Bits which describe the system hardware capabilities - auxv.push_back(auxv_t(SPARC_AT_HWCAP, hwcap)); + //XXX Figure out what these should be + auxv.push_back(auxv_t(X86_AT_HWCAP, 0)); //The system page size - auxv.push_back(auxv_t(SPARC_AT_PAGESZ, SparcISA::VMPageSize)); - //Defined to be 100 in the kernel source. + auxv.push_back(auxv_t(X86_AT_PAGESZ, X86ISA::VMPageSize)); //Frequency at which times() increments - auxv.push_back(auxv_t(SPARC_AT_CLKTCK, 100)); + auxv.push_back(auxv_t(X86_AT_CLKTCK, 100)); // For statically linked executables, this is the virtual address of the // program header tables if they appear in the executable image - auxv.push_back(auxv_t(SPARC_AT_PHDR, elfObject->programHeaderTable())); + auxv.push_back(auxv_t(X86_AT_PHDR, elfObject->programHeaderTable())); // This is the size of a program header entry from the elf file. - auxv.push_back(auxv_t(SPARC_AT_PHENT, elfObject->programHeaderSize())); + auxv.push_back(auxv_t(X86_AT_PHENT, elfObject->programHeaderSize())); // This is the number of program headers from the original elf file. - auxv.push_back(auxv_t(SPARC_AT_PHNUM, elfObject->programHeaderCount())); + auxv.push_back(auxv_t(X86_AT_PHNUM, elfObject->programHeaderCount())); + //Defined to be 100 in the kernel source. //This is the address of the elf "interpreter", It should be set //to 0 for regular executables. It should be something else //(not sure what) for dynamic libraries. - auxv.push_back(auxv_t(SPARC_AT_BASE, 0)); - //This is hardwired to 0 in the elf loading code in the kernel - auxv.push_back(auxv_t(SPARC_AT_FLAGS, 0)); + auxv.push_back(auxv_t(X86_AT_BASE, 0)); + + //XXX Figure out what this should be. + auxv.push_back(auxv_t(X86_AT_FLAGS, 0)); //The entry point to the program - auxv.push_back(auxv_t(SPARC_AT_ENTRY, objFile->entryPoint())); + auxv.push_back(auxv_t(X86_AT_ENTRY, objFile->entryPoint())); //Different user and group IDs - auxv.push_back(auxv_t(SPARC_AT_UID, uid())); - auxv.push_back(auxv_t(SPARC_AT_EUID, euid())); - auxv.push_back(auxv_t(SPARC_AT_GID, gid())); - auxv.push_back(auxv_t(SPARC_AT_EGID, egid())); + auxv.push_back(auxv_t(X86_AT_UID, uid())); + auxv.push_back(auxv_t(X86_AT_EUID, euid())); + auxv.push_back(auxv_t(X86_AT_GID, gid())); + auxv.push_back(auxv_t(X86_AT_EGID, egid())); //Whether to enable "secure mode" in the executable - auxv.push_back(auxv_t(SPARC_AT_SECURE, 0));*/ + auxv.push_back(auxv_t(X86_AT_SECURE, 0)); + //The string "x86_64" with unknown meaning + auxv.push_back(auxv_t(X86_AT_PLATFORM, 0)); } //Figure out how big the initial stack needs to be @@ -338,9 +348,6 @@ X86LiveProcess::argsInit(int intSize, int pageSize) initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize); //Set up the thread context to start running the process - assert(NumArgumentRegs >= 2); - threadContexts[0]->setIntReg(ArgumentReg[0], argc); - threadContexts[0]->setIntReg(ArgumentReg[1], argv_array_base); threadContexts[0]->setIntReg(StackPointerReg, stack_min); Addr prog_entry = objFile->entryPoint(); -- cgit v1.2.3 From dc86f3229c2d3278bf5f32fb9b0b4bf039c0735e Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 28 Jul 2007 21:18:53 -0700 Subject: X86: Fix a comment and adjust the stack base address. The stack base on my development machine starts one page below where it needs to. I don't know why it does, but I've duplicated it in m5. --HG-- extra : convert_revision : c4783ba885b90f17e843f61e07af0bc3330a74bc --- src/arch/x86/process.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc index 713e5d0a2..ff23be339 100644 --- a/src/arch/x86/process.cc +++ b/src/arch/x86/process.cc @@ -122,9 +122,10 @@ X86LiveProcess::X86LiveProcess(const std::string &nm, ObjectFile *objFile, // Set pointer for next thread stack. Reserve 8M for main stack. next_thread_stack_base = stack_base - (8 * 1024 * 1024); - // Set up stack. On SPARC Linux, stack goes from the top of memory - // downward, less the hole for the kernel address space. - stack_base = (Addr)0x80000000000ULL; + // Set up stack. On X86_64 Linux, stack goes from the top of memory + // downward, less the hole for the kernel address space plus one page + // for undertermined purposes. + stack_base = (Addr)0x7FFFFFFF000ULL; // Set up region for mmaps. Tru64 seems to start just above 0 and // grow up from there. -- cgit v1.2.3 From 3dcd848ec340e96f374ee9859bf4f8906fb577cc Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 29 Jul 2007 01:24:57 -0700 Subject: X86: Fix a bug with merge Merge was returning the value to merge in, not the actual result of the merge. --HG-- extra : convert_revision : 230b4b5064037d099ae7859edabdf5be84603849 --- src/arch/x86/insts/static_inst.hh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/arch/x86/insts/static_inst.hh b/src/arch/x86/insts/static_inst.hh index c39c2956e..f42e6693d 100644 --- a/src/arch/x86/insts/static_inst.hh +++ b/src/arch/x86/insts/static_inst.hh @@ -58,6 +58,7 @@ #ifndef __ARCH_X86_INSTS_STATICINST_HH__ #define __ARCH_X86_INSTS_STATICINST_HH__ +#include "base/trace.hh" #include "cpu/static_inst.hh" namespace X86ISA @@ -113,7 +114,7 @@ namespace X86ISA default: panic("Tried to merge with unrecognized size %d.\n", size); } - return val; + return reg; } inline uint64_t pick(uint64_t from, int size) -- cgit v1.2.3 From d99557534217dc59e33ca70591b52d9d9e8322a8 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 29 Jul 2007 01:26:47 -0700 Subject: X86: Fix popa and push with the stack pointer. POPA used st instead of ld, and it didn't skip rsp. push rsp needs to store the -original- value of the stack pointer. --HG-- extra : convert_revision : 376370c99b6ab60fb2bc4cd4f0a6dce71153ad06 --- .../x86/isa/insts/data_transfer/stack_operations.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/arch/x86/isa/insts/data_transfer/stack_operations.py b/src/arch/x86/isa/insts/data_transfer/stack_operations.py index 889e7b88b..1c13b44b4 100644 --- a/src/arch/x86/isa/insts/data_transfer/stack_operations.py +++ b/src/arch/x86/isa/insts/data_transfer/stack_operations.py @@ -85,8 +85,10 @@ def macroop PUSH_R { # Make the default data size of pops 64 bits in 64 bit mode .adjust_env oszIn64Override + # This needs to work slightly differently from the other versions of push + # because the -original- version of the stack pointer is what gets pushed + st reg, ss, [0, t0, rsp], "-env.dataSize" subi rsp, rsp, dsz - st reg, ss, [0, t0, rsp] }; def macroop PUSH_I { @@ -130,14 +132,13 @@ def macroop PUSHA { }; def macroop POPA { - st rdi, ss, [0, t0, rsp], "0 * env.dataSize" - st rsi, ss, [0, t0, rsp], "1 * env.dataSize" - st rbp, ss, [0, t0, rsp], "2 * env.dataSize" - st rsp, ss, [0, t0, rsp], "3 * env.dataSize" - st rbx, ss, [0, t0, rsp], "4 * env.dataSize" - st rdx, ss, [0, t0, rsp], "5 * env.dataSize" - st rcx, ss, [0, t0, rsp], "6 * env.dataSize" - st rax, ss, [0, t0, rsp], "7 * env.dataSize" + ld rdi, ss, [0, t0, rsp], "0 * env.dataSize" + ld rsi, ss, [0, t0, rsp], "1 * env.dataSize" + ld rbp, ss, [0, t0, rsp], "2 * env.dataSize" + ld rbx, ss, [0, t0, rsp], "4 * env.dataSize" + ld rdx, ss, [0, t0, rsp], "5 * env.dataSize" + ld rcx, ss, [0, t0, rsp], "6 * env.dataSize" + ld rax, ss, [0, t0, rsp], "7 * env.dataSize" addi rsp, rsp, "8 * env.dataSize" }; ''' -- cgit v1.2.3 From 33847f8c83f8ac3c85c1388b5b69aacbc5163564 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 29 Jul 2007 01:27:34 -0700 Subject: X86: return -return_value.value() on failure. --HG-- extra : convert_revision : d8e1486ff075b2917be62a0008f83fd6c9e4c09a --- src/arch/x86/syscallreturn.hh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/arch/x86/syscallreturn.hh b/src/arch/x86/syscallreturn.hh index 6a7fdba58..be9715d21 100644 --- a/src/arch/x86/syscallreturn.hh +++ b/src/arch/x86/syscallreturn.hh @@ -67,7 +67,11 @@ namespace X86ISA static inline void setSyscallReturn(SyscallReturn return_value, ThreadContext * tc) { - tc->setIntReg(INTREG_RAX, return_value.value()); + if (return_value.successful()) { + tc->setIntReg(INTREG_RAX, return_value.value()); + } else { + tc->setIntReg(INTREG_RAX, -return_value.value()); + } } }; -- cgit v1.2.3 From b6395da4cea2d12f27ae52517675dfdf507d4a92 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 29 Jul 2007 01:28:36 -0700 Subject: X86: Fix register ordering. The correct order is unintuitively rax, rcx, rdx, rbx, etc, not rax, rbx, rcx, rdx. --HG-- extra : convert_revision : 3abe6a723a6e30becfe34f8da707ea2ff5d4df77 --- src/cpu/nativetrace.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cpu/nativetrace.cc b/src/cpu/nativetrace.cc index 57304c79b..90a0e1a62 100644 --- a/src/cpu/nativetrace.cc +++ b/src/cpu/nativetrace.cc @@ -107,9 +107,9 @@ Trace::NativeTraceRecord::dump() if(!staticInst->isMicroop() || staticInst->isLastMicroop()) { checkIntReg("rax", INTREG_RAX, sizeof(uint64_t)); - checkIntReg("rbx", INTREG_RBX, sizeof(uint64_t)); checkIntReg("rcx", INTREG_RCX, sizeof(uint64_t)); checkIntReg("rdx", INTREG_RDX, sizeof(uint64_t)); + checkIntReg("rbx", INTREG_RBX, sizeof(uint64_t)); checkIntReg("rsp", INTREG_RSP, sizeof(uint64_t)); checkIntReg("rbp", INTREG_RBP, sizeof(uint64_t)); checkIntReg("rsi", INTREG_RSI, sizeof(uint64_t)); -- cgit v1.2.3 From e5f58903651299d8cbba793423d953e750eb16f4 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 29 Jul 2007 01:30:28 -0700 Subject: X86: Make limm use merge and allow overriding the data size. --HG-- extra : convert_revision : c6057226b8ff8f272612a9d3bf7d1d9ba90c819b --- src/arch/x86/isa/microops/limmop.isa | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/arch/x86/isa/microops/limmop.isa b/src/arch/x86/isa/microops/limmop.isa index 37180d7fa..ec68c36dc 100644 --- a/src/arch/x86/isa/microops/limmop.isa +++ b/src/arch/x86/isa/microops/limmop.isa @@ -142,12 +142,12 @@ def template MicroLimmOpConstructor {{ let {{ class LimmOp(X86Microop): - def __init__(self, dest, imm): + def __init__(self, dest, imm, dataSize="env.dataSize"): self.className = "Limm" self.mnemonic = "limm" self.dest = dest self.imm = imm - self.dataSize = "env.dataSize" + self.dataSize = dataSize def getAllocator(self, *microFlags): allocator = '''new %(class_name)s(machInst, mnemonic @@ -165,7 +165,7 @@ let {{ let {{ # Build up the all register version of this micro op iop = InstObjParams("limm", "Limm", 'X86MicroopBase', - {"code" : "DestReg = imm;"}) + {"code" : "DestReg = merge(DestReg, imm, dataSize);"}) header_output += MicroLimmOpDeclare.subst(iop) decoder_output += MicroLimmOpConstructor.subst(iop) decoder_output += MicroLimmOpDisassembly.subst(iop) -- cgit v1.2.3 From 5e34c62b3b3f54c826730841029a875607824c42 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 29 Jul 2007 01:33:06 -0700 Subject: X86: Initial stack frame fixes and constant shuffling. The initial stack frame for x86 is now substantially more correct. The fixes made here can be back ported to SPARC and possible the other ISAs as well. The auxiliary vector types were moved to the LiveProcess base class because they are independent of ISA. Some of the types may only apply to Linux, though, so they may have to be moved. --HG-- extra : convert_revision : 89ace35fcc8eb9586d2fee8eeccbc3686499ef24 --- src/arch/sparc/process.cc | 47 ++++--------- src/arch/x86/process.cc | 167 ++++++++++++++++++++++++++++++++-------------- src/sim/process.hh | 26 ++++++++ 3 files changed, 158 insertions(+), 82 deletions(-) (limited to 'src') diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc index bc950301a..41a1c2136 100644 --- a/src/arch/sparc/process.cc +++ b/src/arch/sparc/process.cc @@ -194,25 +194,6 @@ Sparc64LiveProcess::argsInit(int intSize, int pageSize) // load object file into target memory objFile->loadSections(initVirtMem); - //These are the auxilliary vector types - enum auxTypes - { - SPARC_AT_HWCAP = 16, - SPARC_AT_PAGESZ = 6, - SPARC_AT_CLKTCK = 17, - SPARC_AT_PHDR = 3, - SPARC_AT_PHENT = 4, - SPARC_AT_PHNUM = 5, - SPARC_AT_BASE = 7, - SPARC_AT_FLAGS = 8, - SPARC_AT_ENTRY = 9, - SPARC_AT_UID = 11, - SPARC_AT_EUID = 12, - SPARC_AT_GID = 13, - SPARC_AT_EGID = 14, - SPARC_AT_SECURE = 23 - }; - enum hardwareCaps { M5_HWCAP_SPARC_FLUSH = 1, @@ -241,34 +222,34 @@ Sparc64LiveProcess::argsInit(int intSize, int pageSize) if(elfObject) { //Bits which describe the system hardware capabilities - auxv.push_back(auxv_t(SPARC_AT_HWCAP, hwcap)); + auxv.push_back(auxv_t(M5_AT_HWCAP, hwcap)); //The system page size - auxv.push_back(auxv_t(SPARC_AT_PAGESZ, SparcISA::VMPageSize)); + auxv.push_back(auxv_t(M5_AT_PAGESZ, SparcISA::VMPageSize)); //Defined to be 100 in the kernel source. //Frequency at which times() increments - auxv.push_back(auxv_t(SPARC_AT_CLKTCK, 100)); + auxv.push_back(auxv_t(M5_AT_CLKTCK, 100)); // For statically linked executables, this is the virtual address of the // program header tables if they appear in the executable image - auxv.push_back(auxv_t(SPARC_AT_PHDR, elfObject->programHeaderTable())); + auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable())); // This is the size of a program header entry from the elf file. - auxv.push_back(auxv_t(SPARC_AT_PHENT, elfObject->programHeaderSize())); + auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize())); // This is the number of program headers from the original elf file. - auxv.push_back(auxv_t(SPARC_AT_PHNUM, elfObject->programHeaderCount())); + auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount())); //This is the address of the elf "interpreter", It should be set //to 0 for regular executables. It should be something else //(not sure what) for dynamic libraries. - auxv.push_back(auxv_t(SPARC_AT_BASE, 0)); + auxv.push_back(auxv_t(M5_AT_BASE, 0)); //This is hardwired to 0 in the elf loading code in the kernel - auxv.push_back(auxv_t(SPARC_AT_FLAGS, 0)); + auxv.push_back(auxv_t(M5_AT_FLAGS, 0)); //The entry point to the program - auxv.push_back(auxv_t(SPARC_AT_ENTRY, objFile->entryPoint())); + auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint())); //Different user and group IDs - auxv.push_back(auxv_t(SPARC_AT_UID, uid())); - auxv.push_back(auxv_t(SPARC_AT_EUID, euid())); - auxv.push_back(auxv_t(SPARC_AT_GID, gid())); - auxv.push_back(auxv_t(SPARC_AT_EGID, egid())); + auxv.push_back(auxv_t(M5_AT_UID, uid())); + auxv.push_back(auxv_t(M5_AT_EUID, euid())); + auxv.push_back(auxv_t(M5_AT_GID, gid())); + auxv.push_back(auxv_t(M5_AT_EGID, egid())); //Whether to enable "secure mode" in the executable - auxv.push_back(auxv_t(SPARC_AT_SECURE, 0)); + auxv.push_back(auxv_t(M5_AT_SECURE, 0)); } //Figure out how big the initial stack needs to be diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc index ff23be339..6d30e53e3 100644 --- a/src/arch/x86/process.cc +++ b/src/arch/x86/process.cc @@ -125,7 +125,7 @@ X86LiveProcess::X86LiveProcess(const std::string &nm, ObjectFile *objFile, // Set up stack. On X86_64 Linux, stack goes from the top of memory // downward, less the hole for the kernel address space plus one page // for undertermined purposes. - stack_base = (Addr)0x7FFFFFFF000ULL; + stack_base = (Addr)0x7FFFFFFFF000ULL; // Set up region for mmaps. Tru64 seems to start just above 0 and // grow up from there. @@ -166,36 +166,49 @@ X86LiveProcess::argsInit(int intSize, int pageSize) else filename = argv[0]; - Addr alignmentMask = ~(intSize - 1); + //We want 16 byte alignment + Addr alignmentMask = ~mask(4); // load object file into target memory objFile->loadSections(initVirtMem); - //These are the auxilliary vector types - enum auxTypes - { - X86_AT_NULL = 0, - X86_AT_IGNORE = 1, - X86_AT_EXECFD = 2, - X86_AT_PHDR = 3, - X86_AT_PHENT = 4, - X86_AT_PHNUM = 5, - X86_AT_PAGESZ = 6, - X86_AT_BASE = 7, - X86_AT_FLAGS = 8, - X86_AT_ENTRY = 9, - X86_AT_NOTELF = 10, - X86_AT_UID = 11, - X86_AT_EUID = 12, - X86_AT_GID = 13, - X86_AT_EGID = 14, - X86_AT_PLATFORM = 15, - X86_AT_HWCAP = 16, - X86_AT_CLKTCK = 17, - - X86_AT_SECURE = 13, - - X86_AT_VECTOR_SIZE = 44 + enum X86CpuFeature { + X86_OnboardFPU = 1 << 0, + X86_VirtualModeExtensions = 1 << 1, + X86_DebuggingExtensions = 1 << 2, + X86_PageSizeExtensions = 1 << 3, + + X86_TimeStampCounter = 1 << 4, + X86_ModelSpecificRegisters = 1 << 5, + X86_PhysicalAddressExtensions = 1 << 6, + X86_MachineCheckExtensions = 1 << 7, + + X86_CMPXCHG8Instruction = 1 << 8, + X86_OnboardAPIC = 1 << 9, + X86_SYSENTER_SYSEXIT = 1 << 11, + + X86_MemoryTypeRangeRegisters = 1 << 12, + X86_PageGlobalEnable = 1 << 13, + X86_MachineCheckArchitecture = 1 << 14, + X86_CMOVInstruction = 1 << 15, + + X86_PageAttributeTable = 1 << 16, + X86_36BitPSEs = 1 << 17, + X86_ProcessorSerialNumber = 1 << 18, + X86_CLFLUSHInstruction = 1 << 19, + + X86_DebugTraceStore = 1 << 21, + X86_ACPIViaMSR = 1 << 22, + X86_MultimediaExtensions = 1 << 23, + + X86_FXSAVE_FXRSTOR = 1 << 24, + X86_StreamingSIMDExtensions = 1 << 25, + X86_StreamingSIMDExtensions2 = 1 << 26, + X86_CPUSelfSnoop = 1 << 27, + + X86_HyperThreading = 1 << 28, + X86_AutomaticClockControl = 1 << 29, + X86_IA64Processor = 1 << 30 }; //Setup the auxilliary vectors. These will already have endian conversion. @@ -203,39 +216,71 @@ X86LiveProcess::argsInit(int intSize, int pageSize) ElfObject * elfObject = dynamic_cast(objFile); if(elfObject) { + uint64_t features = + X86_OnboardFPU | + X86_VirtualModeExtensions | + X86_DebuggingExtensions | + X86_PageSizeExtensions | + X86_TimeStampCounter | + X86_ModelSpecificRegisters | + X86_PhysicalAddressExtensions | + X86_MachineCheckExtensions | + X86_CMPXCHG8Instruction | + X86_OnboardAPIC | + X86_SYSENTER_SYSEXIT | + X86_MemoryTypeRangeRegisters | + X86_PageGlobalEnable | + X86_MachineCheckArchitecture | + X86_CMOVInstruction | + X86_PageAttributeTable | + X86_36BitPSEs | +// X86_ProcessorSerialNumber | + X86_CLFLUSHInstruction | +// X86_DebugTraceStore | +// X86_ACPIViaMSR | + X86_MultimediaExtensions | + X86_FXSAVE_FXRSTOR | + X86_StreamingSIMDExtensions | + X86_StreamingSIMDExtensions2 | +// X86_CPUSelfSnoop | +// X86_HyperThreading | +// X86_AutomaticClockControl | +// X86_IA64Processor | + 0; + //Bits which describe the system hardware capabilities //XXX Figure out what these should be - auxv.push_back(auxv_t(X86_AT_HWCAP, 0)); + auxv.push_back(auxv_t(M5_AT_HWCAP, features)); //The system page size - auxv.push_back(auxv_t(X86_AT_PAGESZ, X86ISA::VMPageSize)); + auxv.push_back(auxv_t(M5_AT_PAGESZ, X86ISA::VMPageSize)); //Frequency at which times() increments - auxv.push_back(auxv_t(X86_AT_CLKTCK, 100)); + auxv.push_back(auxv_t(M5_AT_CLKTCK, 100)); // For statically linked executables, this is the virtual address of the // program header tables if they appear in the executable image - auxv.push_back(auxv_t(X86_AT_PHDR, elfObject->programHeaderTable())); + auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable())); // This is the size of a program header entry from the elf file. - auxv.push_back(auxv_t(X86_AT_PHENT, elfObject->programHeaderSize())); + auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize())); // This is the number of program headers from the original elf file. - auxv.push_back(auxv_t(X86_AT_PHNUM, elfObject->programHeaderCount())); + auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount())); //Defined to be 100 in the kernel source. //This is the address of the elf "interpreter", It should be set //to 0 for regular executables. It should be something else //(not sure what) for dynamic libraries. - auxv.push_back(auxv_t(X86_AT_BASE, 0)); + auxv.push_back(auxv_t(M5_AT_BASE, 0)); //XXX Figure out what this should be. - auxv.push_back(auxv_t(X86_AT_FLAGS, 0)); + auxv.push_back(auxv_t(M5_AT_FLAGS, 0)); //The entry point to the program - auxv.push_back(auxv_t(X86_AT_ENTRY, objFile->entryPoint())); + auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint())); //Different user and group IDs - auxv.push_back(auxv_t(X86_AT_UID, uid())); - auxv.push_back(auxv_t(X86_AT_EUID, euid())); - auxv.push_back(auxv_t(X86_AT_GID, gid())); - auxv.push_back(auxv_t(X86_AT_EGID, egid())); + auxv.push_back(auxv_t(M5_AT_UID, uid())); + auxv.push_back(auxv_t(M5_AT_EUID, euid())); + auxv.push_back(auxv_t(M5_AT_GID, gid())); + auxv.push_back(auxv_t(M5_AT_EGID, egid())); //Whether to enable "secure mode" in the executable - auxv.push_back(auxv_t(X86_AT_SECURE, 0)); + auxv.push_back(auxv_t(M5_AT_SECURE, 0)); //The string "x86_64" with unknown meaning - auxv.push_back(auxv_t(X86_AT_PLATFORM, 0)); + auxv.push_back(auxv_t(M5_AT_PLATFORM, 0)); } //Figure out how big the initial stack needs to be @@ -245,29 +290,39 @@ X86LiveProcess::argsInit(int intSize, int pageSize) //This is the name of the file which is present on the initial stack //It's purpose is to let the user space linker examine the original file. - int file_name_size = filename.size() + 1; + int file_name_size = filename.size(); + + string platform = "x86_64"; + int aux_data_size = platform.size() + 1; int env_data_size = 0; for (int i = 0; i < envp.size(); ++i) { - env_data_size += envp[i].size() + 1; + env_data_size += envp[i].size(); } int arg_data_size = 0; for (int i = 0; i < argv.size(); ++i) { - arg_data_size += argv[i].size() + 1; + arg_data_size += argv[i].size(); } + //The auxiliary vector data needs to be padded so it's size is a multiple + //of the alignment mask. + int aux_padding = + ((aux_data_size + ~alignmentMask) & alignmentMask) - aux_data_size; + //The info_block needs to be padded so it's size is a multiple of the //alignment mask. Also, it appears that there needs to be at least some //padding, so if the size is already a multiple, we need to increase it //anyway. int info_block_size = - (file_name_size + + (mysterious_size + + file_name_size + env_data_size + arg_data_size + - intSize) & alignmentMask; + ~alignmentMask) & alignmentMask; int info_block_padding = info_block_size - + mysterious_size - file_name_size - env_data_size - arg_data_size; @@ -281,8 +336,9 @@ X86LiveProcess::argsInit(int intSize, int pageSize) int argc_size = intSize; int space_needed = - mysterious_size + info_block_size + + aux_data_size + + aux_padding + aux_array_size + envp_array_size + argv_array_size + @@ -301,7 +357,8 @@ X86LiveProcess::argsInit(int intSize, int pageSize) Addr file_name_base = mysterious_base - file_name_size; Addr env_data_base = file_name_base - env_data_size; Addr arg_data_base = env_data_base - arg_data_size; - Addr auxv_array_base = arg_data_base - aux_array_size - info_block_padding; + Addr aux_data_base = arg_data_base - aux_data_size - info_block_padding; + Addr auxv_array_base = aux_data_base - aux_array_size - aux_padding; Addr envp_array_base = auxv_array_base - envp_array_size; Addr argv_array_base = envp_array_base - argv_array_size; Addr argc_base = argv_array_base - argc_size; @@ -310,6 +367,7 @@ X86LiveProcess::argsInit(int intSize, int pageSize) DPRINTF(X86, "0x%x - file name\n", file_name_base); DPRINTF(X86, "0x%x - env data\n", env_data_base); DPRINTF(X86, "0x%x - arg data\n", arg_data_base); + DPRINTF(X86, "0x%x - aux data\n", aux_data_base); DPRINTF(X86, "0x%x - auxv array\n", auxv_array_base); DPRINTF(X86, "0x%x - envp array\n", envp_array_base); DPRINTF(X86, "0x%x - argv array\n", argv_array_base); @@ -330,6 +388,10 @@ X86LiveProcess::argsInit(int intSize, int pageSize) //Write the file name initVirtMem->writeString(file_name_base, filename.c_str()); + //Fix up the aux vector which points to the "platform" string + assert(auxv[auxv.size() - 1].a_type = M5_AT_PLATFORM); + auxv[auxv.size() - 1].a_val = aux_data_base; + //Copy the aux stuff for(int x = 0; x < auxv.size(); x++) { @@ -343,12 +405,19 @@ X86LiveProcess::argsInit(int intSize, int pageSize) initVirtMem->writeBlob(auxv_array_base + 2 * intSize * auxv.size(), (uint8_t*)&zero, 2 * intSize); + initVirtMem->writeString(aux_data_base, platform.c_str()); + copyStringArray(envp, envp_array_base, env_data_base, initVirtMem); copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem); initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize); //Set up the thread context to start running the process + //Because of the peculiarities of how syscall works, I believe + //a process starts with r11 containing the value of eflags or maybe r11 + //from before the call to execve. Empirically this value is 0x200. + threadContexts[0]->setIntReg(INTREG_R11, 0x200); + //Set the stack pointer register threadContexts[0]->setIntReg(StackPointerReg, stack_min); Addr prog_entry = objFile->entryPoint(); diff --git a/src/sim/process.hh b/src/sim/process.hh index fa46b9c95..8c702da60 100644 --- a/src/sim/process.hh +++ b/src/sim/process.hh @@ -214,6 +214,32 @@ class LiveProcess : public Process public: + enum AuxiliaryVectorType { + M5_AT_NULL = 0, + M5_AT_IGNORE = 1, + M5_AT_EXECFD = 2, + M5_AT_PHDR = 3, + M5_AT_PHENT = 4, + M5_AT_PHNUM = 5, + M5_AT_PAGESZ = 6, + M5_AT_BASE = 7, + M5_AT_FLAGS = 8, + M5_AT_ENTRY = 9, + M5_AT_NOTELF = 10, + M5_AT_UID = 11, + M5_AT_EUID = 12, + M5_AT_GID = 13, + M5_AT_EGID = 14, + // The following may be specific to Linux + M5_AT_PLATFORM = 15, + M5_AT_HWCAP = 16, + M5_AT_CLKTCK = 17, + + M5_AT_SECURE = 23, + + M5_AT_VECTOR_SIZE = 44 + }; + inline uint64_t uid() {return __uid;} inline uint64_t euid() {return __euid;} inline uint64_t gid() {return __gid;} -- cgit v1.2.3 From 362ff1bcebd78c0c247e435eac657c8a1134b1fb Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Sun, 29 Jul 2007 13:22:44 -0700 Subject: BsaeCPU: Get rid of some bad DPRINTFs. People should never put pointers in DPRINTFs; it messes up tracediffs. Plus these used the FullCPU trace flag, which is not right. --HG-- extra : convert_revision : 82ed56757da0ad947c165ba205b5f752c85c6667 --- src/cpu/base.cc | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 0fc3b4cea..6c8bf65fa 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -106,14 +106,10 @@ BaseCPU::BaseCPU(Params *p) #endif { // currentTick = curTick; - DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); // add self to global list of CPUs cpuList.push_back(this); - DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", - this); - if (number_of_threads > maxThreadsPerCPU) maxThreadsPerCPU = number_of_threads; -- cgit v1.2.3