From 34b4722aeeb5abdf34c3e90365411297884680fe Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 22 Feb 2007 13:17:51 +0000 Subject: [PATCH 1/7] Make the m5 pseudo instructions only work in FS. Also, make sure any undefined opcodes in impdep2 (which in SE is all of them) trap with an illegal_instruction exception. --HG-- extra : convert_revision : dd7848d0685e4cc6f5fd5e3b846a3f70b62ee30a --- src/arch/sparc/isa/decoder.isa | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa index e2d1707dd..2ce700ef1 100644 --- a/src/arch/sparc/isa/decoder.isa +++ b/src/arch/sparc/isa/decoder.isa @@ -1011,13 +1011,15 @@ decode OP default Unknown::unknown() } // M5 special opcodes use the reserved IMPDEP2A opcode space 0x37: decode M5FUNC { +#if FULL_SYSTEM // we have 7 bits of space here to play with... 0x21: m5exit({{PseudoInst::m5exit(xc->tcBase(), O0); }}, No_OpClass, IsNonSpeculative); 0x54: m5panic({{ panic("M5 panic instruction called at pc=%#x.", xc->readPC()); }}, No_OpClass, IsNonSpeculative); - +#endif + default: Trap::impdep2({{fault = new IllegalInstruction;}}); } 0x38: Branch::jmpl({{ Addr target = Rs1 + Rs2_or_imm13; From 6ae4cae971790f2e6e938c80be46f351a4a87e4c Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Fri, 23 Feb 2007 01:05:34 +0000 Subject: [PATCH 2/7] Ali and I both made the same change and we only need it once. I liked mine a little better. --HG-- extra : convert_revision : 3a1b7856e6143ca089fd6e36492608377dfede19 --- src/arch/sparc/isa/decoder.isa | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa index 6c97ca76c..2ce700ef1 100644 --- a/src/arch/sparc/isa/decoder.isa +++ b/src/arch/sparc/isa/decoder.isa @@ -1009,7 +1009,6 @@ decode OP default Unknown::unknown() 0x80: Trap::shutdown({{fault = new IllegalInstruction;}}); 0x81: FailUnimpl::siam(); } -#if FULL_SYSTEM // M5 special opcodes use the reserved IMPDEP2A opcode space 0x37: decode M5FUNC { #if FULL_SYSTEM @@ -1022,9 +1021,6 @@ decode OP default Unknown::unknown() #endif default: Trap::impdep2({{fault = new IllegalInstruction;}}); } -#else - 0x37: Trap::impdep2({{fault = new IllegalInstruction;}}); -#endif 0x38: Branch::jmpl({{ Addr target = Rs1 + Rs2_or_imm13; if(target & 0x3) From 99948060b2863b37c0db5e6b609ff7ff30de6d1b Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 28 Feb 2007 16:29:25 +0000 Subject: [PATCH 3/7] The "hostname" variable isn't used in the process classes. It should be removed from the other ones as well. --HG-- extra : convert_revision : 0c07534de42d6c32ac26d9e43709111e3ab30d57 --- src/arch/alpha/linux/process.hh | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/arch/alpha/linux/process.hh b/src/arch/alpha/linux/process.hh index 2076f6339..cb22f521b 100644 --- a/src/arch/alpha/linux/process.hh +++ b/src/arch/alpha/linux/process.hh @@ -53,9 +53,6 @@ class AlphaLinuxProcess : public AlphaLiveProcess virtual SyscallDesc* getDesc(int callnum); - /// The target system's hostname. - static const char *hostname; - /// Array of syscall descriptors, indexed by call number. static SyscallDesc syscallDescs[]; From 29e5df890d9512a6a2c726dcb4ee46b92ac4cb22 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 28 Feb 2007 16:36:38 +0000 Subject: [PATCH 4/7] Make trap instructions always generate TrapInstruction Fault objects which call into the Process object to handle system calls. Refactored the Process objects, and move the handler code into it's own file, and add some syscalls which are used in a natively compiled hello world. Software traps with trap number 3 (not syscall number 3) are supposed to cause the register windows to be flushed but are ignored right now. Finally, made uname for SPARC report a 2.6.12 kernel which is what m22-018.pool happens to be running. --HG-- extra : convert_revision : ea873f01c62234c0542f310cc143c6a7c76ade94 --- src/arch/sparc/faults.cc | 20 ++ src/arch/sparc/faults.hh | 5 +- src/arch/sparc/isa/decoder.isa | 10 - src/arch/sparc/linux/process.cc | 107 +++++--- src/arch/sparc/linux/process.hh | 55 ++++- src/arch/sparc/process.cc | 424 ++++++++++++++++++++++++-------- src/arch/sparc/process.hh | 122 +++++++-- src/base/loader/elf_object.cc | 9 +- src/base/loader/object_file.hh | 3 +- src/cpu/thread_context.hh | 5 + src/sim/process.cc | 27 +- src/sim/process.hh | 3 +- 12 files changed, 603 insertions(+), 187 deletions(-) diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc index a6f4343ae..391dd7134 100644 --- a/src/arch/sparc/faults.cc +++ b/src/arch/sparc/faults.cc @@ -656,6 +656,26 @@ void FillNNormal::invoke(ThreadContext *tc) tc->setNextNPC(fillStart + 2*sizeof(MachInst)); } +void TrapInstruction::invoke(ThreadContext *tc) +{ + //In SE, this mechanism is how the process requests a service from the + //operating system. We'll get the process object from the thread context + //and let it service the request. + + Process *p = tc->getProcessPtr(); + + SparcLiveProcess *lp = dynamic_cast(p); + assert(lp); + + lp->handleTrap(_n, tc); + + //We need to explicitly advance the pc, since that's not done for us + //on a faulting instruction + tc->setPC(tc->readNextPC()); + tc->setNextPC(tc->readNextNPC()); + tc->setNextNPC(tc->readNextNPC() + sizeof(MachInst)); +} + void PageTableFault::invoke(ThreadContext *tc) { Process *p = tc->getProcessPtr(); diff --git a/src/arch/sparc/faults.hh b/src/arch/sparc/faults.hh index 3c0d9674f..5facc081d 100644 --- a/src/arch/sparc/faults.hh +++ b/src/arch/sparc/faults.hh @@ -246,9 +246,12 @@ class FillNOther : public EnumeratedFault class TrapInstruction : public EnumeratedFault { - public: TrapInstruction(uint32_t n) : EnumeratedFault(n) {;} + //In SE, trap instructions are requesting services from the OS. +#if !FULL_SYSTEM + void invoke(ThreadContext * tc); +#endif }; #if !FULL_SYSTEM diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa index 2ce700ef1..50f0dd282 100644 --- a/src/arch/sparc/isa/decoder.isa +++ b/src/arch/sparc/isa/decoder.isa @@ -1064,27 +1064,17 @@ decode OP default Unknown::unknown() 0x0: Trap::tcci({{ if(passesCondition(Ccr<3:0>, COND2)) { -#if FULL_SYSTEM int lTrapNum = I ? (Rs1 + SW_TRAP) : (Rs1 + Rs2); DPRINTF(Sparc, "The trap number is %d\n", lTrapNum); fault = new TrapInstruction(lTrapNum); -#else - DPRINTF(Sparc, "The syscall number is %d\n", R1); - xc->syscall(R1); -#endif } }}, IsSerializeAfter, IsNonSpeculative); 0x2: Trap::tccx({{ if(passesCondition(Ccr<7:4>, COND2)) { -#if FULL_SYSTEM int lTrapNum = I ? (Rs1 + SW_TRAP) : (Rs1 + Rs2); DPRINTF(Sparc, "The trap number is %d\n", lTrapNum); fault = new TrapInstruction(lTrapNum); -#else - DPRINTF(Sparc, "The syscall number is %d\n", R1); - xc->syscall(R1); -#endif } }}, IsSerializeAfter, IsNonSpeculative); } diff --git a/src/arch/sparc/linux/process.cc b/src/arch/sparc/linux/process.cc index 565975fe0..9c7c0e643 100644 --- a/src/arch/sparc/linux/process.cc +++ b/src/arch/sparc/linux/process.cc @@ -54,7 +54,7 @@ unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process, strcpy(name->sysname, "Linux"); strcpy(name->nodename, "m5.eecs.umich.edu"); - strcpy(name->release, "2.4.20"); + strcpy(name->release, "2.6.12"); strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); strcpy(name->machine, "sparc"); @@ -141,7 +141,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = { /* 41 */ SyscallDesc("dup", unimplementedFunc), /* 42 */ SyscallDesc("pipe", pipePseudoFunc), /* 43 */ SyscallDesc("times", unimplementedFunc), - /* 44 */ SyscallDesc("getuid32", unimplementedFunc), + /* 44 */ SyscallDesc("getuid32", getuidFunc), /* 45 */ SyscallDesc("umount2", unimplementedFunc), /* 46 */ SyscallDesc("setgid", unimplementedFunc), /* 47 */ SyscallDesc("getgid", getgidFunc), @@ -150,7 +150,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = { /* 50 */ SyscallDesc("getegid", getegidFunc), /* 51 */ SyscallDesc("acct", unimplementedFunc), /* 52 */ SyscallDesc("memory_ordering", unimplementedFunc), - /* 53 */ SyscallDesc("getgid32", unimplementedFunc), + /* 53 */ SyscallDesc("getgid32", getgidFunc), /* 54 */ SyscallDesc("ioctl", unimplementedFunc), /* 55 */ SyscallDesc("reboot", unimplementedFunc), /* 56 */ SyscallDesc("mmap2", unimplementedFunc), @@ -160,14 +160,14 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = { /* 60 */ SyscallDesc("umask", unimplementedFunc), /* 61 */ SyscallDesc("chroot", unimplementedFunc), /* 62 */ SyscallDesc("fstat", fstatFunc), - /* 63 */ SyscallDesc("fstat64", unimplementedFunc), + /* 63 */ SyscallDesc("fstat64", fstatFunc), /* 64 */ SyscallDesc("getpagesize", unimplementedFunc), /* 65 */ SyscallDesc("msync", unimplementedFunc), /* 66 */ SyscallDesc("vfork", unimplementedFunc), /* 67 */ SyscallDesc("pread64", unimplementedFunc), /* 68 */ SyscallDesc("pwrite64", unimplementedFunc), - /* 69 */ SyscallDesc("geteuid32", unimplementedFunc), - /* 70 */ SyscallDesc("getdgid32", unimplementedFunc), + /* 69 */ SyscallDesc("geteuid32", geteuidFunc), + /* 70 */ SyscallDesc("getegid32", getegidFunc), /* 71 */ SyscallDesc("mmap", mmapFunc), /* 72 */ SyscallDesc("setreuid32", unimplementedFunc), /* 73 */ SyscallDesc("munmap", munmapFunc), @@ -184,7 +184,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = { /* 84 */ SyscallDesc("ftruncate64", unimplementedFunc), /* 85 */ SyscallDesc("swapon", unimplementedFunc), /* 86 */ SyscallDesc("getitimer", unimplementedFunc), - /* 87 */ SyscallDesc("setuid32", unimplementedFunc), + /* 87 */ SyscallDesc("setuid32", setuidFunc), /* 88 */ SyscallDesc("sethostname", unimplementedFunc), /* 89 */ SyscallDesc("setgid32", unimplementedFunc), /* 90 */ SyscallDesc("dup2", unimplementedFunc), @@ -383,30 +383,6 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = { /* 283 */ SyscallDesc("keyctl", unimplementedFunc) }; -SparcLinuxProcess::SparcLinuxProcess(const std::string &name, - ObjectFile *objFile, - System * system, - int stdin_fd, - int stdout_fd, - int stderr_fd, - std::vector &argv, - std::vector &envp, - const std::string &cwd, - uint64_t _uid, uint64_t _euid, - uint64_t _gid, uint64_t _egid, - uint64_t _pid, uint64_t _ppid) - : SparcLiveProcess(name, objFile, system, - stdin_fd, stdout_fd, stderr_fd, argv, envp, cwd, - _uid, _euid, _gid, _egid, _pid, _ppid), - Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) -{ - // The sparc syscall table must be <= 284 entries because that is all there - // is space for. - assert(Num_Syscall_Descs <= 284); -} - - - SyscallDesc* SparcLinuxProcess::getDesc(int callnum) { @@ -414,3 +390,72 @@ SparcLinuxProcess::getDesc(int callnum) return NULL; return &syscallDescs[callnum]; } + + + +SparcLinuxProcess::SparcLinuxProcess() : + Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) +{ + // The sparc syscall table must be <= 284 entries because that is all there + // is space for. + assert(Num_Syscall_Descs <= 284); +} + +Sparc32LinuxProcess::Sparc32LinuxProcess(const std::string &name, + ObjectFile *objFile, + System * system, + int stdin_fd, + int stdout_fd, + int stderr_fd, + std::vector &argv, + std::vector &envp, + const std::string &cwd, + uint64_t _uid, uint64_t _euid, + uint64_t _gid, uint64_t _egid, + uint64_t _pid, uint64_t _ppid) + : Sparc32LiveProcess(name, objFile, system, + stdin_fd, stdout_fd, stderr_fd, argv, envp, cwd, + _uid, _euid, _gid, _egid, _pid, _ppid) +{} + +void Sparc32LinuxProcess::handleTrap(int trapNum, ThreadContext *tc) +{ + switch(trapNum) + { + case 0x10: //Linux 32 bit syscall trap + tc->syscall(tc->readIntReg(1)); + break; + default: + SparcLiveProcess::handleTrap(trapNum, tc); + } +} + +Sparc64LinuxProcess::Sparc64LinuxProcess(const std::string &name, + ObjectFile *objFile, + System * system, + int stdin_fd, + int stdout_fd, + int stderr_fd, + std::vector &argv, + std::vector &envp, + const std::string &cwd, + uint64_t _uid, uint64_t _euid, + uint64_t _gid, uint64_t _egid, + uint64_t _pid, uint64_t _ppid) + : Sparc64LiveProcess(name, objFile, system, + stdin_fd, stdout_fd, stderr_fd, argv, envp, cwd, + _uid, _euid, _gid, _egid, _pid, _ppid) +{} + +void Sparc64LinuxProcess::handleTrap(int trapNum, ThreadContext *tc) +{ + switch(trapNum) + { + case 0x10: //Linux 32 bit syscall trap + case 0x6d: //Linux 64 bit syscall trap + tc->syscall(tc->readIntReg(1)); + break; + default: + SparcLiveProcess::handleTrap(trapNum, tc); + } +} diff --git a/src/arch/sparc/linux/process.hh b/src/arch/sparc/linux/process.hh index e212de973..e3373bb6b 100644 --- a/src/arch/sparc/linux/process.hh +++ b/src/arch/sparc/linux/process.hh @@ -38,12 +38,28 @@ namespace SparcISA { +//This contains all of the common elements of a SPARC Linux process which +//are not shared by other operating systems. The rest come from the common +//SPARC process class. +class SparcLinuxProcess +{ + public: + SparcLinuxProcess(); + + /// Array of syscall descriptors, indexed by call number. + static SyscallDesc syscallDescs[]; + + SyscallDesc* getDesc(int callnum); + + const int Num_Syscall_Descs; +}; + /// A process with emulated SPARC/Linux syscalls. -class SparcLinuxProcess : public SparcLiveProcess +class Sparc32LinuxProcess : public SparcLinuxProcess, public Sparc32LiveProcess { public: /// Constructor. - SparcLinuxProcess(const std::string &name, + Sparc32LinuxProcess(const std::string &name, ObjectFile *objFile, System * system, int stdin_fd, int stdout_fd, int stderr_fd, @@ -54,19 +70,40 @@ class SparcLinuxProcess : public SparcLiveProcess uint64_t _gid, uint64_t _egid, uint64_t _pid, uint64_t _ppid); - virtual SyscallDesc* getDesc(int callnum); + SyscallDesc* getDesc(int callnum) + { + return SparcLinuxProcess::getDesc(callnum); + } - /// The target system's hostname. - static const char *hostname; + void handleTrap(int trapNum, ThreadContext *tc); +}; - /// Array of syscall descriptors, indexed by call number. - static SyscallDesc syscallDescs[]; +/// A process with emulated 32 bit SPARC/Linux syscalls. +class Sparc64LinuxProcess : public SparcLinuxProcess, public Sparc64LiveProcess +{ + public: + /// Constructor. + Sparc64LinuxProcess(const std::string &name, + ObjectFile *objFile, + System * system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::vector &argv, + std::vector &envp, + const std::string &cwd, + uint64_t _uid, uint64_t _euid, + uint64_t _gid, uint64_t _egid, + uint64_t _pid, uint64_t _ppid); - const int Num_Syscall_Descs; + SyscallDesc* getDesc(int callnum) + { + return SparcLinuxProcess::getDesc(callnum); + } + + void handleTrap(int trapNum, ThreadContext *tc); }; SyscallReturn getresuidFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc); } // namespace SparcISA -#endif // __ALPHA_LINUX_PROCESS_HH__ +#endif // __SPARC_LINUX_PROCESS_HH__ diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc index 1e639b9a5..d5a95e0c0 100644 --- a/src/arch/sparc/process.cc +++ b/src/arch/sparc/process.cc @@ -30,6 +30,7 @@ */ #include "arch/sparc/asi.hh" +#include "arch/sparc/handlers.hh" #include "arch/sparc/isa_traits.hh" #include "arch/sparc/process.hh" #include "arch/sparc/types.hh" @@ -59,14 +60,6 @@ SparcLiveProcess::SparcLiveProcess(const std::string &nm, ObjectFile *objFile, brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize(); brk_point = roundUp(brk_point, VMPageSize); - // 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 region for mmaps. Tru64 seems to start just above 0 and - // grow up from there. - mmap_start = mmap_end = 0xfffff80000000000ULL; - // Set pointer for next thread stack. Reserve 8M for main stack. next_thread_stack_base = stack_base - (8 * 1024 * 1024); @@ -75,8 +68,62 @@ SparcLiveProcess::SparcLiveProcess(const std::string &nm, ObjectFile *objFile, spillStart = 0; } +void SparcLiveProcess::handleTrap(int trapNum, ThreadContext *tc) +{ + switch(trapNum) + { + case 0x03: //Flush window trap + warn("Ignoring request to flush register windows.\n"); + break; + default: + panic("Unimplemented trap to operating system: trap number %#x.\n", trapNum); + } +} + void -SparcLiveProcess::startup() +Sparc32LiveProcess::startup() +{ + argsInit(32 / 8, VMPageSize); + + //From the SPARC ABI + + //The process runs in user mode + threadContexts[0]->setMiscRegWithEffect(MISCREG_PSTATE, 0x02); + + //Setup default FP state + threadContexts[0]->setMiscReg(MISCREG_FSR, 0); + + threadContexts[0]->setMiscReg(MISCREG_TICK, 0); + // + /* + * Register window management registers + */ + + //No windows contain info from other programs + //threadContexts[0]->setMiscReg(MISCREG_OTHERWIN, 0); + threadContexts[0]->setIntReg(NumIntArchRegs + 6, 0); + //There are no windows to pop + //threadContexts[0]->setMiscReg(MISCREG_CANRESTORE, 0); + threadContexts[0]->setIntReg(NumIntArchRegs + 4, 0); + //All windows are available to save into + //threadContexts[0]->setMiscReg(MISCREG_CANSAVE, NWindows - 2); + threadContexts[0]->setIntReg(NumIntArchRegs + 3, NWindows - 2); + //All windows are "clean" + //threadContexts[0]->setMiscReg(MISCREG_CLEANWIN, NWindows); + threadContexts[0]->setIntReg(NumIntArchRegs + 5, NWindows); + //Start with register window 0 + threadContexts[0]->setMiscReg(MISCREG_CWP, 0); + //Always use spill and fill traps 0 + //threadContexts[0]->setMiscReg(MISCREG_WSTATE, 0); + threadContexts[0]->setIntReg(NumIntArchRegs + 7, 0); + //Set the trap level to 0 + threadContexts[0]->setMiscReg(MISCREG_TL, 0); + //Set the ASI register to something fixed + threadContexts[0]->setMiscReg(MISCREG_ASI, ASI_PRIMARY); +} + +void +Sparc64LiveProcess::startup() { argsInit(sizeof(IntReg), VMPageSize); @@ -117,94 +164,22 @@ SparcLiveProcess::startup() threadContexts[0]->setMiscReg(MISCREG_ASI, ASI_PRIMARY); } -m5_auxv_t buildAuxVect(int64_t type, int64_t val) +M5_32_auxv_t::M5_32_auxv_t(int32_t type, int32_t val) { - m5_auxv_t result; - result.a_type = TheISA::htog(type); - result.a_val = TheISA::htog(val); - return result; + a_type = TheISA::htog(type); + a_val = TheISA::htog(val); } -//We only use 19 instructions for the trap handlers, but there would be -//space for 32 in a real SPARC trap table. -const int numFillInsts = 32; -const int numSpillInsts = 32; - -MachInst fillHandler[numFillInsts] = +M5_64_auxv_t::M5_64_auxv_t(int64_t type, int64_t val) { - htog(0x87802018), //wr %g0, ASI_AIUP, %asi - htog(0xe0dba7ff), //ldxa [%sp + BIAS + (0*8)] %asi, %l0 - htog(0xe2dba807), //ldxa [%sp + BIAS + (1*8)] %asi, %l1 - htog(0xe4dba80f), //ldxa [%sp + BIAS + (2*8)] %asi, %l2 - htog(0xe6dba817), //ldxa [%sp + BIAS + (3*8)] %asi, %l3 - htog(0xe8dba81f), //ldxa [%sp + BIAS + (4*8)] %asi, %l4 - htog(0xeadba827), //ldxa [%sp + BIAS + (5*8)] %asi, %l5 - htog(0xecdba82f), //ldxa [%sp + BIAS + (6*8)] %asi, %l6 - htog(0xeedba837), //ldxa [%sp + BIAS + (7*8)] %asi, %l7 - htog(0xf0dba83f), //ldxa [%sp + BIAS + (8*8)] %asi, %i0 - htog(0xf2dba847), //ldxa [%sp + BIAS + (9*8)] %asi, %i1 - htog(0xf4dba84f), //ldxa [%sp + BIAS + (10*8)] %asi, %i2 - htog(0xf6dba857), //ldxa [%sp + BIAS + (11*8)] %asi, %i3 - htog(0xf8dba85f), //ldxa [%sp + BIAS + (12*8)] %asi, %i4 - htog(0xfadba867), //ldxa [%sp + BIAS + (13*8)] %asi, %i5 - htog(0xfcdba86f), //ldxa [%sp + BIAS + (14*8)] %asi, %i6 - htog(0xfedba877), //ldxa [%sp + BIAS + (15*8)] %asi, %i7 - htog(0x83880000), //restored - htog(0x83F00000), //retry - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000) //illtrap -}; - -MachInst spillHandler[numSpillInsts] = -{ - htog(0x87802018), //wr %g0, ASI_AIUP, %asi - htog(0xe0f3a7ff), //stxa %l0, [%sp + BIAS + (0*8)] %asi - htog(0xe2f3a807), //stxa %l1, [%sp + BIAS + (1*8)] %asi - htog(0xe4f3a80f), //stxa %l2, [%sp + BIAS + (2*8)] %asi - htog(0xe6f3a817), //stxa %l3, [%sp + BIAS + (3*8)] %asi - htog(0xe8f3a81f), //stxa %l4, [%sp + BIAS + (4*8)] %asi - htog(0xeaf3a827), //stxa %l5, [%sp + BIAS + (5*8)] %asi - htog(0xecf3a82f), //stxa %l6, [%sp + BIAS + (6*8)] %asi - htog(0xeef3a837), //stxa %l7, [%sp + BIAS + (7*8)] %asi - htog(0xf0f3a83f), //stxa %i0, [%sp + BIAS + (8*8)] %asi - htog(0xf2f3a847), //stxa %i1, [%sp + BIAS + (9*8)] %asi - htog(0xf4f3a84f), //stxa %i2, [%sp + BIAS + (10*8)] %asi - htog(0xf6f3a857), //stxa %i3, [%sp + BIAS + (11*8)] %asi - htog(0xf8f3a85f), //stxa %i4, [%sp + BIAS + (12*8)] %asi - htog(0xfaf3a867), //stxa %i5, [%sp + BIAS + (13*8)] %asi - htog(0xfcf3a86f), //stxa %i6, [%sp + BIAS + (14*8)] %asi - htog(0xfef3a877), //stxa %i7, [%sp + BIAS + (15*8)] %asi - htog(0x81880000), //saved - htog(0x83F00000), //retry - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000), //illtrap - htog(0x00000000) //illtrap -}; + a_type = TheISA::htog(type); + a_val = TheISA::htog(val); +} void -SparcLiveProcess::argsInit(int intSize, int pageSize) +Sparc64LiveProcess::argsInit(int intSize, int pageSize) { + typedef M5_64_auxv_t auxv_t; Process::startup(); string filename; @@ -265,34 +240,34 @@ SparcLiveProcess::argsInit(int intSize, int pageSize) if(elfObject) { //Bits which describe the system hardware capabilities - auxv.push_back(buildAuxVect(SPARC_AT_HWCAP, hwcap)); + auxv.push_back(auxv_t(SPARC_AT_HWCAP, hwcap)); //The system page size - auxv.push_back(buildAuxVect(SPARC_AT_PAGESZ, SparcISA::VMPageSize)); + auxv.push_back(auxv_t(SPARC_AT_PAGESZ, SparcISA::VMPageSize)); //Defined to be 100 in the kernel source. //Frequency at which times() increments - auxv.push_back(buildAuxVect(SPARC_AT_CLKTCK, 100)); + auxv.push_back(auxv_t(SPARC_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(buildAuxVect(SPARC_AT_PHDR, elfObject->programHeaderTable())); + auxv.push_back(auxv_t(SPARC_AT_PHDR, elfObject->programHeaderTable())); // This is the size of a program header entry from the elf file. - auxv.push_back(buildAuxVect(SPARC_AT_PHENT, elfObject->programHeaderSize())); + auxv.push_back(auxv_t(SPARC_AT_PHENT, elfObject->programHeaderSize())); // This is the number of program headers from the original elf file. - auxv.push_back(buildAuxVect(SPARC_AT_PHNUM, elfObject->programHeaderCount())); + auxv.push_back(auxv_t(SPARC_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(buildAuxVect(SPARC_AT_BASE, 0)); + 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(buildAuxVect(SPARC_AT_FLAGS, 0)); + auxv.push_back(auxv_t(SPARC_AT_FLAGS, 0)); //The entry point to the program - auxv.push_back(buildAuxVect(SPARC_AT_ENTRY, objFile->entryPoint())); + auxv.push_back(auxv_t(SPARC_AT_ENTRY, objFile->entryPoint())); //Different user and group IDs - auxv.push_back(buildAuxVect(SPARC_AT_UID, uid())); - auxv.push_back(buildAuxVect(SPARC_AT_EUID, euid())); - auxv.push_back(buildAuxVect(SPARC_AT_GID, gid())); - auxv.push_back(buildAuxVect(SPARC_AT_EGID, egid())); + 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())); //Whether to enable "secure mode" in the executable - auxv.push_back(buildAuxVect(SPARC_AT_SECURE, 0)); + auxv.push_back(auxv_t(SPARC_AT_SECURE, 0)); } //Figure out how big the initial stack needs to be @@ -419,8 +394,8 @@ SparcLiveProcess::argsInit(int intSize, int pageSize) int spillSize = sizeof(MachInst) * numSpillInsts; fillStart = stack_base; spillStart = fillStart + fillSize; - initVirtMem->writeBlob(fillStart, (uint8_t*)fillHandler, fillSize); - initVirtMem->writeBlob(spillStart, (uint8_t*)spillHandler, spillSize); + initVirtMem->writeBlob(fillStart, (uint8_t*)fillHandler64, fillSize); + initVirtMem->writeBlob(spillStart, (uint8_t*)spillHandler64, spillSize); //Set up the thread context to start running the process threadContexts[0]->setIntReg(ArgumentReg0, argc); @@ -437,3 +412,240 @@ SparcLiveProcess::argsInit(int intSize, int pageSize) // num_processes++; } + +void +Sparc32LiveProcess::argsInit(int intSize, int pageSize) +{ + typedef M5_32_auxv_t auxv_t; + Process::startup(); + + string filename; + if(argv.size() < 1) + filename = ""; + else + filename = argv[0]; + + Addr alignmentMask = ~(intSize - 1); + + // 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, + M5_HWCAP_SPARC_STBAR = 2, + M5_HWCAP_SPARC_SWAP = 4, + M5_HWCAP_SPARC_MULDIV = 8, + M5_HWCAP_SPARC_V9 = 16, + //This one should technically only be set + //if there is a cheetah or cheetah_plus tlb, + //but we'll use it all the time + M5_HWCAP_SPARC_ULTRA3 = 32 + }; + + const int64_t hwcap = + M5_HWCAP_SPARC_FLUSH | + M5_HWCAP_SPARC_STBAR | + M5_HWCAP_SPARC_SWAP | + M5_HWCAP_SPARC_MULDIV | + M5_HWCAP_SPARC_V9 | + M5_HWCAP_SPARC_ULTRA3; + + + //Setup the auxilliary vectors. These will already have endian conversion. + //Auxilliary vectors are loaded only for elf formatted executables. + ElfObject * elfObject = dynamic_cast(objFile); + if(elfObject) + { + //Bits which describe the system hardware capabilities + auxv.push_back(auxv_t(SPARC_AT_HWCAP, hwcap)); + //The system page size + auxv.push_back(auxv_t(SPARC_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)); + // 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())); + // This is the size of a program header entry from the elf file. + auxv.push_back(auxv_t(SPARC_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())); + //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)); + //The entry point to the program + auxv.push_back(auxv_t(SPARC_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())); + //Whether to enable "secure mode" in the executable + auxv.push_back(auxv_t(SPARC_AT_SECURE, 0)); + } + + //Figure out how big the initial stack needs to be + + // The unaccounted for 0 at the top of the stack + int mysterious_size = intSize; + + //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 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; + } + + //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 + + env_data_size + + arg_data_size + + intSize) & alignmentMask; + + int info_block_padding = + info_block_size - + file_name_size - + env_data_size - + arg_data_size; + + //Each auxilliary vector is two 8 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; + int window_save_size = intSize * 16; + + int space_needed = + mysterious_size + + info_block_size + + aux_array_size + + envp_array_size + + argv_array_size + + argc_size + + window_save_size; + + stack_min = stack_base - space_needed; + stack_min &= alignmentMask; + stack_size = stack_base - stack_min; + + // map memory + pTable->allocate(roundDown(stack_min, pageSize), + roundUp(stack_size, pageSize)); + + // map out initial stack contents + Addr mysterious_base = stack_base - mysterious_size; + 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 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; +#ifndef NDEBUG + // only used in DPRINTF + Addr window_save_base = argc_base - window_save_size; +#endif + + DPRINTF(Sparc, "The addresses of items on the initial stack:\n"); + DPRINTF(Sparc, "0x%x - file name\n", file_name_base); + DPRINTF(Sparc, "0x%x - env data\n", env_data_base); + DPRINTF(Sparc, "0x%x - arg data\n", arg_data_base); + DPRINTF(Sparc, "0x%x - auxv array\n", auxv_array_base); + DPRINTF(Sparc, "0x%x - envp array\n", envp_array_base); + DPRINTF(Sparc, "0x%x - argv array\n", argv_array_base); + DPRINTF(Sparc, "0x%x - argc \n", argc_base); + DPRINTF(Sparc, "0x%x - window save\n", window_save_base); + DPRINTF(Sparc, "0x%x - stack min\n", stack_min); + + // write contents to stack + + // figure out argc + uint32_t argc = argv.size(); + uint32_t guestArgc = TheISA::htog(argc); + + //Write out the mysterious 0 + uint64_t mysterious_zero = 0; + initVirtMem->writeBlob(mysterious_base, + (uint8_t*)&mysterious_zero, mysterious_size); + + //Write the file name + initVirtMem->writeString(file_name_base, filename.c_str()); + + //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); + + copyStringArray(envp, envp_array_base, env_data_base, initVirtMem, intSize); + copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem, intSize); + + initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize); + + //Stuff the trap handlers into the processes address space. + //Since the stack grows down and is the highest area in the processes + //address space, we can put stuff above it and stay out of the way. + int fillSize = sizeof(MachInst) * numFillInsts; + int spillSize = sizeof(MachInst) * numSpillInsts; + fillStart = stack_base; + spillStart = fillStart + fillSize; + initVirtMem->writeBlob(fillStart, (uint8_t*)fillHandler32, fillSize); + initVirtMem->writeBlob(spillStart, (uint8_t*)spillHandler32, spillSize); + + //Set up the thread context to start running the process + threadContexts[0]->setIntReg(ArgumentReg0, argc); + threadContexts[0]->setIntReg(ArgumentReg1, argv_array_base); + threadContexts[0]->setIntReg(StackPointerReg, stack_min); + + Addr prog_entry = objFile->entryPoint(); + threadContexts[0]->setPC(prog_entry); + threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst)); + threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst))); + + //Align the "stack_min" to a page boundary. + stack_min = roundDown(stack_min, pageSize); + +// num_processes++; +} diff --git a/src/arch/sparc/process.hh b/src/arch/sparc/process.hh index 1cf7ec224..2512441c6 100644 --- a/src/arch/sparc/process.hh +++ b/src/arch/sparc/process.hh @@ -39,27 +39,13 @@ class ObjectFile; class System; -typedef struct -{ - int64_t a_type; - union { - int64_t a_val; - Addr a_ptr; - Addr a_fcn; - }; -} m5_auxv_t; - class SparcLiveProcess : public LiveProcess { protected: - static const Addr StackBias = 2047; - //The locations of the fill and spill handlers Addr fillStart, spillStart; - std::vector auxv; - SparcLiveProcess(const std::string &nm, ObjectFile *objFile, System *_system, int stdin_fd, int stdout_fd, int stderr_fd, std::vector &argv, @@ -69,11 +55,10 @@ class SparcLiveProcess : public LiveProcess uint64_t _gid, uint64_t _egid, uint64_t _pid, uint64_t _ppid); - void startup(); - public: - void argsInit(int intSize, int pageSize); + //Handles traps which request services from the operating system + virtual void handleTrap(int trapNum, ThreadContext *tc); Addr readFillStart() { return fillStart; } @@ -83,4 +68,107 @@ class SparcLiveProcess : public LiveProcess }; +struct M5_32_auxv_t +{ + int32_t a_type; + union { + int32_t a_val; + int32_t a_ptr; + int32_t a_fcn; + }; + + M5_32_auxv_t() + {} + + M5_32_auxv_t(int32_t type, int32_t val); +}; + +class Sparc32LiveProcess : public SparcLiveProcess +{ + protected: + + std::vector auxv; + + Sparc32LiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector &argv, + std::vector &envp, + const std::string &cwd, + uint64_t _uid, uint64_t _euid, + uint64_t _gid, uint64_t _egid, + uint64_t _pid, uint64_t _ppid) : + SparcLiveProcess(nm, objFile, _system, + stdin_fd, stdout_fd, stderr_fd, + argv, envp, cwd, + _uid, _euid, _gid, _egid, _pid, _ppid) + { + // 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)0xf0000000ULL; + + // Set up region for mmaps. + mmap_start = mmap_end = 0x70000000; + } + + void startup(); + + public: + + void argsInit(int intSize, int pageSize); + +}; + +struct M5_64_auxv_t +{ + int64_t a_type; + union { + int64_t a_val; + int64_t a_ptr; + int64_t a_fcn; + }; + + M5_64_auxv_t() + {} + + M5_64_auxv_t(int64_t type, int64_t val); +}; + +class Sparc64LiveProcess : public SparcLiveProcess +{ + protected: + + static const Addr StackBias = 2047; + + std::vector auxv; + + Sparc64LiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector &argv, + std::vector &envp, + const std::string &cwd, + uint64_t _uid, uint64_t _euid, + uint64_t _gid, uint64_t _egid, + uint64_t _pid, uint64_t _ppid) : + SparcLiveProcess(nm, objFile, _system, + stdin_fd, stdout_fd, stderr_fd, + argv, envp, cwd, + _uid, _euid, _gid, _egid, _pid, _ppid) + { + // 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 region for mmaps. Tru64 seems to start just above 0 and + // grow up from there. + mmap_start = mmap_end = 0xfffff80000000000ULL; + } + + void startup(); + + public: + + void argsInit(int intSize, int pageSize); + +}; + #endif // __SPARC_PROCESS_HH__ diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc index d59affe85..b56dc5aa6 100644 --- a/src/base/loader/elf_object.cc +++ b/src/base/loader/elf_object.cc @@ -78,9 +78,14 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) //just assume if it wasn't something else and it's 64 bit, that's //what it must be. if (ehdr.e_machine == EM_SPARC64 || - ehdr.e_machine == EM_SPARC || + (ehdr.e_machine == EM_SPARC && + ehdr.e_ident[EI_CLASS] == ELFCLASS64)|| ehdr.e_machine == EM_SPARCV9) { - arch = ObjectFile::SPARC; + arch = ObjectFile::SPARC64; + } else if (ehdr.e_machine == EM_SPARC32PLUS || + (ehdr.e_machine == EM_SPARC && + ehdr.e_ident[EI_CLASS] == ELFCLASS32)) { + arch = ObjectFile::SPARC32; } else if (ehdr.e_machine == EM_MIPS && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { arch = ObjectFile::Mips; diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh index 18e6482be..49c7363e6 100644 --- a/src/base/loader/object_file.hh +++ b/src/base/loader/object_file.hh @@ -47,7 +47,8 @@ class ObjectFile enum Arch { UnknownArch, Alpha, - SPARC, + SPARC64, + SPARC32, Mips }; diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh index 16e491fd3..a24dc49da 100644 --- a/src/cpu/thread_context.hh +++ b/src/cpu/thread_context.hh @@ -254,6 +254,8 @@ class ThreadContext // Same with st cond failures. virtual Counter readFuncExeInst() = 0; + virtual void syscall(int64_t callnum) = 0; + // This function exits the thread context in the CPU and returns // 1 if the CPU has no more active threads (meaning it's OK to exit); // Used in syscall-emulation mode when a thread calls the exit syscall. @@ -441,6 +443,9 @@ class ProxyThreadContext : public ThreadContext void setSyscallReturn(SyscallReturn return_value) { actualTC->setSyscallReturn(return_value); } + void syscall(int64_t callnum) + { actualTC->syscall(callnum); } + Counter readFuncExeInst() { return actualTC->readFuncExeInst(); } #endif diff --git a/src/sim/process.cc b/src/sim/process.cc index e5d868115..acc509a6f 100644 --- a/src/sim/process.cc +++ b/src/sim/process.cc @@ -302,20 +302,20 @@ DEFINE_SIM_OBJECT_CLASS_NAME("Process", Process) void copyStringArray(vector &strings, Addr array_ptr, Addr data_ptr, - TranslatingPort* memPort) + TranslatingPort* memPort, int ptr_size) { Addr data_ptr_swap; for (int i = 0; i < strings.size(); ++i) { data_ptr_swap = htog(data_ptr); - memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr_swap, sizeof(Addr)); + memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr_swap, ptr_size); memPort->writeString(data_ptr, strings[i].c_str()); - array_ptr += sizeof(Addr); + array_ptr += ptr_size; data_ptr += strings[i].size() + 1; } // add NULL terminator data_ptr = 0; - memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr, sizeof(Addr)); + memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr, ptr_size); } LiveProcess::LiveProcess(const string &nm, ObjectFile *_objFile, @@ -475,14 +475,23 @@ LiveProcess::create(const std::string &nm, System *system, int stdin_fd, fatal("Unknown/unsupported operating system."); } #elif THE_ISA == SPARC_ISA - if (objFile->getArch() != ObjectFile::SPARC) + if (objFile->getArch() != ObjectFile::SPARC64 && objFile->getArch() != ObjectFile::SPARC32) fatal("Object file architecture does not match compiled ISA (SPARC)."); switch (objFile->getOpSys()) { case ObjectFile::Linux: - process = new SparcLinuxProcess(nm, objFile, system, - stdin_fd, stdout_fd, stderr_fd, - argv, envp, cwd, - _uid, _euid, _gid, _egid, _pid, _ppid); + if (objFile->getArch() == ObjectFile::SPARC64) { + process = new Sparc64LinuxProcess(nm, objFile, system, + stdin_fd, stdout_fd, stderr_fd, + argv, envp, cwd, + _uid, _euid, _gid, + _egid, _pid, _ppid); + } else { + process = new Sparc32LinuxProcess(nm, objFile, system, + stdin_fd, stdout_fd, stderr_fd, + argv, envp, cwd, + _uid, _euid, _gid, + _egid, _pid, _ppid); + } break; diff --git a/src/sim/process.hh b/src/sim/process.hh index bf65c6e06..1226db81b 100644 --- a/src/sim/process.hh +++ b/src/sim/process.hh @@ -44,6 +44,7 @@ #include #include "base/statistics.hh" +#include "sim/host.hh" #include "sim/sim_object.hh" class ThreadContext; @@ -59,7 +60,7 @@ namespace TheISA void copyStringArray(std::vector &strings, Addr array_ptr, - Addr data_ptr, TranslatingPort* memPort); + Addr data_ptr, TranslatingPort* memPort, int ptr_size = sizeof(Addr)); class Process : public SimObject { From ececf101c7e6bfcf06bd9a8b54cc0fabaea84205 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 28 Feb 2007 16:49:17 +0000 Subject: [PATCH 5/7] Make the m5 psuedo instructions use the BasicOperate format --HG-- extra : convert_revision : f02da702ab9b99da124fac7e10a07386b04f3a0f --- src/arch/sparc/isa/decoder.isa | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa index 3b84e3073..36b9d1caa 100644 --- a/src/arch/sparc/isa/decoder.isa +++ b/src/arch/sparc/isa/decoder.isa @@ -1012,17 +1012,19 @@ decode OP default Unknown::unknown() // M5 special opcodes use the reserved IMPDEP2A opcode space 0x37: decode M5FUNC { #if FULL_SYSTEM - // we have 7 bits of space here to play with... - 0x21: m5exit({{PseudoInst::m5exit(xc->tcBase(), O0); - }}, No_OpClass, IsNonSpeculative); - 0x50: m5readfile({{ - O0 = PseudoInst::readfile(xc->tcBase(), O0, O1, O2); - }}, IsNonSpeculative); - 0x51: m5break({{PseudoInst::debugbreak(xc->tcBase()); - }}, IsNonSpeculative); - 0x54: m5panic({{ - panic("M5 panic instruction called at pc=%#x.", xc->readPC()); - }}, No_OpClass, IsNonSpeculative); + format BasicOperate { + // we have 7 bits of space here to play with... + 0x21: m5exit({{PseudoInst::m5exit(xc->tcBase(), O0); + }}, No_OpClass, IsNonSpeculative); + 0x50: m5readfile({{ + O0 = PseudoInst::readfile(xc->tcBase(), O0, O1, O2); + }}, IsNonSpeculative); + 0x51: m5break({{PseudoInst::debugbreak(xc->tcBase()); + }}, IsNonSpeculative); + 0x54: m5panic({{ + panic("M5 panic instruction called at pc=%#x.", xc->readPC()); + }}, No_OpClass, IsNonSpeculative); + } #endif default: Trap::impdep2({{fault = new IllegalInstruction;}}); } From d8ada247f4fb107e7dc530ceb96a624d46c8ed9a Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Fri, 2 Mar 2007 14:43:27 +0000 Subject: [PATCH 6/7] Forgot to commit this new file last earlier. --HG-- extra : convert_revision : f2d80ae551b7e29426141d5c9fe355b43a0b9c7d --- src/arch/sparc/handlers.hh | 190 +++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 src/arch/sparc/handlers.hh diff --git a/src/arch/sparc/handlers.hh b/src/arch/sparc/handlers.hh new file mode 100644 index 000000000..ce5b69427 --- /dev/null +++ b/src/arch/sparc/handlers.hh @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2003-2004 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_SPARC_HANDLERS_HH__ +#define __ARCH_SPARC_HANDLERS_HH__ + +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/types.hh" +#include "sim/byteswap.hh" + +namespace SparcISA { + +//We only use 19 instructions for the trap handlers, but there would be +//space for 32 in a real SPARC trap table. +const int numFillInsts = 32; +const int numSpillInsts = 32; + +const MachInst fillHandler64[numFillInsts] = +{ + htog(0x87802018), //wr %g0, ASI_AIUP, %asi + htog(0xe0dba7ff), //ldxa [%sp + BIAS + (0*8)] %asi, %l0 + htog(0xe2dba807), //ldxa [%sp + BIAS + (1*8)] %asi, %l1 + htog(0xe4dba80f), //ldxa [%sp + BIAS + (2*8)] %asi, %l2 + htog(0xe6dba817), //ldxa [%sp + BIAS + (3*8)] %asi, %l3 + htog(0xe8dba81f), //ldxa [%sp + BIAS + (4*8)] %asi, %l4 + htog(0xeadba827), //ldxa [%sp + BIAS + (5*8)] %asi, %l5 + htog(0xecdba82f), //ldxa [%sp + BIAS + (6*8)] %asi, %l6 + htog(0xeedba837), //ldxa [%sp + BIAS + (7*8)] %asi, %l7 + htog(0xf0dba83f), //ldxa [%sp + BIAS + (8*8)] %asi, %i0 + htog(0xf2dba847), //ldxa [%sp + BIAS + (9*8)] %asi, %i1 + htog(0xf4dba84f), //ldxa [%sp + BIAS + (10*8)] %asi, %i2 + htog(0xf6dba857), //ldxa [%sp + BIAS + (11*8)] %asi, %i3 + htog(0xf8dba85f), //ldxa [%sp + BIAS + (12*8)] %asi, %i4 + htog(0xfadba867), //ldxa [%sp + BIAS + (13*8)] %asi, %i5 + htog(0xfcdba86f), //ldxa [%sp + BIAS + (14*8)] %asi, %i6 + htog(0xfedba877), //ldxa [%sp + BIAS + (15*8)] %asi, %i7 + htog(0x83880000), //restored + htog(0x83F00000), //retry + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000) //illtrap +}; + +const MachInst fillHandler32[numFillInsts] = +{ + htog(0x87802018), //wr %g0, ASI_AIUP, %asi + htog(0xe083a000), //lduwa [%sp + (0*4)] %asi, %l0 + htog(0xe283a004), //lduwa [%sp + (1*4)] %asi, %l1 + htog(0xe483a008), //lduwa [%sp + (2*4)] %asi, %l2 + htog(0xe683a00c), //lduwa [%sp + (3*4)] %asi, %l3 + htog(0xe883a010), //lduwa [%sp + (4*4)] %asi, %l4 + htog(0xea83a014), //lduwa [%sp + (5*4)] %asi, %l5 + htog(0xec83a018), //lduwa [%sp + (6*4)] %asi, %l6 + htog(0xee83a01c), //lduwa [%sp + (7*4)] %asi, %l7 + htog(0xf083a020), //lduwa [%sp + (8*4)] %asi, %i0 + htog(0xf283a024), //lduwa [%sp + (9*4)] %asi, %i1 + htog(0xf483a028), //lduwa [%sp + (10*4)] %asi, %i2 + htog(0xf683a02c), //lduwa [%sp + (11*4)] %asi, %i3 + htog(0xf883a030), //lduwa [%sp + (12*4)] %asi, %i4 + htog(0xfa83a034), //lduwa [%sp + (13*4)] %asi, %i5 + htog(0xfc83a038), //lduwa [%sp + (14*4)] %asi, %i6 + htog(0xfe83a03c), //lduwa [%sp + (15*4)] %asi, %i7 + htog(0x83880000), //restored + htog(0x83F00000), //retry + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000) //illtrap +}; + +const MachInst spillHandler64[numSpillInsts] = +{ + htog(0x87802018), //wr %g0, ASI_AIUP, %asi + htog(0xe0f3a7ff), //stxa %l0, [%sp + BIAS + (0*8)] %asi + htog(0xe2f3a807), //stxa %l1, [%sp + BIAS + (1*8)] %asi + htog(0xe4f3a80f), //stxa %l2, [%sp + BIAS + (2*8)] %asi + htog(0xe6f3a817), //stxa %l3, [%sp + BIAS + (3*8)] %asi + htog(0xe8f3a81f), //stxa %l4, [%sp + BIAS + (4*8)] %asi + htog(0xeaf3a827), //stxa %l5, [%sp + BIAS + (5*8)] %asi + htog(0xecf3a82f), //stxa %l6, [%sp + BIAS + (6*8)] %asi + htog(0xeef3a837), //stxa %l7, [%sp + BIAS + (7*8)] %asi + htog(0xf0f3a83f), //stxa %i0, [%sp + BIAS + (8*8)] %asi + htog(0xf2f3a847), //stxa %i1, [%sp + BIAS + (9*8)] %asi + htog(0xf4f3a84f), //stxa %i2, [%sp + BIAS + (10*8)] %asi + htog(0xf6f3a857), //stxa %i3, [%sp + BIAS + (11*8)] %asi + htog(0xf8f3a85f), //stxa %i4, [%sp + BIAS + (12*8)] %asi + htog(0xfaf3a867), //stxa %i5, [%sp + BIAS + (13*8)] %asi + htog(0xfcf3a86f), //stxa %i6, [%sp + BIAS + (14*8)] %asi + htog(0xfef3a877), //stxa %i7, [%sp + BIAS + (15*8)] %asi + htog(0x81880000), //saved + htog(0x83F00000), //retry + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000) //illtrap +}; + +const MachInst spillHandler32[numSpillInsts] = +{ + htog(0x87802018), //wr %g0, ASI_AIUP, %asi + htog(0xe0a3a000), //stwa %l0, [%sp + (0*4)] %asi + htog(0xe2a3a004), //stwa %l1, [%sp + (1*4)] %asi + htog(0xe4a3a008), //stwa %l2, [%sp + (2*4)] %asi + htog(0xe6a3a00c), //stwa %l3, [%sp + (3*4)] %asi + htog(0xe8a3a010), //stwa %l4, [%sp + (4*4)] %asi + htog(0xeaa3a014), //stwa %l5, [%sp + (5*4)] %asi + htog(0xeca3a018), //stwa %l6, [%sp + (6*4)] %asi + htog(0xeea3a01c), //stwa %l7, [%sp + (7*4)] %asi + htog(0xf0a3a020), //stwa %i0, [%sp + (8*4)] %asi + htog(0xf2a3a024), //stwa %i1, [%sp + (9*4)] %asi + htog(0xf4a3a028), //stwa %i2, [%sp + (10*4)] %asi + htog(0xf6a3a02c), //stwa %i3, [%sp + (11*4)] %asi + htog(0xf8a3a030), //stwa %i4, [%sp + (12*4)] %asi + htog(0xfaa3a034), //stwa %i5, [%sp + (13*4)] %asi + htog(0xfca3a038), //stwa %i6, [%sp + (14*4)] %asi + htog(0xfea3a03c), //stwa %i7, [%sp + (15*4)] %asi + htog(0x81880000), //saved + htog(0x83F00000), //retry + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000), //illtrap + htog(0x00000000) //illtrap +}; + +} // namespace SparcISA +#endif // __ARCH_SPARC_HANDLERS_HH__ From 4e8d2d1593475008b926829e6944a59963166079 Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Fri, 2 Mar 2007 22:34:51 -0500 Subject: [PATCH 7/7] make ldtw(a) -- Twin 32 bit load work correctly -- by doing it the same way as the twin 64 bit loads src/arch/isa_parser.py: src/arch/sparc/isa/decoder.isa: src/arch/sparc/isa/operands.isa: src/base/bigint.hh: src/cpu/simple/atomic.cc: src/cpu/simple/timing.cc: src/mem/packet_access.hh: make ldtw(a) Twin 32 bit load work correctly --HG-- extra : convert_revision : 2646b269d58cc1774e896065875a56cf5e313b42 --- src/arch/isa_parser.py | 9 ++++++--- src/arch/sparc/isa/decoder.isa | 10 ++++------ src/arch/sparc/isa/operands.isa | 3 ++- src/base/bigint.hh | 13 +++++++++++++ src/cpu/simple/atomic.cc | 4 ++++ src/cpu/simple/timing.cc | 4 ++++ src/mem/packet_access.hh | 12 ++++++++++++ 7 files changed, 45 insertions(+), 10 deletions(-) diff --git a/src/arch/isa_parser.py b/src/arch/isa_parser.py index 39500df36..9b63c8842 100755 --- a/src/arch/isa_parser.py +++ b/src/arch/isa_parser.py @@ -1124,9 +1124,12 @@ def buildOperandTypeMap(userDict, lineno): ctype = 'float' elif size == 64: ctype = 'double' - elif desc == 'twin int': + elif desc == 'twin64 int': is_signed = 0 ctype = 'Twin64_t' + elif desc == 'twin32 int': + is_signed = 0 + ctype = 'Twin32_t' if ctype == '': error(lineno, 'Unrecognized type description "%s" in userDict') operandTypeMap[ext] = (size, ctype, is_signed) @@ -1159,7 +1162,7 @@ class Operand(object): # template must be careful not to use it if it doesn't apply. if self.isMem(): self.mem_acc_size = self.makeAccSize() - if self.ctype == 'Twin64_t': + if self.ctype in ['Twin32_t', 'Twin64_t']: self.mem_acc_type = 'Twin' else: self.mem_acc_type = 'uint' @@ -1392,7 +1395,7 @@ class MemOperand(Operand): # Note that initializations in the declarations are solely # to avoid 'uninitialized variable' errors from the compiler. # Declare memory data variable. - if self.ctype == 'Twin64_t': + if self.ctype in ['Twin32_t','Twin64_t']: return "%s %s; %s.a = 0; %s.b = 0;\n" % (self.ctype, self.base_name, self.base_name, self.base_name) c = '%s %s = 0;\n' % (self.ctype, self.base_name) diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa index 36b9d1caa..2e85e1274 100644 --- a/src/arch/sparc/isa/decoder.isa +++ b/src/arch/sparc/isa/decoder.isa @@ -1160,9 +1160,8 @@ decode OP default Unknown::unknown() 0x01: ldub({{Rd = Mem.ub;}}); 0x02: lduh({{Rd = Mem.uhw;}}); 0x03: ldtw({{ - uint64_t val = Mem.udw; - RdLow = val<31:0>; - RdHigh = val<63:32>; + RdLow = (Mem.tuw).a; + RdHigh = (Mem.tuw).b; }}); } format Store { @@ -1250,9 +1249,8 @@ decode OP default Unknown::unknown() {{RdLow.udw = (Mem.tudw).a; RdHigh.udw = (Mem.tudw).b;}}, {{EXT_ASI}}); default: ldtwa({{ - uint64_t val = Mem.udw; - RdLow = val<31:0>; - RdHigh = val<63:32>; + RdLow = (Mem.tuw).a; + RdHigh = (Mem.tuw).b; }}, {{EXT_ASI}}); } } diff --git a/src/arch/sparc/isa/operands.isa b/src/arch/sparc/isa/operands.isa index 092544aab..038919bd1 100644 --- a/src/arch/sparc/isa/operands.isa +++ b/src/arch/sparc/isa/operands.isa @@ -37,7 +37,8 @@ def operand_types {{ 'uw' : ('unsigned int', 32), 'sdw' : ('signed int', 64), 'udw' : ('unsigned int', 64), - 'tudw' : ('twin int', 64), + 'tudw' : ('twin64 int', 64), + 'tuw' : ('twin32 int', 32), 'sf' : ('float', 32), 'df' : ('float', 64), 'qf' : ('float', 128) diff --git a/src/base/bigint.hh b/src/base/bigint.hh index aa60eeb04..d533e662a 100644 --- a/src/base/bigint.hh +++ b/src/base/bigint.hh @@ -42,9 +42,22 @@ struct m5_twin64_t { } }; +struct m5_twin32_t { + uint32_t a; + uint32_t b; + inline m5_twin32_t& operator=(const uint32_t x) + { + a = x; + b = x; + return *this; + } +}; + + // This is for twin loads (two 64 bit values), not 1 128 bit value (as far as // endian conversion is concerned! typedef m5_twin64_t Twin64_t; +typedef m5_twin32_t Twin32_t; #endif // __BASE_BIGINT_HH__ diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 3001241fe..df7e780e6 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -319,6 +319,10 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) #ifndef DOXYGEN_SHOULD_SKIP_THIS +template +Fault +AtomicSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); + template Fault AtomicSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index ff3606a74..7f857c68d 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -315,6 +315,10 @@ template Fault TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags); +template +Fault +TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags); + template Fault TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); diff --git a/src/mem/packet_access.hh b/src/mem/packet_access.hh index 882aa98d0..552b6dd27 100644 --- a/src/mem/packet_access.hh +++ b/src/mem/packet_access.hh @@ -53,6 +53,18 @@ Packet::get() return d; } +template<> +inline Twin32_t +Packet::get() +{ + Twin32_t d; + assert(staticData || dynamicData); + assert(sizeof(Twin32_t) <= size); + d.a = TheISA::gtoh(*(uint32_t*)data); + d.b = TheISA::gtoh(*((uint32_t*)data + 1)); + return d; +} + /** return the value of what is pointed to in the packet. */ template