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
This commit is contained in:
Gabe Black 2007-02-28 16:36:38 +00:00
parent 99948060b2
commit 29e5df890d
12 changed files with 603 additions and 187 deletions

View file

@ -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<SparcLiveProcess *>(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();

View file

@ -246,9 +246,12 @@ class FillNOther : public EnumeratedFault<FillNOther>
class TrapInstruction : public EnumeratedFault<TrapInstruction>
{
public:
TrapInstruction(uint32_t n) : EnumeratedFault<TrapInstruction>(n) {;}
//In SE, trap instructions are requesting services from the OS.
#if !FULL_SYSTEM
void invoke(ThreadContext * tc);
#endif
};
#if !FULL_SYSTEM

View file

@ -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);
}

View file

@ -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<SparcLinux>),
/* 63 */ SyscallDesc("fstat64", unimplementedFunc),
/* 63 */ SyscallDesc("fstat64", fstatFunc<SparcLinux>),
/* 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<SparcLinux>),
/* 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<std::string> &argv,
std::vector<std::string> &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<std::string> &argv,
std::vector<std::string> &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<std::string> &argv,
std::vector<std::string> &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);
}
}

View file

@ -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<std::string> &argv,
std::vector<std::string> &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__

View file

@ -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<ElfObject *>(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++;
}

View file

@ -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<m5_auxv_t> auxv;
SparcLiveProcess(const std::string &nm, ObjectFile *objFile,
System *_system, int stdin_fd, int stdout_fd, int stderr_fd,
std::vector<std::string> &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<M5_32_auxv_t> auxv;
Sparc32LiveProcess(const std::string &nm, ObjectFile *objFile,
System *_system, int stdin_fd, int stdout_fd, int stderr_fd,
std::vector<std::string> &argv,
std::vector<std::string> &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<M5_64_auxv_t> auxv;
Sparc64LiveProcess(const std::string &nm, ObjectFile *objFile,
System *_system, int stdin_fd, int stdout_fd, int stderr_fd,
std::vector<std::string> &argv,
std::vector<std::string> &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__

View file

@ -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;

View file

@ -47,7 +47,8 @@ class ObjectFile
enum Arch {
UnknownArch,
Alpha,
SPARC,
SPARC64,
SPARC32,
Mips
};

View file

@ -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

View file

@ -302,20 +302,20 @@ DEFINE_SIM_OBJECT_CLASS_NAME("Process", Process)
void
copyStringArray(vector<string> &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;

View file

@ -44,6 +44,7 @@
#include <vector>
#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<std::string> &strings, Addr array_ptr,
Addr data_ptr, TranslatingPort* memPort);
Addr data_ptr, TranslatingPort* memPort, int ptr_size = sizeof(Addr));
class Process : public SimObject
{