diff options
author | Korey Sewell <ksewell@umich.edu> | 2009-07-31 10:40:42 -0400 |
---|---|---|
committer | Korey Sewell <ksewell@umich.edu> | 2009-07-31 10:40:42 -0400 |
commit | aa75b9a7a7489bf86c4e6d406ff612e596ddff96 (patch) | |
tree | 58a6816583a21c19c181e32bff10bf74aa9ad15f | |
parent | 60063cc700912666fa8b7968d692d00a1e82cb67 (diff) | |
parent | 3dd3de5feb31055a48acb39575da25a9cea2626d (diff) | |
download | gem5-aa75b9a7a7489bf86c4e6d406ff612e596ddff96.tar.xz |
merge mips fix and statetrace changes
31 files changed, 1076 insertions, 128 deletions
diff --git a/src/arch/arm/ArmNativeTrace.py b/src/arch/arm/ArmNativeTrace.py new file mode 100644 index 000000000..0a76913e3 --- /dev/null +++ b/src/arch/arm/ArmNativeTrace.py @@ -0,0 +1,37 @@ +# Copyright (c) 2009 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 NativeTrace import NativeTrace + +class ArmNativeTrace(NativeTrace): + type = 'ArmNativeTrace' + cxx_class = 'Trace::ArmNativeTrace' + stop_on_pc_error = Param.Bool(True, + "Stop M5 if it and statetrace's pcs are different") diff --git a/src/arch/arm/SConscript b/src/arch/arm/SConscript index 519435489..55ecabdc3 100644 --- a/src/arch/arm/SConscript +++ b/src/arch/arm/SConscript @@ -39,11 +39,14 @@ if env['TARGET_ISA'] == 'arm': Source('insts/mem.cc') Source('insts/pred_inst.cc') Source('insts/static_inst.cc') + Source('nativetrace.cc') Source('pagetable.cc') Source('tlb.cc') Source('vtophys.cc') + SimObject('ArmNativeTrace.py') SimObject('ArmTLB.py') + TraceFlag('Arm') if env['FULL_SYSTEM']: diff --git a/src/arch/arm/isa.hh b/src/arch/arm/isa.hh index 39acc9c08..2315afa9e 100644 --- a/src/arch/arm/isa.hh +++ b/src/arch/arm/isa.hh @@ -48,7 +48,11 @@ namespace ArmISA public: void clear() { - // Unknown startup state currently + memset(miscRegs, 0, sizeof(miscRegs)); + CPSR cpsr = 0; + cpsr.mode = MODE_USER; + miscRegs[MISCREG_CPSR] = cpsr; + //XXX We need to initialize the rest of the state. } MiscReg diff --git a/src/arch/arm/isa/decoder.isa b/src/arch/arm/isa/decoder.isa index 76d584858..a999b52e9 100644 --- a/src/arch/arm/isa/decoder.isa +++ b/src/arch/arm/isa/decoder.isa @@ -113,8 +113,7 @@ format DataOp { 0x1: decode OPCODE { 0x9: BranchExchange::bx({{ }}); 0xb: PredOp::clz({{ - unsigned lsb = findLsbSet(Rm); - Rd = (lsb > 31) ? 32 : lsb; + Rd = ((Rm == 0) ? 32 : (31 - findMsbSet(Rm))); }}); } 0x2: decode OPCODE { @@ -319,6 +318,10 @@ format DataOp { 0x12,0x16,0x1a,0x1e: ArmMacroFMOp::sfm_pw({{ }}); 0x13,0x17,0x1b,0x1f: ArmMacroFMOp::lfm_pw({{ }}); } + 0xb: decode LOADOP { + 0x0: WarnUnimpl::fstmx(); + 0x1: WarnUnimpl::fldmx(); + } } 0x7: decode OPCODE_24 { 0: decode CPNUM { @@ -417,12 +420,29 @@ format DataOp { } } } + 0xa: decode MISC_OPCODE { + 0x1: decode MEDIA_OPCODE { + 0xf: decode RN { + 0x0: FloatOp::fmrx_fpsid({{ Rd = Fpsid; }}); + 0x1: FloatOp::fmrx_fpscr({{ Rd = Fpscr; }}); + 0x8: FloatOp::fmrx_fpexc({{ Rd = Fpexc; }}); + } + 0xe: decode RN { + 0x0: FloatOp::fmxr_fpsid({{ Fpsid = Rd; }}); + 0x1: FloatOp::fmxr_fpscr({{ Fpscr = Rd; }}); + 0x8: FloatOp::fmxr_fpexc({{ Fpexc = Rd; }}); + } + } + } } format PredOp { // ARM System Call (SoftWare Interrupt) 1: swi({{ if (testPredicate(Cpsr, condCode)) { - xc->syscall(IMMED_23_0); + if (IMMED_23_0) + xc->syscall(IMMED_23_0); + else + xc->syscall(R7); } }}); } diff --git a/src/arch/arm/isa/formats/pred.isa b/src/arch/arm/isa/formats/pred.isa index 50e162f3d..e90788c91 100644 --- a/src/arch/arm/isa/formats/pred.isa +++ b/src/arch/arm/isa/formats/pred.isa @@ -105,7 +105,8 @@ let {{ def getCcCode(flagtype): icReg = icImm = iv = '' if flagtype == "none": - icReg = icImm = iv = '1' + icReg = icImm = 'Cpsr<29:>' + iv = 'Cpsr<28:>' elif flagtype == "add": icReg = icImm = 'findCarry(32, resTemp, Rn, op2)' iv = 'findOverflow(32, resTemp, Rn, op2)' @@ -125,7 +126,8 @@ let {{ def getImmCcCode(flagtype): ivValue = icValue = '' if flagtype == "none": - icValue = ivValue = '1' + icValue = 'Cpsr<29:>' + ivValue = 'Cpsr<28:>' elif flagtype == "add": icValue = 'findCarry(32, resTemp, Rn, rotated_imm)' ivValue = 'findOverflow(32, resTemp, Rn, rotated_imm)' diff --git a/src/arch/arm/isa/operands.isa b/src/arch/arm/isa/operands.isa index fa41918c1..ac7427dad 100644 --- a/src/arch/arm/isa/operands.isa +++ b/src/arch/arm/isa/operands.isa @@ -57,6 +57,7 @@ def operands {{ 'Rm': ('IntReg', 'uw', 'RM', 'IsInteger', 2, maybePCRead, maybePCWrite), 'Rs': ('IntReg', 'uw', 'RS', 'IsInteger', 3, maybePCRead, maybePCWrite), 'Rn': ('IntReg', 'uw', 'RN', 'IsInteger', 4, maybePCRead, maybePCWrite), + 'R7': ('IntReg', 'uw', '7', 'IsInteger', 5), #Destination register for load/store double instructions 'Rdo': ('IntReg', 'uw', '(RD & ~1)', 'IsInteger', 4, maybePCRead, maybePCWrite), @@ -81,7 +82,10 @@ def operands {{ 'Cpsr': ('ControlReg', 'uw', 'MISCREG_CPSR', 'IsInteger', 40), 'Fpsr': ('ControlReg', 'uw', 'MISCREG_FPSR', 'IsInteger', 41), - 'NPC': ('NPC', 'uw', None, (None, None, 'IsControl'), 42), - 'NNPC': ('NNPC', 'uw', None, (None, None, 'IsControl'), 43), + 'Fpsid': ('ControlReg', 'uw', 'MISCREG_FPSID', 'IsInteger', 42), + 'Fpscr': ('ControlReg', 'uw', 'MISCREG_FPSCR', 'IsInteger', 43), + 'Fpexc': ('ControlReg', 'uw', 'MISCREG_FPEXC', 'IsInteger', 44), + 'NPC': ('NPC', 'uw', None, (None, None, 'IsControl'), 45), + 'NNPC': ('NNPC', 'uw', None, (None, None, 'IsControl'), 46) }}; diff --git a/src/arch/arm/linux/linux.hh b/src/arch/arm/linux/linux.hh index 16bcee47a..d99fa8e49 100644 --- a/src/arch/arm/linux/linux.hh +++ b/src/arch/arm/linux/linux.hh @@ -66,18 +66,7 @@ class ArmLinux : public Linux //@} /// For mmap(). - static const unsigned TGT_MAP_ANONYMOUS = 0x800; - - //@{ - /// For getsysinfo(). - static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string - static const unsigned GSI_CPU_INFO = 59; //!< CPU information - static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type - static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine - static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system - static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB - static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz - //@} + static const unsigned TGT_MAP_ANONYMOUS = 0x20; //@{ /// For getrusage(). @@ -87,13 +76,8 @@ class ArmLinux : public Linux //@} //@{ - /// For setsysinfo(). - static const unsigned SSI_IEEE_FP_CONTROL = 14; //!< ieee_set_fp_control() - //@} - - //@{ /// ioctl() command codes. - static const unsigned TIOCGETP_ = 0x40067408; + static const unsigned TIOCGETP_ = 0x5401; static const unsigned TIOCSETP_ = 0x80067409; static const unsigned TIOCSETN_ = 0x8006740a; static const unsigned TIOCSETC_ = 0x80067411; @@ -114,15 +98,56 @@ class ArmLinux : public Linux TGT_RLIMIT_DATA = 2, TGT_RLIMIT_STACK = 3, TGT_RLIMIT_CORE = 4, - TGT_RLIMIT_NOFILE = 5, - TGT_RLIMIT_AS = 6, - TGT_RLIMIT_RSS = 7, - TGT_RLIMIT_VMEM = 7, - TGT_RLIMIT_NPROC = 8, - TGT_RLIMIT_MEMLOCK = 9, + TGT_RLIMIT_RSS = 5, + TGT_RLIMIT_NPROC = 6, + TGT_RLIMIT_NOFILE = 7, + TGT_RLIMIT_MEMLOCK = 8, + TGT_RLIMIT_AS = 9, TGT_RLIMIT_LOCKS = 10 }; + typedef struct { + uint32_t st_dev; + uint32_t st_ino; + uint16_t st_mode; + uint16_t st_nlink; + uint16_t st_uid; + uint16_t st_gid; + uint32_t st_rdev; + uint32_t st_size; + uint32_t st_blksize; + uint32_t st_blocks; + uint32_t st_atimeX; + uint32_t st_atime_nsec; + uint32_t st_mtimeX; + uint32_t st_mtime_nsec; + uint32_t st_ctimeX; + uint32_t st_ctime_nsec; + } tgt_stat; + + typedef struct { + uint64_t st_dev; + uint8_t __pad0[4]; + uint32_t __st_ino; + uint32_t st_mode; + uint32_t st_nlink; + uint32_t st_uid; + uint32_t st_gid; + uint64_t st_rdev; + uint8_t __pad3[4]; + int64_t __attribute__ ((aligned (8))) st_size; + uint32_t st_blksize; + uint64_t __attribute__ ((aligned (8))) st_blocks; + uint32_t st_atimeX; + uint32_t st_atime_nsec; + uint32_t st_mtimeX; + uint32_t st_mtime_nsec; + uint32_t st_ctimeX; + uint32_t st_ctime_nsec; + uint64_t st_ino; + } tgt_stat64; + + }; #endif diff --git a/src/arch/arm/linux/process.cc b/src/arch/arm/linux/process.cc index 7158acfff..56e3588a7 100644 --- a/src/arch/arm/linux/process.cc +++ b/src/arch/arm/linux/process.cc @@ -106,7 +106,7 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 40 */ SyscallDesc("rmdir", unimplementedFunc), /* 41 */ SyscallDesc("dup", unimplementedFunc), /* 42 */ SyscallDesc("pipe", unimplementedFunc), - /* 43 */ SyscallDesc("times", unimplementedFunc), + /* 43 */ SyscallDesc("times", ignoreFunc), /* 44 */ SyscallDesc("prof", unimplementedFunc), /* 45 */ SyscallDesc("brk", brkFunc), /* 46 */ SyscallDesc("setgid", unimplementedFunc), @@ -260,7 +260,7 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = { /* 194 */ SyscallDesc("ftruncate64", unimplementedFunc), /* 195 */ SyscallDesc("stat64", unimplementedFunc), /* 196 */ SyscallDesc("lstat64", lstat64Func<ArmLinux>), - /* 197 */ SyscallDesc("fstat64", fstatFunc<ArmLinux>), + /* 197 */ SyscallDesc("fstat64", fstat64Func<ArmLinux>), /* 198 */ SyscallDesc("lchown", unimplementedFunc), /* 199 */ SyscallDesc("getuid", getuidFunc), /* 200 */ SyscallDesc("getgid", getgidFunc), @@ -418,7 +418,6 @@ setTLSFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) { uint32_t tlsPtr = process->getSyscallArg(tc, 0); - TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, 0)); tc->getMemPort()->writeBlob(ArmLinuxProcess::commPage + 0x0ff0, (uint8_t *)&tlsPtr, sizeof(tlsPtr)); @@ -448,7 +447,8 @@ ArmLinuxProcess::getDesc(int callnum) // Angel SWI syscalls are unsupported in this release if (callnum == 0x123456) { panic("Attempt to execute an ANGEL_SWI system call (newlib-related)"); - } else if ((callnum & 0x00f00000) == 0x00900000) { + } else if ((callnum & 0x00f00000) == 0x00900000 || + (callnum & 0xf0000) == 0xf0000) { callnum &= 0x000fffff; if ((callnum & 0x0f0000) == 0xf0000) { callnum -= 0x0f0001; @@ -496,7 +496,7 @@ ArmLinuxProcess::startup() { 0x00, 0x30, 0x92, 0xe5, //ldr r3, [r2] 0x00, 0x30, 0x53, 0xe0, //subs r3, r3, r0 - 0x00, 0x10, 0x92, 0x05, //streq r1, [r2] + 0x00, 0x10, 0x82, 0x05, //streq r1, [r2] 0x03, 0x00, 0xa0, 0xe1, //mov r0, r3 0x0e, 0xf0, 0xa0, 0xe1 //usr_ret lr }; diff --git a/src/arch/arm/miscregs.hh b/src/arch/arm/miscregs.hh index 42065b0fd..3180669de 100644 --- a/src/arch/arm/miscregs.hh +++ b/src/arch/arm/miscregs.hh @@ -62,6 +62,9 @@ namespace ArmISA MISCREG_SPSR_UND, MISCREG_SPSR_ABT, MISCREG_FPSR, + MISCREG_FPSID, + MISCREG_FPSCR, + MISCREG_FPEXC, NUM_MISCREGS }; diff --git a/src/arch/arm/nativetrace.cc b/src/arch/arm/nativetrace.cc new file mode 100644 index 000000000..1ad9e1a19 --- /dev/null +++ b/src/arch/arm/nativetrace.cc @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2006 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 + */ + +#include "arch/arm/isa_traits.hh" +#include "arch/arm/miscregs.hh" +#include "arch/arm/nativetrace.hh" +#include "cpu/thread_context.hh" +#include "params/ArmNativeTrace.hh" + +namespace Trace { + +#if TRACING_ON +static const char *regNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "fp", "r12", "sp", "lr", "pc", + "cpsr" +}; +#endif + +void +Trace::ArmNativeTrace::ThreadState::update(NativeTrace *parent) +{ + oldState = state[current]; + current = (current + 1) % 2; + newState = state[current]; + + memcpy(newState, oldState, sizeof(state[0])); + + uint32_t diffVector; + parent->read(&diffVector, sizeof(diffVector)); + diffVector = ArmISA::gtoh(diffVector); + + int changes = 0; + for (int i = 0; i < STATE_NUMVALS; i++) { + if (diffVector & 0x1) { + changed[i] = true; + changes++; + } else { + changed[i] = false; + } + diffVector >>= 1; + } + + uint32_t values[changes]; + parent->read(values, sizeof(values)); + int pos = 0; + for (int i = 0; i < STATE_NUMVALS; i++) { + if (changed[i]) { + newState[i] = ArmISA::gtoh(values[pos++]); + changed[i] = (newState[i] != oldState[i]); + } + } +} + +void +Trace::ArmNativeTrace::ThreadState::update(ThreadContext *tc) +{ + oldState = state[current]; + current = (current + 1) % 2; + newState = state[current]; + + // Regular int regs + for (int i = 0; i < 15; i++) { + newState[i] = tc->readIntReg(i); + changed[i] = (oldState[i] != newState[i]); + } + + //R15, aliased with the PC + newState[STATE_PC] = tc->readNextPC(); + changed[STATE_PC] = (newState[STATE_PC] != oldState[STATE_PC]); + + //CPSR + newState[STATE_CPSR] = tc->readMiscReg(MISCREG_CPSR); + changed[STATE_CPSR] = (newState[STATE_CPSR] != oldState[STATE_CPSR]); +} + +void +Trace::ArmNativeTrace::check(NativeTraceRecord *record) +{ + ThreadContext *tc = record->getThread(); + // This area is read only on the target. It can't stop there to tell us + // what's going on, so we should skip over anything there also. + if (tc->readNextPC() > 0xffff0000) + return; + nState.update(this); + mState.update(tc); + + bool errorFound = false; + // Regular int regs + for (int i = 0; i < STATE_NUMVALS; i++) { + if (nState.changed[i] || mState.changed[i]) { + const char *vergence = " "; + bool oldMatch = (mState.oldState[i] == nState.oldState[i]); + bool newMatch = (mState.newState[i] == nState.newState[i]); + if (oldMatch && newMatch) { + // The more things change, the more they stay the same. + continue; + } else if (oldMatch && !newMatch) { + vergence = "<>"; + } else if (!oldMatch && newMatch) { + vergence = "><"; + } + errorFound = true; + if (!nState.changed[i]) { + DPRINTF(ExecRegDelta, "%s [%5s] "\ + "Native: %#010x "\ + "M5: %#010x => %#010x\n", + vergence, regNames[i], + nState.newState[i], + mState.oldState[i], mState.newState[i]); + } else if (!mState.changed[i]) { + DPRINTF(ExecRegDelta, "%s [%5s] "\ + "Native: %#010x => %#010x "\ + "M5: %#010x \n", + vergence, regNames[i], + nState.oldState[i], nState.newState[i], + mState.newState[i]); + } else { + DPRINTF(ExecRegDelta, "%s [%5s] "\ + "Native: %#010x => %#010x "\ + "M5: %#010x => %#010x\n", + vergence, regNames[i], + nState.oldState[i], nState.newState[i], + mState.oldState[i], mState.newState[i]); + } + } + } + if (errorFound) { + StaticInstPtr inst = record->getStaticInst(); + assert(inst); + bool ran = true; + if (inst->isMicroop()) { + ran = false; + inst = record->getMacroStaticInst(); + } + assert(inst); + record->traceInst(inst, ran); + + bool pcError = (mState.newState[STATE_PC] != + nState.newState[STATE_PC]); + if (stopOnPCError && pcError) + panic("Native trace detected an error in control flow!"); + } +} + +} /* namespace Trace */ + +//////////////////////////////////////////////////////////////////////// +// +// ExeTracer Simulation Object +// +Trace::ArmNativeTrace * +ArmNativeTraceParams::create() +{ + return new Trace::ArmNativeTrace(this); +}; diff --git a/src/arch/arm/nativetrace.hh b/src/arch/arm/nativetrace.hh new file mode 100644 index 000000000..7467e3378 --- /dev/null +++ b/src/arch/arm/nativetrace.hh @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2006 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 + */ + +#ifndef __ARCH_ARM_NATIVETRACE_HH__ +#define __ARCH_ARM_NATIVETRACE_HH__ + +#include "base/types.hh" +#include "cpu/nativetrace.hh" +#include "params/ArmNativeTrace.hh" + +namespace Trace { + +class ArmNativeTrace : public NativeTrace +{ + public: + enum StateID { + STATE_R0, + STATE_R1, + STATE_R2, + STATE_R3, + STATE_R4, + STATE_R5, + STATE_R6, + STATE_R7, + STATE_R8, + STATE_R9, + STATE_R10, + STATE_R11, + STATE_FP = STATE_R11, + STATE_R12, + STATE_R13, + STATE_SP = STATE_R13, + STATE_R14, + STATE_LR = STATE_R14, + STATE_R15, + STATE_PC = STATE_R15, + STATE_CPSR, + STATE_NUMVALS + }; + + protected: + struct ThreadState { + bool changed[STATE_NUMVALS]; + uint32_t state[2][STATE_NUMVALS]; + uint32_t *newState; + uint32_t *oldState; + int current; + void update(NativeTrace *parent); + void update(ThreadContext *tc); + + ThreadState() + { + for (int i = 0; i < STATE_NUMVALS; i++) { + changed[i] = false; + state[0][i] = state[1][i] = 0; + current = 0; + newState = state[0]; + oldState = state[1]; + } + } + }; + + ThreadState nState, mState; + + bool stopOnPCError; + + public: + typedef ArmNativeTraceParams Params; + + const Params * + params() const + { + return dynamic_cast<const Params *>(_params); + } + + ArmNativeTrace(const Params *p) : + NativeTrace(p), stopOnPCError(p->stop_on_pc_error) + {} + + void check(NativeTraceRecord *record); +}; + +} /* namespace Trace */ + +#endif // __ARCH_ARM_NATIVETRACE_HH__ diff --git a/src/arch/arm/process.cc b/src/arch/arm/process.cc index 365d5b22c..cd7cc9736 100644 --- a/src/arch/arm/process.cc +++ b/src/arch/arm/process.cc @@ -46,7 +46,7 @@ using namespace ArmISA; ArmLiveProcess::ArmLiveProcess(LiveProcessParams *params, ObjectFile *objFile) : LiveProcess(params, objFile) { - stack_base = 0xc0000000L; + stack_base = 0xbf000000L; // Set pointer for next thread stack. Reserve 8M for main stack. next_thread_stack_base = stack_base - (8 * 1024 * 1024); @@ -88,73 +88,239 @@ ArmLiveProcess::copyStringArray32(std::vector<std::string> &strings, void ArmLiveProcess::argsInit(int intSize, int pageSize) { + typedef AuxVector<uint32_t> auxv_t; + std::vector<auxv_t> auxv; + + string filename; + if (argv.size() < 1) + filename = ""; + else + filename = argv[0]; + + //We want 16 byte alignment + uint64_t align = 16; + // Overloaded argsInit so that we can fine-tune for ARM architecture Process::startup(); // load object file into target memory objFile->loadSections(initVirtMem); - // Calculate how much space we need for arg & env arrays. - int argv_array_size = intSize * (argv.size() + 1); - int envp_array_size = intSize * (envp.size() + 1); - int arg_data_size = 0; - for (int i = 0; i < argv.size(); ++i) { - arg_data_size += argv[i].size() + 1; + enum ArmCpuFeature { + Arm_Swp = 1 << 0, + Arm_Half = 1 << 1, + Arm_Thumb = 1 << 2, + Arm_26Bit = 1 << 3, + Arm_FastMult = 1 << 4, + Arm_Fpa = 1 << 5, + Arm_Vfp = 1 << 6, + Arm_Edsp = 1 << 7, + Arm_Java = 1 << 8, + Arm_Iwmmxt = 1 << 9, + Arm_Crunch = 1 << 10 + }; + + //Setup the auxilliary vectors. These will already have endian conversion. + //Auxilliary vectors are loaded only for elf formatted executables. + ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile); + if (elfObject) { + uint32_t features = + Arm_Swp | + Arm_Half | + Arm_Thumb | +// Arm_26Bit | + Arm_FastMult | +// Arm_Fpa | + Arm_Vfp | + Arm_Edsp | + Arm_Java | +// Arm_Iwmmxt | +// Arm_Crunch | + 0; + + //Bits which describe the system hardware capabilities + //XXX Figure out what these should be + auxv.push_back(auxv_t(M5_AT_HWCAP, features)); + //The system page size + auxv.push_back(auxv_t(M5_AT_PAGESZ, ArmISA::VMPageSize)); + //Frequency at which times() increments + auxv.push_back(auxv_t(M5_AT_CLKTCK, 0x64)); + // 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(M5_AT_PHDR, elfObject->programHeaderTable())); + // This is the size of a program header entry from the elf file. + 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(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(M5_AT_BASE, 0)); + + //XXX Figure out what this should be. + auxv.push_back(auxv_t(M5_AT_FLAGS, 0)); + //The entry point to the program + auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint())); + //Different user and group IDs + 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(M5_AT_SECURE, 0)); + //The filename of the program + auxv.push_back(auxv_t(M5_AT_EXECFN, 0)); + //The string "v51" with unknown meaning + auxv.push_back(auxv_t(M5_AT_PLATFORM, 0)); } + + //Figure out how big the initial stack nedes to be + + // A sentry NULL void pointer at the top of the stack. + int sentry_size = intSize; + + string platform = "v51"; + int platform_size = platform.size() + 1; + + // The aux vectors are put on the stack in two groups. The first group are + // the vectors that are generated as the elf is loaded. The second group + // are the ones that were computed ahead of time and include the platform + // string. + int aux_data_size = filename.size() + 1; + int env_data_size = 0; for (int i = 0; i < envp.size(); ++i) { env_data_size += envp[i].size() + 1; } + int arg_data_size = 0; + for (int i = 0; i < argv.size(); ++i) { + arg_data_size += argv[i].size() + 1; + } - int space_needed = - argv_array_size + envp_array_size + arg_data_size + env_data_size; - if (space_needed < 16*1024) - space_needed = 16*1024; + int info_block_size = + sentry_size + env_data_size + arg_data_size + + aux_data_size + platform_size; + + //Each auxilliary vector is two 4 byte words + int aux_array_size = intSize * 2 * (auxv.size() + 1); + + int envp_array_size = intSize * (envp.size() + 1); + int argv_array_size = intSize * (argv.size() + 1); + + int argc_size = intSize; + + //Figure out the size of the contents of the actual initial frame + int frame_size = + info_block_size + + aux_array_size + + envp_array_size + + argv_array_size + + argc_size; + + //There needs to be padding after the auxiliary vector data so that the + //very bottom of the stack is aligned properly. + int partial_size = frame_size; + int aligned_partial_size = roundUp(partial_size, align); + int aux_padding = aligned_partial_size - partial_size; + + int space_needed = frame_size + aux_padding; - // set bottom of stack stack_min = stack_base - space_needed; - // align it - stack_min = roundDown(stack_min, pageSize); + stack_min = roundDown(stack_min, align); stack_size = stack_base - stack_min; + // map memory - pTable->allocate(stack_min, roundUp(stack_size, pageSize)); + pTable->allocate(roundDown(stack_min, pageSize), + roundUp(stack_size, pageSize)); // map out initial stack contents - Addr argv_array_base = stack_min + intSize; // room for argc - Addr envp_array_base = argv_array_base + argv_array_size; - Addr arg_data_base = envp_array_base + envp_array_size; - Addr env_data_base = arg_data_base + arg_data_size; + uint32_t sentry_base = stack_base - sentry_size; + uint32_t aux_data_base = sentry_base - aux_data_size; + uint32_t env_data_base = aux_data_base - env_data_size; + uint32_t arg_data_base = env_data_base - arg_data_size; + uint32_t platform_base = arg_data_base - platform_size; + uint32_t auxv_array_base = platform_base - aux_array_size - aux_padding; + uint32_t envp_array_base = auxv_array_base - envp_array_size; + uint32_t argv_array_base = envp_array_base - argv_array_size; + uint32_t argc_base = argv_array_base - argc_size; + + DPRINTF(Stack, "The addresses of items on the initial stack:\n"); + DPRINTF(Stack, "0x%x - aux data\n", aux_data_base); + DPRINTF(Stack, "0x%x - env data\n", env_data_base); + DPRINTF(Stack, "0x%x - arg data\n", arg_data_base); + DPRINTF(Stack, "0x%x - platform base\n", platform_base); + DPRINTF(Stack, "0x%x - auxv array\n", auxv_array_base); + DPRINTF(Stack, "0x%x - envp array\n", envp_array_base); + DPRINTF(Stack, "0x%x - argv array\n", argv_array_base); + DPRINTF(Stack, "0x%x - argc \n", argc_base); + DPRINTF(Stack, "0x%x - stack min\n", stack_min); // write contents to stack - uint64_t argc = argv.size(); - if (intSize == 8) - argc = htog((uint64_t)argc); - else if (intSize == 4) - argc = htog((uint32_t)argc); - else - panic("Unknown int size"); - initVirtMem->writeBlob(stack_min, (uint8_t*)&argc, intSize); + // figure out argc + uint32_t argc = argv.size(); + uint32_t guestArgc = ArmISA::htog(argc); - copyStringArray32(argv, argv_array_base, arg_data_base, initVirtMem); - copyStringArray32(envp, envp_array_base, env_data_base, initVirtMem); + //Write out the sentry void * + uint32_t sentry_NULL = 0; + initVirtMem->writeBlob(sentry_base, + (uint8_t*)&sentry_NULL, sentry_size); - /* - //uint8_t insns[] = {0xe5, 0x9f, 0x00, 0x08, 0xe1, 0xa0, 0xf0, 0x0e}; - uint8_t insns[] = {0x08, 0x00, 0x9f, 0xe5, 0x0e, 0xf0, 0xa0, 0xe1}; + //Fix up the aux vectors which point to other data + for (int i = auxv.size() - 1; i >= 0; i--) { + if (auxv[i].a_type == M5_AT_PLATFORM) { + auxv[i].a_val = platform_base; + initVirtMem->writeString(platform_base, platform.c_str()); + } else if (auxv[i].a_type == M5_AT_EXECFN) { + auxv[i].a_val = aux_data_base; + initVirtMem->writeString(aux_data_base, filename.c_str()); + } + } - initVirtMem->writeBlob(0xffff0fe0, insns, 8); - */ + //Copy the aux stuff + for(int x = 0; x < auxv.size(); x++) + { + initVirtMem->writeBlob(auxv_array_base + x * 2 * intSize, + (uint8_t*)&(auxv[x].a_type), intSize); + initVirtMem->writeBlob(auxv_array_base + (x * 2 + 1) * intSize, + (uint8_t*)&(auxv[x].a_val), intSize); + } + //Write out the terminating zeroed auxilliary vector + const uint64_t zero = 0; + initVirtMem->writeBlob(auxv_array_base + 2 * intSize * auxv.size(), + (uint8_t*)&zero, 2 * intSize); - ThreadContext *tc = system->getThreadContext(contextIds[0]); + 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); - tc->setIntReg(ArgumentReg1, argc); - tc->setIntReg(ArgumentReg2, argv_array_base); + ThreadContext *tc = system->getThreadContext(contextIds[0]); + //Set the stack pointer register tc->setIntReg(StackPointerReg, stack_min); + //A pointer to a function to run when the program exits. We'll set this + //to zero explicitly to make sure this isn't used. + tc->setIntReg(ArgumentReg0, 0); + //Set argument regs 1 and 2 to argv[0] and envp[0] respectively + if (argv.size() > 0) { + tc->setIntReg(ArgumentReg1, arg_data_base + arg_data_size - + argv[argv.size() - 1].size() - 1); + } else { + tc->setIntReg(ArgumentReg1, 0); + } + if (envp.size() > 0) { + tc->setIntReg(ArgumentReg2, env_data_base + env_data_size - + envp[envp.size() - 1].size() - 1); + } else { + tc->setIntReg(ArgumentReg2, 0); + } Addr prog_entry = objFile->entryPoint(); tc->setPC(prog_entry); tc->setNextPC(prog_entry + sizeof(MachInst)); + + //Align the "stack_min" to a page boundary. + stack_min = roundDown(stack_min, pageSize); } ArmISA::IntReg diff --git a/src/arch/mips/mt.hh b/src/arch/mips/mt.hh index 3cb81c201..7217c335e 100755 --- a/src/arch/mips/mt.hh +++ b/src/arch/mips/mt.hh @@ -118,7 +118,7 @@ forkThread(TC *tc, Fault &fault, int Rd_bits, int Rs, int Rt) tc->readRegOtherThread(MISCREG_TC_BIND + Ctrl_Base_DepTag, tid); TCBindReg tcBind = tc->readMiscRegNoEffect(MISCREG_TC_BIND); - if (tidTCBind.curVPE = tcBind.curVPE) { + if (tidTCBind.curVPE == tcBind.curVPE) { TCStatusReg tidTCStatus = tc->readRegOtherThread(MISCREG_TC_STATUS + diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc index 16fc698dd..15ad88f76 100644 --- a/src/base/loader/elf_object.cc +++ b/src/base/loader/elf_object.cc @@ -107,7 +107,6 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) { case ELFOSABI_LINUX: - case ELFOSABI_ARM: opSys = ObjectFile::Linux; break; case ELFOSABI_SOLARIS: @@ -116,6 +115,9 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) case ELFOSABI_TRU64: opSys = ObjectFile::Tru64; break; + case ELFOSABI_ARM: + opSys = ObjectFile::LinuxArmOABI; + break; default: opSys = ObjectFile::UnknownOpSys; } diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh index 73df5caf6..e511451b7 100644 --- a/src/base/loader/object_file.hh +++ b/src/base/loader/object_file.hh @@ -59,7 +59,8 @@ class ObjectFile UnknownOpSys, Tru64, Linux, - Solaris + Solaris, + LinuxArmOABI }; protected: diff --git a/src/cpu/NativeTrace.py b/src/cpu/NativeTrace.py index 7fd240543..dba6de067 100644 --- a/src/cpu/NativeTrace.py +++ b/src/cpu/NativeTrace.py @@ -28,9 +28,9 @@ from m5.SimObject import SimObject from m5.params import * -from InstTracer import InstTracer +from ExeTracer import ExeTracer -class NativeTrace(InstTracer): +class NativeTrace(ExeTracer): abstract = True type = 'NativeTrace' cxx_class = 'Trace::NativeTrace' diff --git a/src/cpu/nativetrace.cc b/src/cpu/nativetrace.cc index 47c58434f..8c17eb825 100644 --- a/src/cpu/nativetrace.cc +++ b/src/cpu/nativetrace.cc @@ -38,7 +38,7 @@ using namespace std; namespace Trace { NativeTrace::NativeTrace(const Params *p) - : InstTracer(p) + : ExeTracer(p) { if (ListenSocket::allDisabled()) fatal("All listeners are disabled!"); diff --git a/src/cpu/nativetrace.hh b/src/cpu/nativetrace.hh index 34869f263..6ad6b0242 100644 --- a/src/cpu/nativetrace.hh +++ b/src/cpu/nativetrace.hh @@ -37,8 +37,8 @@ #include "base/socket.hh" #include "base/trace.hh" #include "base/types.hh" +#include "cpu/exetrace.hh" #include "cpu/static_inst.hh" -#include "sim/insttracer.hh" class ThreadContext; @@ -46,7 +46,7 @@ namespace Trace { class NativeTrace; -class NativeTraceRecord : public InstRecord +class NativeTraceRecord : public ExeTracerRecord { protected: NativeTrace * parent; @@ -56,7 +56,7 @@ class NativeTraceRecord : public InstRecord Tick _when, ThreadContext *_thread, const StaticInstPtr _staticInst, Addr _pc, bool spec, const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0) - : InstRecord(_when, _thread, _staticInst, _pc, spec, + : ExeTracerRecord(_when, _thread, _staticInst, _pc, spec, _macroStaticInst, _upc), parent(_parent) { @@ -65,7 +65,7 @@ class NativeTraceRecord : public InstRecord void dump(); }; -class NativeTrace : public InstTracer +class NativeTrace : public ExeTracer { protected: int fd; diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index d9d624e77..8a44eba37 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -262,7 +262,9 @@ class SimpleThread : public ThreadState { int flatIndex = isa.flattenIntIndex(reg_idx); assert(flatIndex < TheISA::NumIntRegs); - return intRegs[flatIndex]; + uint64_t regVal = intRegs[flatIndex]; + DPRINTF(IntRegs, "Reading int reg %d as %#x.\n", reg_idx, regVal); + return regVal; } FloatReg readFloatReg(int reg_idx) @@ -283,6 +285,7 @@ class SimpleThread : public ThreadState { int flatIndex = isa.flattenIntIndex(reg_idx); assert(flatIndex < TheISA::NumIntRegs); + DPRINTF(IntRegs, "Setting int reg %d to %#x.\n", reg_idx, val); intRegs[flatIndex] = val; } diff --git a/src/sim/process.cc b/src/sim/process.cc index c12101069..55bd2f209 100644 --- a/src/sim/process.cc +++ b/src/sim/process.cc @@ -748,7 +748,9 @@ LiveProcess::create(LiveProcessParams * params) case ObjectFile::Linux: process = new ArmLinuxProcess(params, objFile); break; - + case ObjectFile::LinuxArmOABI: + fatal("M5 does not support ARM OABI binaries. Please recompile with an" + " EABI compiler."); default: fatal("Unknown/unsupported operating system."); } diff --git a/src/sim/process.hh b/src/sim/process.hh index 0d5421dcd..05a48071a 100644 --- a/src/sim/process.hh +++ b/src/sim/process.hh @@ -295,6 +295,10 @@ class LiveProcess : public Process M5_AT_CLKTCK = 17, M5_AT_SECURE = 23, + M5_BASE_PLATFORM = 24, + M5_AT_RANDOM = 25, + + M5_AT_EXECFN = 31, M5_AT_VECTOR_SIZE = 44 }; diff --git a/tests/quick/00.hello/ref/arm/linux/simple-atomic/simerr b/tests/quick/00.hello/ref/arm/linux/simple-atomic/simerr index a2692a6c9..7c23c610e 100755 --- a/tests/quick/00.hello/ref/arm/linux/simple-atomic/simerr +++ b/tests/quick/00.hello/ref/arm/linux/simple-atomic/simerr @@ -1,5 +1,5 @@ warn: Sockets disabled, not accepting gdb connections For more information see: http://www.m5sim.org/warn/d946bea6 -warn: allowing mmap of file @ fd 4294967295. This will break if not /dev/zero. -For more information see: http://www.m5sim.org/warn/3a2134f6 +warn: instruction 'fstmx' unimplemented +For more information see: http://www.m5sim.org/warn/21b09adb hack: be nice to actually delete the event here diff --git a/tests/quick/00.hello/ref/arm/linux/simple-atomic/simout b/tests/quick/00.hello/ref/arm/linux/simple-atomic/simout index 40fbf355d..15f79c280 100755 --- a/tests/quick/00.hello/ref/arm/linux/simple-atomic/simout +++ b/tests/quick/00.hello/ref/arm/linux/simple-atomic/simout @@ -5,13 +5,12 @@ The Regents of The University of Michigan All Rights Reserved -M5 compiled Jun 9 2009 23:46:33 -M5 revision 6639f3c716a6 6238 default qtip tip armreg.patch qbase -M5 started Jun 9 2009 23:53:49 +M5 compiled Jul 27 2009 00:45:04 +M5 revision 44a3d32f3217 6414 default qtip tip runnableagainstatupdate.patch +M5 started Jul 27 2009 00:45:05 M5 executing on fajita command line: build/ARM_SE/m5.fast -d build/ARM_SE/tests/fast/quick/00.hello/arm/linux/simple-atomic -re tests/run.py build/ARM_SE/tests/fast/quick/00.hello/arm/linux/simple-atomic Global frequency set at 1000000000000 ticks per second info: Entering event queue @ 0. Starting simulation... -info: Increasing stack size by one page. Hello world! -Exiting @ tick 2299000 because target called exit() +Exiting @ tick 2748500 because target called exit() diff --git a/tests/quick/00.hello/ref/arm/linux/simple-atomic/stats.txt b/tests/quick/00.hello/ref/arm/linux/simple-atomic/stats.txt index 5a17d118e..ece84babb 100644 --- a/tests/quick/00.hello/ref/arm/linux/simple-atomic/stats.txt +++ b/tests/quick/00.hello/ref/arm/linux/simple-atomic/stats.txt @@ -1,13 +1,13 @@ ---------- Begin Simulation Statistics ---------- -host_inst_rate 79163 # Simulator instruction rate (inst/s) -host_mem_usage 189980 # Number of bytes of host memory used -host_seconds 0.06 # Real time elapsed on the host -host_tick_rate 39442081 # Simulator tick rate (ticks/s) +host_inst_rate 9392 # Simulator instruction rate (inst/s) +host_mem_usage 189932 # Number of bytes of host memory used +host_seconds 0.59 # Real time elapsed on the host +host_tick_rate 4693453 # Simulator tick rate (ticks/s) sim_freq 1000000000000 # Frequency of simulated ticks -sim_insts 4598 # Number of instructions simulated -sim_seconds 0.000002 # Number of seconds simulated -sim_ticks 2299000 # Number of ticks simulated +sim_insts 5498 # Number of instructions simulated +sim_seconds 0.000003 # Number of seconds simulated +sim_ticks 2748500 # Number of ticks simulated system.cpu.dtb.accesses 0 # DTB accesses system.cpu.dtb.hits 0 # DTB hits system.cpu.dtb.misses 0 # DTB misses @@ -28,9 +28,9 @@ system.cpu.itb.write_accesses 0 # DT system.cpu.itb.write_hits 0 # DTB write hits system.cpu.itb.write_misses 0 # DTB write misses system.cpu.not_idle_fraction 1 # Percentage of non-idle cycles -system.cpu.numCycles 4599 # number of cpu cycles simulated -system.cpu.num_insts 4598 # Number of instructions executed -system.cpu.num_refs 1851 # Number of memory references -system.cpu.workload.PROG:num_syscalls 14 # Number of system calls +system.cpu.numCycles 5498 # number of cpu cycles simulated +system.cpu.num_insts 5498 # Number of instructions executed +system.cpu.num_refs 2127 # Number of memory references +system.cpu.workload.PROG:num_syscalls 13 # Number of system calls ---------- End Simulation Statistics ---------- diff --git a/tests/test-progs/hello/bin/arm/linux/hello b/tests/test-progs/hello/bin/arm/linux/hello Binary files differindex 818e17048..831ea7ee8 100755 --- a/tests/test-progs/hello/bin/arm/linux/hello +++ b/tests/test-progs/hello/bin/arm/linux/hello diff --git a/util/statetrace/Makefile b/util/statetrace/Makefile index 2abc06d8e..438828981 100644 --- a/util/statetrace/Makefile +++ b/util/statetrace/Makefile @@ -26,12 +26,31 @@ # # Authors: Gabe Black -.PHONY: statetrace +CXX := g++ +INCLUDES := -I ./ -I ./arch +CXXFLAGS := -O3 -ggdb -statetrace: statetrace-native +define build-obj +$(CXX) -c $(patsubst %.o,%.cc,$@) -o $@ $(INCLUDES) $(CXXFLAGS) +endef -statetrace-native: statetrace.cc tracechild.cc tracechild_arch.cc printer.cc printer.hh refcnt.hh regstate.hh tracechild.hh - g++ statetrace.cc tracechild.cc tracechild_arch.cc printer.cc -I ./ -I ./arch/ -O3 --static -o statetrace +define final-link +$(CXX) $(INCLUDES) $(CXXFLAGS) -o $@ $^ +endef -statetrace-sparc: statetrace.cc tracechild.cc tracechild_arch.cc printer.cc printer.hh refcnt.hh regstate.hh tracechild.hh - sparc64-unknown-linux-gnu-g++ statetrace.cc tracechild.cc tracechild_arch.cc printer.cc -g -I ./ -I ./arch/ -O3 --static -o statetrace +all: statetrace + +printer.o: printer.cc printer.hh tracechild.hh refcnt.hh regstate.hh + $(build-obj) +statetrace.o: statetrace.cc printer.hh tracechild.hh refcnt.hh regstate.hh + $(build-obj) +tracechild.o: tracechild.cc tracechild.hh regstate.hh + $(build-obj) +tracechild_arch.o: statetrace.cc printer.hh tracechild.hh refcnt.hh regstate.hh arch/tracechild_arm.hh arch/tracechild_arm.cc arch/tracechild_i386.hh arch/tracechild_i386.cc arch/tracechild_amd64.cc arch/tracechild_amd64.hh arch/tracechild_sparc.cc arch/tracechild_sparc.hh + $(build-obj) + +statetrace: printer.o statetrace.o tracechild.o tracechild_arch.o + $(final-link) + +clean: + rm -f *.o statetrace diff --git a/util/statetrace/arch/tracechild_arm.cc b/util/statetrace/arch/tracechild_arm.cc new file mode 100644 index 000000000..b52c0694a --- /dev/null +++ b/util/statetrace/arch/tracechild_arm.cc @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2006-2009 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: Ali Saidi + * Gabe Black + */ + +#include <iostream> +#include <errno.h> +#include <stdint.h> +#include <cstring> + +#include "tracechild_arm.hh" + +using namespace std; + +const char* ARMTraceChild::regNames[numregs] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "fp", "r12", "sp", "lr", "pc", + "cpsr" }; + + +ARMTraceChild::ARMTraceChild() +{ + for (int x = 0; x < numregs; x++) { + memset(®s, 0, sizeof(regs)); + memset(&oldregs, 0, sizeof(regs)); + regDiffSinceUpdate[x] = false; + } +} + +bool ARMTraceChild::sendState(int socket) +{ + uint32_t regVal = 0; + uint32_t message[numregs + 1]; + int pos = 1; + message[0] = 0; + for (int x = 0; x < numregs; x++) { + if (regDiffSinceUpdate[x]) { + message[0] = message[0] | (1 << x); + message[pos++] = getRegVal(x); + } + } + + size_t sent = 0; + size_t toSend = pos * sizeof(message[0]); + uint8_t *messagePtr = (uint8_t *)message; + while (toSend != 0) { + sent = write(socket, messagePtr, toSend); + if (sent == -1) { + cerr << "Write failed! " << strerror(errno) << endl; + tracing = false; + return false; + } + toSend -= sent; + messagePtr += sent; + } + + return true; +} + +uint32_t ARMTraceChild::getRegs(user_regs &myregs, int num) +{ + assert(num < numregs && num >= 0); + return myregs.uregs[num]; +} + +bool ARMTraceChild::update(int pid) +{ + oldregs = regs; + if(ptrace(PTRACE_GETREGS, pid, 0, ®s) != 0) + { + cerr << "update: " << strerror(errno) << endl; + return false; + } + + for(unsigned int x = 0; x < numregs; x++) + regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x)); + return true; +} + +int64_t ARMTraceChild::getRegVal(int num) +{ + return getRegs(regs, num); +} + +int64_t ARMTraceChild::getOldRegVal(int num) +{ + return getRegs(oldregs, num); +} + +char * ARMTraceChild::printReg(int num) +{ + sprintf(printBuffer, "0x%08X", (uint32_t)getRegVal(num)); + return printBuffer; +} + +ostream & ARMTraceChild::outputStartState(ostream & os) +{ + uint32_t sp = getSP(); + uint32_t pc = getPC(); + uint32_t highestInfo = 0; + char obuf[1024]; + sprintf(obuf, "Initial stack pointer = 0x%08x\n", sp); + os << obuf; + sprintf(obuf, "Initial program counter = 0x%08x\n", pc); + os << obuf; + + //Output the argument count + int32_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sprintf(obuf, "0x%08x: Argc = 0x%08x\n", sp, cargc); + os << obuf; + sp += 4; + + //Output argv pointers + int argCount = 0; + int32_t cargv; + do + { + cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sprintf(obuf, "0x%08x: argv[%d] = 0x%08x\n", + sp, argCount++, cargv); + if(cargv) + if(highestInfo < cargv) + highestInfo = cargv; + os << obuf; + sp += 4; + } while(cargv); + + //Output the envp pointers + int envCount = 0; + uint32_t cenvp; + do + { + cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sprintf(obuf, "0x%08x: envp[%d] = 0x%08x\n", + sp, envCount++, cenvp); + os << obuf; + sp += 4; + } while(cenvp); + uint32_t auxType, auxVal; + do + { + auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sp += 4; + auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + sp += 4; + sprintf(obuf, "0x%08x: Auxiliary vector = {0x%08x, 0x%08x}\n", + sp - 8, auxType, auxVal); + os << obuf; + } while(auxType != 0 || auxVal != 0); + //Print out the argument strings, environment strings, and file name. + string current; + uint32_t buf; + uint32_t currentStart = sp; + bool clearedInitialPadding = false; + do + { + buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0); + char * cbuf = (char *)&buf; + for(int x = 0; x < sizeof(uint32_t); x++) + { + if(cbuf[x]) + current += cbuf[x]; + else + { + sprintf(obuf, "0x%08x: \"%s\"\n", + currentStart, current.c_str()); + os << obuf; + current = ""; + currentStart = sp + x + 1; + } + } + sp += 4; + clearedInitialPadding = clearedInitialPadding || buf != 0; + } while(!clearedInitialPadding || buf != 0 || sp <= highestInfo); + return os; +} + +bool ARMTraceChild::step() +{ + const uint32_t bkpt_inst = 0xe7f001f0; + + uint32_t lr = getRegVal(14); + uint32_t pc = getPC(); + uint32_t lrOp; + + // Since ARM uses software breakpoints behind the scenes, they don't work + // in read only areas like the page of routines provided by the kernel. The + // link register generally holds the address the process wants to the + // kernel to return to after it's done, so we'll install a software + // breakpoint there. If the lr happens to point to the next instruction + // we'll leave out our breakpoint to avoid an infinite loop. This isn't a + // fool proof strategy, but it should work well in all the reasonable + // scenarios I can think of right now. + + if (pc != lr) { + lrOp = ptrace(PTRACE_PEEKDATA, pid, lr, 0); + ptrace(PTRACE_POKEDATA, pid, lr, bkpt_inst); + } + ptraceSingleStep(); + if (pc != lr) { + ptrace(PTRACE_POKEDATA, pid, lr, lrOp); + } +} + + +TraceChild * genTraceChild() +{ + return new ARMTraceChild; +} + diff --git a/util/statetrace/arch/tracechild_arm.hh b/util/statetrace/arch/tracechild_arm.hh new file mode 100644 index 000000000..9e1af6a8d --- /dev/null +++ b/util/statetrace/arch/tracechild_arm.hh @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2009 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: Ali Saidi + * Gabe Black + */ + +#ifndef TRACECHILD_ARM_HH +#define TRACECHILD_ARM_HH + +#include <cassert> +#include <string> +#include <sys/user.h> +#include <sys/ptrace.h> +#include "tracechild.hh" + + +class ARMTraceChild : public TraceChild +{ + public: + enum RegNum + { + // r0 - r3 argument, temp, caller save + // r4 - r10 callee save + // r11 - FP + // r12 - temp + // r13 - stack + // r14 - link + // r15 - pc + R0, R1, R2, R3, R4, R5, R6, R7, + R8, R9, R10, FP, R12, SP, LR, PC, + CPSR, + numregs + }; + private: + char printBuffer[256]; + static const char *regNames[numregs]; + uint32_t getRegs(user_regs& myregs, int num); + user_regs regs; + user_regs oldregs; + bool regDiffSinceUpdate[numregs]; + + protected: + bool update(int pid); + + public: + ARMTraceChild(); + bool sendState(int socket); + + int getNumRegs() + { + return numregs; + } + + bool diffSinceUpdate(int num) + { + assert(num < numregs && num >= 0); + return regDiffSinceUpdate[num]; + } + + std::string getRegName(int num) + { + assert(num < numregs && num >= 0); + return regNames[num]; + } + + int64_t getRegVal(int num); + int64_t getOldRegVal(int num); + + bool step(); + + uint64_t getPC() + { + return getRegVal(PC); + } + + uint64_t getSP() + { + return getRegVal(SP); + } + + char * printReg(int num); + + std::ostream & outputStartState(std::ostream & os); + +}; + +#endif + diff --git a/util/statetrace/statetrace.cc b/util/statetrace/statetrace.cc index 5f7224b25..e2762ac2c 100644 --- a/util/statetrace/statetrace.cc +++ b/util/statetrace/statetrace.cc @@ -28,19 +28,19 @@ * Authors: Gabe Black */ -#include <iostream> +#include <cstring> +#include <errno.h> #include <fstream> +#include <iostream> +#include <netdb.h> +#include <netinet/in.h> +#include <stdio.h> #include <string> +#include <sys/ptrace.h> +#include <sys/socket.h> #include <sys/types.h> #include <sys/wait.h> -#include <sys/ptrace.h> #include <unistd.h> -#include <stdio.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#include <errno.h> #include "printer.hh" #include "tracechild.hh" @@ -61,6 +61,7 @@ int main(int argc, char * argv[], char * envp[]) //Parse the command line arguments bool printInitial = false; bool printTrace = true; + string host = "localhost"; for(int x = 1; x < argc; x++) { if(!strcmp(argv[x], "-h")) @@ -68,6 +69,17 @@ int main(int argc, char * argv[], char * envp[]) printUsage(argv[0]); return 0; } + if(!strcmp(argv[x], "--host")) + { + x++; + if(x >= argc) + { + cerr << "Incorrect usage.\n" << endl; + printUsage(argv[0]); + return 1; + } + host = argv[x]; + } else if(!strcmp(argv[x], "-r")) { cout << "Legal register names:" << endl; @@ -111,6 +123,7 @@ int main(int argc, char * argv[], char * envp[]) cerr << "Couldn't start target program" << endl; return 1; } + child->step(); if(printInitial) { child->outputStartState(cout); @@ -127,7 +140,7 @@ int main(int argc, char * argv[], char * envp[]) return 1; } struct hostent *server; - server = gethostbyname("localhost"); + server = gethostbyname(host.c_str()); if(!server) { cerr << "Couldn't get host ip! " << strerror(errno) << endl; @@ -145,7 +158,6 @@ int main(int argc, char * argv[], char * envp[]) cerr << "Couldn't connect to server! " << strerror(errno) << endl; return 1; } - child->step(); while(child->isTracing()) { if(!child->sendState(sock)) diff --git a/util/statetrace/tracechild.cc b/util/statetrace/tracechild.cc index 603429829..85f42addd 100644 --- a/util/statetrace/tracechild.cc +++ b/util/statetrace/tracechild.cc @@ -29,10 +29,11 @@ */ #include "tracechild.hh" -#include <sys/wait.h> -#include <sys/ptrace.h> -#include <iostream> +#include <cstring> #include <errno.h> +#include <iostream> +#include <sys/ptrace.h> +#include <sys/wait.h> using namespace std; @@ -78,11 +79,6 @@ bool TraceChild::startTracing(const char * pathToFile, char * const argv[]) return false; } tracing = true; - if(!update(pid)) - { - cout << "Didn't update successfully!" << endl; - return false; - } return true; } diff --git a/util/statetrace/tracechild_arch.cc b/util/statetrace/tracechild_arch.cc index 570a12b54..345de46e8 100644 --- a/util/statetrace/tracechild_arch.cc +++ b/util/statetrace/tracechild_arch.cc @@ -33,6 +33,8 @@ #elif defined __amd64__ // #error "AMD64 architecture not implemented" #include "arch/tracechild_amd64.cc" +#elif defined __arm__ + #include "arch/tracechild_arm.cc" #elif defined __hppa__ #error "Hppa architecture not implemented" #elif defined __i386__ || defined __i486__ || \ |