/* 309 */ SyscallDesc("get_kernel_syms", unimplementedFunc),
/* 310 */ SyscallDesc("syslog", unimplementedFunc),
/* 311 */ SyscallDesc("reboot", unimplementedFunc),
- /* 312 */ SyscallDesc("clone", cloneFunc),
+ /* 312 */ SyscallDesc("clone", cloneFunc<AlphaLinux>),
/* 313 */ SyscallDesc("uselib", unimplementedFunc),
/* 314 */ SyscallDesc("mlock", unimplementedFunc),
/* 315 */ SyscallDesc("munlock", unimplementedFunc),
AlphaProcess::AlphaProcess(ProcessParams *params, ObjectFile *objFile)
: Process(params, objFile)
{
- brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
- brk_point = roundUp(brk_point, PageBytes);
+ memState->brkPoint = objFile->dataBase() + objFile->dataSize() +
+ objFile->bssSize();
+ memState->brkPoint = roundUp(memState->brkPoint, PageBytes);
// Set up stack. On Alpha, stack goes below text section. This
// code should get moved to some architecture-specific spot.
- stack_base = objFile->textBase() - (409600+4096);
+ memState->stackBase = objFile->textBase() - (409600+4096);
// Set up region for mmaps. Tru64 seems to start just above 0 and
// grow up from there.
- mmap_end = 0x10000;
+ memState->mmapEnd = 0x10000;
// Set pointer for next thread stack. Reserve 8M for main stack.
- next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+ memState->nextThreadStackBase = memState->stackBase - (8 * 1024 * 1024);
}
space_needed = 32*1024;
// set bottom of stack
- stack_min = stack_base - space_needed;
+ memState->stackMin = memState->stackBase - space_needed;
// align it
- stack_min = roundDown(stack_min, pageSize);
- stack_size = stack_base - stack_min;
+ memState->stackMin = roundDown(memState->stackMin, pageSize);
+ memState->stackSize = memState->stackBase - memState->stackMin;
// map memory
- allocateMem(stack_min, roundUp(stack_size, pageSize));
+ allocateMem(memState->stackMin, roundUp(memState->stackSize, pageSize));
// map out initial stack contents
- Addr argv_array_base = stack_min + intSize; // room for argc
+ Addr argv_array_base = memState->stackMin + intSize; // room for argc
Addr envp_array_base = argv_array_base + argv_array_size;
Addr auxv_array_base = envp_array_base + envp_array_size;
Addr arg_data_base = auxv_array_base + auxv_array_size;
else
panic("Unknown int size");
- initVirtMem.writeBlob(stack_min, (uint8_t*)&argc, intSize);
+ initVirtMem.writeBlob(memState->stackMin, (uint8_t*)&argc, intSize);
copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
setSyscallArg(tc, 0, argc);
setSyscallArg(tc, 1, argv_array_base);
- tc->setIntReg(StackPointerReg, stack_min);
+ tc->setIntReg(StackPointerReg, memState->stackMin);
tc->pcState(getStartPC());
}
/* 117 */ SyscallDesc("ipc", unimplementedFunc),
/* 118 */ SyscallDesc("fsync", unimplementedFunc),
/* 119 */ SyscallDesc("sigreturn", unimplementedFunc),
- /* 120 */ SyscallDesc("clone", cloneFunc),
+ /* 120 */ SyscallDesc("clone", cloneFunc<ArmLinux32>),
/* 121 */ SyscallDesc("setdomainname", unimplementedFunc),
/* 122 */ SyscallDesc("uname", unameFunc32),
/* 123 */ SyscallDesc("unused#123", unimplementedFunc),
ObjectFile::Arch _arch)
: ArmProcess(params, objFile, _arch)
{
- stack_base = 0xbf000000L;
+ memState->stackBase = 0xbf000000L;
// Set pointer for next thread stack. Reserve 8M for main stack.
- next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+ memState->nextThreadStackBase = memState->stackBase - (8 * 1024 * 1024);
// Set up break point (Top of Heap)
- brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
- brk_point = roundUp(brk_point, PageBytes);
+ memState->brkPoint = objFile->dataBase() + objFile->dataSize() +
+ objFile->bssSize();
+ memState->brkPoint = roundUp(memState->brkPoint, PageBytes);
// Set up region for mmaps. For now, start at bottom of kuseg space.
- mmap_end = 0x40000000L;
+ memState->mmapEnd = 0x40000000L;
}
ArmProcess64::ArmProcess64(ProcessParams *params, ObjectFile *objFile,
ObjectFile::Arch _arch)
: ArmProcess(params, objFile, _arch)
{
- stack_base = 0x7fffff0000L;
+ memState->stackBase = 0x7fffff0000L;
// Set pointer for next thread stack. Reserve 8M for main stack.
- next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+ memState->nextThreadStackBase = memState->stackBase - (8 * 1024 * 1024);
// Set up break point (Top of Heap)
- brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
- brk_point = roundUp(brk_point, PageBytes);
+ memState->brkPoint = objFile->dataBase() + objFile->dataSize() +
+ objFile->bssSize();
+ memState->brkPoint = roundUp(memState->brkPoint, PageBytes);
// Set up region for mmaps. For now, start at bottom of kuseg space.
- mmap_end = 0x4000000000L;
+ memState->mmapEnd = 0x4000000000L;
}
void
int space_needed = frame_size + aux_padding;
- stack_min = stack_base - space_needed;
- stack_min = roundDown(stack_min, align);
- stack_size = stack_base - stack_min;
+ memState->stackMin = memState->stackBase - space_needed;
+ memState->stackMin = roundDown(memState->stackMin, align);
+ memState->stackSize = memState->stackBase - memState->stackMin;
// map memory
- allocateMem(roundDown(stack_min, pageSize), roundUp(stack_size, pageSize));
+ allocateMem(roundDown(memState->stackMin, pageSize),
+ roundUp(memState->stackSize, pageSize));
// map out initial stack contents
- IntType sentry_base = stack_base - sentry_size;
+ IntType sentry_base = memState->stackBase - sentry_size;
IntType aux_data_base = sentry_base - aux_data_size;
IntType env_data_base = aux_data_base - env_data_size;
IntType arg_data_base = env_data_base - arg_data_size;
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);
+ DPRINTF(Stack, "0x%x - stack min\n", memState->stackMin);
// write contents to stack
ThreadContext *tc = system->getThreadContext(contextIds[0]);
//Set the stack pointer register
- tc->setIntReg(spIndex, stack_min);
+ tc->setIntReg(spIndex, memState->stackMin);
//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);
pc.set(getStartPC() & ~mask(1));
tc->pcState(pc);
- //Align the "stack_min" to a page boundary.
- stack_min = roundDown(stack_min, pageSize);
+ //Align the "stackMin" to a page boundary.
+ memState->stackMin = roundDown(memState->stackMin, pageSize);
}
ArmISA::IntReg
npc(val + sizeof(MachInst));
};
+ void
+ setNPC(Addr val)
+ {
+ npc(val);
+ }
+
SimplePCState() {}
SimplePCState(Addr val) { set(val); }
{
// Set up stack. On MIPS, stack starts at the top of kuseg
// user address space. MIPS stack grows down from here
- stack_base = 0x7FFFFFFF;
+ memState->stackBase = 0x7FFFFFFF;
// Set pointer for next thread stack. Reserve 8M for main stack.
- next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+ memState->nextThreadStackBase = memState->stackBase - (8 * 1024 * 1024);
// Set up break point (Top of Heap)
- brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
- brk_point = roundUp(brk_point, PageBytes);
+ memState->brkPoint = objFile->dataBase() + objFile->dataSize() +
+ objFile->bssSize();
+ memState->brkPoint = roundUp(memState->brkPoint, PageBytes);
// Set up region for mmaps. Start it 1GB above the top of the heap.
- mmap_end = brk_point + 0x40000000L;
+ memState->mmapEnd = memState->brkPoint + 0x40000000L;
}
void
env_data_size;
// set bottom of stack
- stack_min = stack_base - space_needed;
+ memState->stackMin = memState->stackBase - space_needed;
// align it
- stack_min = roundDown(stack_min, pageSize);
- stack_size = stack_base - stack_min;
+ memState->stackMin = roundDown(memState->stackMin, pageSize);
+ memState->stackSize = memState->stackBase - memState->stackMin;
// map memory
- allocateMem(stack_min, roundUp(stack_size, pageSize));
+ allocateMem(memState->stackMin, roundUp(memState->stackSize, pageSize));
// map out initial stack contents
- IntType argv_array_base = stack_min + intSize; // room for argc
+ IntType argv_array_base = memState->stackMin + intSize; // room for argc
IntType envp_array_base = argv_array_base + argv_array_size;
IntType auxv_array_base = envp_array_base + envp_array_size;
IntType arg_data_base = auxv_array_base + auxv_array_size;
argc = htog((IntType)argc);
- initVirtMem.writeBlob(stack_min, (uint8_t*)&argc, intSize);
+ initVirtMem.writeBlob(memState->stackMin, (uint8_t*)&argc, intSize);
copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
setSyscallArg(tc, 0, argc);
setSyscallArg(tc, 1, argv_array_base);
- tc->setIntReg(StackPointerReg, stack_min);
+ tc->setIntReg(StackPointerReg, memState->stackMin);
tc->pcState(getStartPC());
}
PowerProcess::PowerProcess(ProcessParams *params, ObjectFile *objFile)
: Process(params, objFile)
{
- stack_base = 0xbf000000L;
+ memState->stackBase = 0xbf000000L;
// Set pointer for next thread stack. Reserve 8M for main stack.
- next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+ memState->nextThreadStackBase = memState->stackBase - (8 * 1024 * 1024);
// Set up break point (Top of Heap)
- brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
- brk_point = roundUp(brk_point, PageBytes);
+ memState->brkPoint = objFile->dataBase() + objFile->dataSize() +
+ objFile->bssSize();
+ memState->brkPoint = roundUp(memState->brkPoint, PageBytes);
// Set up region for mmaps. For now, start at bottom of kuseg space.
- mmap_end = 0x70000000L;
+ memState->mmapEnd = 0x70000000L;
}
void
int space_needed = frame_size + aux_padding;
- stack_min = stack_base - space_needed;
- stack_min = roundDown(stack_min, align);
- stack_size = stack_base - stack_min;
+ memState->stackMin = memState->stackBase - space_needed;
+ memState->stackMin = roundDown(memState->stackMin, align);
+ memState->stackSize = memState->stackBase - memState->stackMin;
// map memory
- allocateMem(roundDown(stack_min, pageSize), roundUp(stack_size, pageSize));
+ allocateMem(roundDown(memState->stackMin, pageSize),
+ roundUp(memState->stackSize, pageSize));
// map out initial stack contents
- uint32_t sentry_base = stack_base - sentry_size;
+ uint32_t sentry_base = memState->stackBase - 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;
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);
+ DPRINTF(Stack, "0x%x - stack min\n", memState->stackMin);
// write contents to stack
ThreadContext *tc = system->getThreadContext(contextIds[0]);
//Set the stack pointer register
- tc->setIntReg(StackPointerReg, stack_min);
+ tc->setIntReg(StackPointerReg, memState->stackMin);
tc->pcState(getStartPC());
//Align the "stack_min" to a page boundary.
- stack_min = roundDown(stack_min, pageSize);
+ memState->stackMin = roundDown(memState->stackMin, pageSize);
}
PowerISA::IntReg
{
// Set up stack. On RISC-V, stack starts at the top of kuseg
// user address space. RISC-V stack grows down from here
- stack_base = 0x7FFFFFFF;
+ memState->stackBase = (Addr)0x7FFFFFFF;
// Set pointer for next thread stack. Reserve 8M for main stack.
- next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+ memState->nextThreadStackBase = memState->stackBase - (8 * 1024 * 1024);
// Set up break point (Top of Heap)
- brk_point = objFile->bssBase() + objFile->bssSize();
+ memState->brkPoint = objFile->bssBase() + objFile->bssSize();
// Set up region for mmaps. Start it 1GB above the top of the heap.
- mmap_end = brk_point + 0x40000000L;
+ memState->mmapEnd = memState->brkPoint + 0x40000000L;
}
void
env_data_size += env.size() + 1;
int auxv_array_size = 2 * sizeof(IntType)*auxv.size();
- stack_size = sizeof(IntType) + argv_array_size + 2 * sizeof(Addr) +
- arg_data_size + 2 * sizeof(Addr);
+ memState->stackSize = sizeof(IntType) + argv_array_size + 2 *
+ sizeof(Addr) + arg_data_size + 2 * sizeof(Addr);
if (!envp.empty()) {
- stack_size += 2 * sizeof(Addr) + envp_array_size + 2 * sizeof(Addr) +
- env_data_size;
+ memState->stackSize += 2 * sizeof(Addr) + envp_array_size + 2 *
+ sizeof(Addr) + env_data_size;
}
if (!auxv.empty())
- stack_size += 2 * sizeof(Addr) + auxv_array_size;
- stack_min = roundDown(stack_base - stack_size, pageSize);
- allocateMem(stack_min, roundUp(stack_size, pageSize));
+ memState->stackSize += 2 * sizeof(Addr) + auxv_array_size;
+ memState->stackMin = roundDown(memState->stackBase - memState->stackSize,
+ pageSize);
+ allocateMem(memState->stackMin, roundUp(memState->stackSize, pageSize));
- Addr argv_array_base = stack_min + sizeof(IntType);
+ Addr argv_array_base = memState->stackMin + sizeof(IntType);
Addr arg_data_base = argv_array_base + argv_array_size + 2 * sizeof(Addr);
Addr envp_array_base = arg_data_base + arg_data_size;
if (!envp.empty())
}
}
- Addr sp = stack_min;
+ Addr sp = memState->stackMin;
initVirtMem.writeBlob(sp, (uint8_t *)&argc, sizeof(IntType));
sp += sizeof(IntType);
for (Addr arg_pointer: arg_pointers) {
}
ThreadContext *tc = system->getThreadContext(contextIds[0]);
- tc->setIntReg(StackPointerReg, stack_min);
+ tc->setIntReg(StackPointerReg, memState->stackMin);
tc->pcState(getStartPC());
}
/* 214 */ SyscallDesc("sysinfo", sysinfoFunc<Sparc32Linux>), // 32 bit
/* 215 */ SyscallDesc("ipc", unimplementedFunc), // 32 bit
/* 216 */ SyscallDesc("sigreturn", unimplementedFunc), // 32 bit
- /* 217 */ SyscallDesc("clone", cloneFunc),
+ /* 217 */ SyscallDesc("clone", cloneFunc<Sparc32Linux>),
/* 218 */ SyscallDesc("ioprio_get", unimplementedFunc), // 32 bit
/* 219 */ SyscallDesc("adjtimex", unimplementedFunc), // 32 bit
/* 220 */ SyscallDesc("sigprocmask", unimplementedFunc), // 32 bit
/* 214 */ SyscallDesc("sysinfo", sysinfoFunc<SparcLinux>),
/* 215 */ SyscallDesc("ipc", unimplementedFunc),
/* 216 */ SyscallDesc("sigreturn", unimplementedFunc),
- /* 217 */ SyscallDesc("clone", cloneFunc),
+ /* 217 */ SyscallDesc("clone", cloneFunc<SparcLinux>),
/* 218 */ SyscallDesc("ioprio_get", unimplementedFunc),
/* 219 */ SyscallDesc("adjtimex", unimplementedFunc),
/* 220 */ SyscallDesc("sigprocmask", unimplementedFunc),
{
// XXX all the below need to be updated for SPARC - Ali
- brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
- brk_point = roundUp(brk_point, PageBytes);
+ memState->brkPoint = objFile->dataBase() + objFile->dataSize() +
+ objFile->bssSize();
+ memState->brkPoint = roundUp(memState->brkPoint, PageBytes);
// Set pointer for next thread stack. Reserve 8M for main stack.
- next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+ memState->nextThreadStackBase = memState->stackBase - (8 * 1024 * 1024);
// Initialize these to 0s
fillStart = 0;
aux_padding +
frame_size;
- stack_min = stack_base - space_needed;
- stack_min = roundDown(stack_min, align);
- stack_size = stack_base - stack_min;
+ memState->stackMin = memState->stackBase - space_needed;
+ memState->stackMin = roundDown(memState->stackMin, align);
+ memState->stackSize = memState->stackBase - memState->stackMin;
// Allocate space for the stack
- allocateMem(roundDown(stack_min, pageSize), roundUp(stack_size, pageSize));
+ allocateMem(roundDown(memState->stackMin, pageSize),
+ roundUp(memState->stackSize, pageSize));
// map out initial stack contents
- IntType sentry_base = stack_base - sentry_size;
+ IntType sentry_base = memState->stackBase - sentry_size;
IntType file_name_base = sentry_base - file_name_size;
IntType env_data_base = file_name_base - env_data_size;
IntType arg_data_base = env_data_base - arg_data_size;
DPRINTF(Stack, "%#x - argv array\n", argv_array_base);
DPRINTF(Stack, "%#x - argc \n", argc_base);
DPRINTF(Stack, "%#x - window save\n", window_save_base);
- DPRINTF(Stack, "%#x - stack min\n", stack_min);
+ DPRINTF(Stack, "%#x - stack min\n", memState->stackMin);
- assert(window_save_base == stack_min);
+ assert(window_save_base == memState->stackMin);
// write contents to stack
// Set up space for the trap handlers into the processes address space.
// Since the stack grows down and there is reserved address space abov
// it, we can put stuff above it and stay out of the way.
- fillStart = stack_base;
+ fillStart = memState->stackBase;
spillStart = fillStart + sizeof(MachInst) * numFillInsts;
ThreadContext *tc = system->getThreadContext(contextIds[0]);
// assert(NumArgumentRegs >= 2);
// tc->setIntReg(ArgumentReg[0], argc);
// tc->setIntReg(ArgumentReg[1], argv_array_base);
- tc->setIntReg(StackPointerReg, stack_min - StackBias);
+ tc->setIntReg(StackPointerReg, memState->stackMin - StackBias);
// %g1 is a pointer to a function that should be run at exit. Since we
// don't have anything like that, it should be set to 0.
tc->pcState(getStartPC());
// Align the "stack_min" to a page boundary.
- stack_min = roundDown(stack_min, pageSize);
+ memState->stackMin = roundDown(memState->stackMin, pageSize);
}
void
{
// 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;
+ memState->stackBase = (Addr)0xf0000000ULL;
// Set up region for mmaps.
- mmap_end = 0x70000000;
+ memState->mmapEnd = 0x70000000;
}
void initState();
{
// 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;
+ memState->stackBase = (Addr)0x80000000000ULL;
// Set up region for mmaps.
- mmap_end = 0xfffff80000000000ULL;
+ memState->mmapEnd = 0xfffff80000000000ULL;
}
void initState();
/* 53 */ SyscallDesc("socketpair", unimplementedFunc),
/* 54 */ SyscallDesc("setsockopt", unimplementedFunc),
/* 55 */ SyscallDesc("getsockopt", unimplementedFunc),
- /* 56 */ SyscallDesc("clone", cloneFunc),
+ /* 56 */ SyscallDesc("clone", cloneFunc<X86Linux64>),
/* 57 */ SyscallDesc("fork", unimplementedFunc),
/* 58 */ SyscallDesc("vfork", unimplementedFunc),
- /* 59 */ SyscallDesc("execve", unimplementedFunc),
+ /* 59 */ SyscallDesc("execve", execveFunc<X86Linux64>),
/* 60 */ SyscallDesc("exit", exitFunc),
/* 61 */ SyscallDesc("wait4", unimplementedFunc),
/* 62 */ SyscallDesc("kill", unimplementedFunc),
/* 215 */ SyscallDesc("epoll_wait_old", unimplementedFunc),
/* 216 */ SyscallDesc("remap_file_pages", unimplementedFunc),
/* 217 */ SyscallDesc("getdents64", unimplementedFunc),
- /* 218 */ SyscallDesc("set_tid_address", unimplementedFunc),
+ /* 218 */ SyscallDesc("set_tid_address", setTidAddressFunc),
/* 219 */ SyscallDesc("restart_syscall", unimplementedFunc),
/* 220 */ SyscallDesc("semtimedop", unimplementedFunc),
/* 221 */ SyscallDesc("fadvise64", unimplementedFunc),
sizeof(syscallDescs64) / sizeof(SyscallDesc))
{}
+void X86_64LinuxProcess::clone(ThreadContext *old_tc, ThreadContext *new_tc,
+ Process *process, TheISA::IntReg flags)
+{
+ X86_64Process::clone(old_tc, new_tc, (X86_64Process*)process, flags);
+}
+
static SyscallDesc syscallDescs32[] = {
/* 0 */ SyscallDesc("restart_syscall", unimplementedFunc),
/* 1 */ SyscallDesc("exit", exitFunc),
/* 8 */ SyscallDesc("creat", unimplementedFunc),
/* 9 */ SyscallDesc("link", unimplementedFunc),
/* 10 */ SyscallDesc("unlink", unimplementedFunc),
- /* 11 */ SyscallDesc("execve", unimplementedFunc),
+ /* 11 */ SyscallDesc("execve", execveFunc<X86Linux32>),
/* 12 */ SyscallDesc("chdir", unimplementedFunc),
/* 13 */ SyscallDesc("time", timeFunc<X86Linux32>),
/* 14 */ SyscallDesc("mknod", unimplementedFunc),
/* 117 */ SyscallDesc("ipc", unimplementedFunc),
/* 118 */ SyscallDesc("fsync", unimplementedFunc),
/* 119 */ SyscallDesc("sigreturn", unimplementedFunc),
- /* 120 */ SyscallDesc("clone", unimplementedFunc),
+ /* 120 */ SyscallDesc("clone", cloneFunc<X86Linux32>),
/* 121 */ SyscallDesc("setdomainname", unimplementedFunc),
/* 122 */ SyscallDesc("uname", unameFunc),
/* 123 */ SyscallDesc("modify_ldt", unimplementedFunc),
/* 255 */ SyscallDesc("epoll_ctl", unimplementedFunc),
/* 256 */ SyscallDesc("epoll_wait", unimplementedFunc),
/* 257 */ SyscallDesc("remap_file_pages", unimplementedFunc),
- /* 258 */ SyscallDesc("set_tid_address", unimplementedFunc),
+ /* 258 */ SyscallDesc("set_tid_address", setTidAddressFunc),
/* 259 */ SyscallDesc("timer_create", unimplementedFunc),
/* 260 */ SyscallDesc("timer_settime", unimplementedFunc),
/* 261 */ SyscallDesc("timer_gettime", unimplementedFunc),
: I386Process(params, objFile, syscallDescs32,
sizeof(syscallDescs32) / sizeof(SyscallDesc))
{}
+
+void I386LinuxProcess::clone(ThreadContext *old_tc, ThreadContext *new_tc,
+ Process *process, TheISA::IntReg flags)
+{
+ I386Process::clone(old_tc, new_tc, (I386Process*)process, flags);
+}
#include "arch/x86/process.hh"
#include "sim/process.hh"
+struct ProcessParams;
+struct ThreadContext;
+
namespace X86ISA {
class X86_64LinuxProcess : public X86_64Process
public:
/// Constructor.
X86_64LinuxProcess(ProcessParams * params, ObjectFile *objFile);
+ void clone(ThreadContext *old_tc, ThreadContext *new_tc, Process *process,
+ TheISA::IntReg flags);
};
class I386LinuxProcess : public I386Process
public:
/// Constructor.
I386LinuxProcess(ProcessParams * params, ObjectFile *objFile);
+ void clone(ThreadContext *old_tc, ThreadContext *new_tc, Process *process,
+ TheISA::IntReg flags);
};
} // namespace X86ISA
: Process(params, objFile), syscallDescs(_syscallDescs),
numSyscallDescs(_numSyscallDescs)
{
- brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
- brk_point = roundUp(brk_point, PageBytes);
+ memState->brkPoint = objFile->dataBase() + objFile->dataSize()
+ + objFile->bssSize();
+ memState->brkPoint = roundUp(memState->brkPoint, PageBytes);
+}
+
+void X86Process::clone(ThreadContext *old_tc, ThreadContext *new_tc,
+ Process *p, TheISA::IntReg flags)
+{
+ Process::clone(old_tc, new_tc, p, flags);
+ X86Process *process = (X86Process*)p;
+ *process = *this;
}
X86_64Process::X86_64Process(ProcessParams *params, ObjectFile *objFile,
// Set up stack. On X86_64 Linux, stack goes from the top of memory
// downward, less the hole for the kernel address space plus one page
// for undertermined purposes.
- stack_base = (Addr)0x7FFFFFFFF000ULL;
+ memState->stackBase = (Addr)0x7FFFFFFFF000ULL;
// Set pointer for next thread stack. Reserve 8M for main stack.
- next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+ memState->nextThreadStackBase = memState->stackBase - (8 * 1024 * 1024);
// "mmap_base" is a function which defines where mmap region starts in
// the process address space.
// We do not use any address space layout randomization in gem5
// therefore the random fields become zero; the smallest gap space was
// chosen but gap could potentially be much larger.
- mmap_end = (Addr)0x7FFFF7FFF000ULL;
+ memState->mmapEnd = (Addr)0x7FFFF7FFF000ULL;
}
void
vsyscallPage.vsyscallOffset = 0x400;
vsyscallPage.vsysexitOffset = 0x410;
- stack_base = _gdtStart;
+ memState->stackBase = _gdtStart;
// Set pointer for next thread stack. Reserve 8M for main stack.
- next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+ memState->nextThreadStackBase = memState->stackBase - (8 * 1024 * 1024);
// "mmap_base" is a function which defines where mmap region starts in
// the process address space.
// We do not use any address space layout randomization in gem5
// therefore the random fields become zero; the smallest gap space was
// chosen but gap could potentially be much larger.
- mmap_end = (Addr)0xB7FFF000ULL;
+ memState->mmapEnd = (Addr)0xB7FFF000ULL;
}
SyscallDesc*
aux_padding +
frame_size;
- stack_min = stack_base - space_needed;
- stack_min = roundDown(stack_min, align);
- stack_size = roundUp(stack_base - stack_min, pageSize);
+ memState->stackMin = memState->stackBase - space_needed;
+ memState->stackMin = roundDown(memState->stackMin, align);
+ memState->stackSize = roundUp(memState->stackBase - memState->stackMin,
+ pageSize);
// map memory
- Addr stack_end = roundDown(stack_base - stack_size, pageSize);
+ Addr stack_end = roundDown(memState->stackBase - memState->stackSize,
+ pageSize);
- DPRINTF(Stack, "Mapping the stack: 0x%x %dB\n", stack_end, stack_size);
- allocateMem(stack_end, stack_size);
+ DPRINTF(Stack, "Mapping the stack: 0x%x %dB\n",
+ stack_end, memState->stackSize);
+ allocateMem(stack_end, memState->stackSize);
// map out initial stack contents
- IntType sentry_base = stack_base - sentry_size;
+ IntType sentry_base = memState->stackBase - sentry_size;
IntType file_name_base = sentry_base - file_name_size;
IntType env_data_base = file_name_base - env_data_size;
IntType arg_data_base = env_data_base - arg_data_size;
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);
+ DPRINTF(Stack, "0x%x - stack min\n", memState->stackMin);
// write contents to stack
ThreadContext *tc = system->getThreadContext(contextIds[0]);
//Set the stack pointer register
- tc->setIntReg(StackPointerReg, stack_min);
+ tc->setIntReg(StackPointerReg, memState->stackMin);
// There doesn't need to be any segment base added in since we're dealing
// with the flat segmentation model.
tc->pcState(getStartPC());
//Align the "stack_min" to a page boundary.
- stack_min = roundDown(stack_min, pageSize);
+ memState->stackMin = roundDown(memState->stackMin, pageSize);
}
void
return tc->setIntReg(ArgumentReg[i], val);
}
+void
+X86_64Process::clone(ThreadContext *old_tc, ThreadContext *new_tc,
+ Process *p, TheISA::IntReg flags)
+{
+ X86Process::clone(old_tc, new_tc, p, flags);
+ ((X86_64Process*)p)->vsyscallPage = vsyscallPage;
+}
+
X86ISA::IntReg
I386Process::getSyscallArg(ThreadContext *tc, int &i)
{
assert(i < NumArgumentRegs);
return tc->setIntReg(ArgumentReg[i], val);
}
+
+void
+I386Process::clone(ThreadContext *old_tc, ThreadContext *new_tc,
+ Process *p, TheISA::IntReg flags)
+{
+ X86Process::clone(old_tc, new_tc, p, flags);
+ ((I386Process*)p)->vsyscallPage = vsyscallPage;
+}
SyscallDesc* getDesc(int callnum);
void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value);
+ void clone(ThreadContext *old_tc, ThreadContext *new_tc,
+ Process *process, TheISA::IntReg flags);
+
+ X86Process &
+ operator=(const X86Process &in)
+ {
+ if (this == &in)
+ return *this;
+
+ _gdtStart = in._gdtStart;
+ _gdtSize = in._gdtSize;
+ syscallDescs = in.syscallDescs;
+
+ return *this;
+ }
};
class X86_64Process : public X86Process
Addr size;
Addr vtimeOffset;
Addr vgettimeofdayOffset;
+
+ VSyscallPage &
+ operator=(const VSyscallPage &in)
+ {
+ if (this == &in)
+ return *this;
+
+ base = in.base;
+ size = in.size;
+ vtimeOffset = in.vtimeOffset;
+ vgettimeofdayOffset = in.vgettimeofdayOffset;
+
+ return *this;
+ }
};
VSyscallPage vsyscallPage;
/// Explicitly import the otherwise hidden getSyscallArg
using Process::getSyscallArg;
void setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val);
+ void clone(ThreadContext *old_tc, ThreadContext *new_tc,
+ Process *process, TheISA::IntReg flags);
};
class I386Process : public X86Process
Addr size;
Addr vsyscallOffset;
Addr vsysexitOffset;
+
+ VSyscallPage &
+ operator=(const VSyscallPage &in)
+ {
+ if (this == &in)
+ return *this;
+
+ base = in.base;
+ size = in.size;
+ vsyscallOffset = in.vsyscallOffset;
+ vsysexitOffset = in.vsysexitOffset;
+
+ return *this;
+ }
};
VSyscallPage vsyscallPage;
X86ISA::IntReg getSyscallArg(ThreadContext *tc, int &i);
X86ISA::IntReg getSyscallArg(ThreadContext *tc, int &i, int width);
void setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val);
+ void clone(ThreadContext *old_tc, ThreadContext *new_tc,
+ Process *process, TheISA::IntReg flags);
};
/**
PCState() {}
PCState(Addr val) { set(val); }
+ void
+ setNPC(Addr val)
+ {
+ Base::setNPC(val);
+ _size = 0;
+ }
+
uint8_t size() const { return _size; }
void size(uint8_t newSize) { _size = newSize; }
Process *getProcessPtr() { return actualTC->getProcessPtr(); }
+ void setProcessPtr(Process *p) { actualTC->setProcessPtr(p); }
+
PortProxy &getPhysProxy() { return actualTC->getPhysProxy(); }
FSTranslatingPortProxy &getVirtProxy()
return actualTC->pcState(val);
}
+ void setNPC(Addr val)
+ {
+ checkerTC->setNPC(val);
+ actualTC->setNPC(val);
+ }
+
void pcStateNoRecord(const TheISA::PCState &val)
{
return actualTC->pcState(val);
/** Returns a pointer to this thread's process. */
virtual Process *getProcessPtr() { return thread->getProcessPtr(); }
+ virtual void setProcessPtr(Process *p) { thread->setProcessPtr(p); }
+
virtual PortProxy &getPhysProxy() { return thread->getPhysProxy(); }
virtual FSTranslatingPortProxy &getVirtProxy();
return _pcState.nextInstAddr();
}
+ void
+ setNPC(Addr val)
+ {
+ _pcState.setNPC(val);
+ }
+
MicroPC
microPC()
{
virtual Process *getProcessPtr() = 0;
+ virtual void setProcessPtr(Process *p) = 0;
+
virtual Status status() const = 0;
virtual void setStatus(Status new_status) = 0;
virtual void pcState(const TheISA::PCState &val) = 0;
+ void
+ setNPC(Addr val)
+ {
+ TheISA::PCState pc_state = pcState();
+ pc_state.setNPC(val);
+ pcState(pc_state);
+ }
+
virtual void pcStateNoRecord(const TheISA::PCState &val) = 0;
virtual Addr instAddr() = 0;
Process *getProcessPtr() { return actualTC->getProcessPtr(); }
+ void setProcessPtr(Process *p) { actualTC->setProcessPtr(p); }
+
Status status() const { return actualTC->status(); }
void setStatus(Status new_status) { actualTC->setStatus(new_status); }
Process *getProcessPtr() { return process; }
+ void setProcessPtr(Process *p)
+ {
+ process = p;
+ /**
+ * When the process pointer changes while operating in SE Mode,
+ * the se translating port proxy needs to be reinitialized since it
+ * holds a pointer to the process class.
+ */
+ if (proxy) {
+ delete proxy;
+ proxy = NULL;
+ initMemProxies(NULL);
+ }
+ }
+
SETranslatingPortProxy &getMemProxy();
/** Reads the number of instructions functionally executed and
length = roundUp(length, TheISA::PageBytes);
Process *proc = gpuTc->getProcessPtr();
+ auto mem_state = proc->memState;
if (proc->mmapGrowsDown()) {
DPRINTF(HSAIL, "GROWS DOWN");
- start = proc->mmap_end - length;
- proc->mmap_end = start;
+ start = mem_state->mmapEnd - length;
+ mem_state->mmapEnd = start;
} else {
DPRINTF(HSAIL, "GROWS UP");
- start = proc->mmap_end;
- proc->mmap_end += length;
+ start = mem_state->mmapEnd;
+ mem_state->mmapEnd += length;
// assertion to make sure we don't overwrite the stack (it grows down)
- assert(proc->mmap_end < proc->stack_base - proc->max_stack_size);
+ assert(mem_state->stackBase - proc->maxStackSize > mem_state->mmapEnd);
}
DPRINTF(HSAIL,"Shader::mmap start= %#x, %#x\n", start, length);
}
}
+void
+FuncPageTable::getMappings(std::vector<std::pair<Addr, Addr>> *addr_maps)
+{
+ for (auto &iter : pTable)
+ addr_maps->push_back(make_pair(iter.first, iter.second.pageStart()));
+}
+
void
FuncPageTable::unmap(Addr vaddr, int64_t size)
{
pTableCache[2].valid = false;
}
}
+
+ virtual void getMappings(std::vector<std::pair<Addr, Addr>>
+ *addr_mappings) {};
};
/**
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
+
+ void getMappings(std::vector<std::pair<Addr, Addr>> *addr_maps) override;
};
/**
SETranslatingPortProxy(MasterPort& port, Process* p, AllocType alloc);
virtual ~SETranslatingPortProxy();
+ void setPageTable(PageTableBase *p) { pTable = p; }
+ void setProcess(Process *p) { process = p; }
bool tryReadBlob(Addr addr, uint8_t *p, int size) const;
bool tryWriteBlob(Addr addr, const uint8_t *p, int size) const;
bool tryMemsetBlob(Addr addr, uint8_t val, int size) const;
useArchPT = Param.Bool('false', 'maintain an in-memory version of the page\
table in an architecture-specific format')
kvmInSE = Param.Bool('false', 'initialize the process for KvmCPU in SE')
- max_stack_size = Param.MemorySize('64MB', 'maximum size of the stack')
+ maxStackSize = Param.MemorySize('64MB', 'maximum size of the stack')
uid = Param.Int(100, 'user id')
euid = Param.Int(100, 'effective user id')
return _fdArray[tgt_fd];
}
+void
+FDArray::setFDEntry(int tgt_fd, std::shared_ptr<FDEntry> fdep)
+{
+ assert(0 <= tgt_fd && tgt_fd < _fdArray.size());
+ _fdArray[tgt_fd] = fdep;
+}
+
int
FDArray::closeFDEntry(int tgt_fd)
{
*/
int getSize() const { return _fdArray.size(); }
+ /**
+ * Put the pointer specified by fdep into the _fdArray entry indexed
+ * by tgt_fd.
+ * @param tgt_fd Use target file descriptors to index the array.
+ * @param fdep Incoming pointer used to set the entry pointed to by tgt_fd.
+ */
+ void setFDEntry(int tgt_fd, std::shared_ptr<FDEntry> fdep);
+
/**
* Try to close the host file descriptor. If successful, set the
* specified file descriptor entry object pointer to nullptr.
Process::Process(ProcessParams * params, ObjectFile * obj_file)
: SimObject(params), system(params->system),
- brk_point(0), stack_base(0), stack_size(0), stack_min(0),
- max_stack_size(params->max_stack_size),
- next_thread_stack_base(0),
useArchPT(params->useArchPT),
kvmInSE(params->kvmInSE),
pTable(useArchPT ?
_gid(params->gid), _egid(params->egid),
_pid(params->pid), _ppid(params->ppid),
_pgid(params->pgid), drivers(params->drivers),
- fds(make_shared<FDArray>(params->input, params->output, params->errout))
+ fds(make_shared<FDArray>(params->input, params->output, params->errout)),
+ maxStackSize(params->maxStackSize),
+ childClearTID(0)
{
- mmap_end = 0;
-
if (_pid >= System::maxPID)
fatal("_pid is too large: %d", _pid);
if (!ret_pair.second)
fatal("_pid %d is already used", _pid);
- // load up symbols, if any... these may be used for debugging or
- // profiling.
+ /**
+ * Linux bundles together processes into this concept called a thread
+ * group. The thread group is responsible for recording which processes
+ * behave as threads within a process context. The thread group leader
+ * is the process who's tgid is equal to its pid. Other processes which
+ * belong to the thread group, but do not lead the thread group, are
+ * treated as child threads. These threads are created by the clone system
+ * call with options specified to create threads (differing from the
+ * options used to implement a fork). By default, set up the tgid/pid
+ * with a new, equivalent value. If CLONE_THREAD is specified, patch
+ * the tgid value with the old process' value.
+ */
+ _tgid = params->pid;
+
+ exitGroup = new bool();
+ memState = new MemState();
+ sigchld = new bool();
+
if (!debugSymbolTable) {
debugSymbolTable = new SymbolTable();
if (!objFile->loadGlobalSymbols(debugSymbolTable) ||
!objFile->loadLocalSymbols(debugSymbolTable) ||
!objFile->loadWeakSymbols(debugSymbolTable)) {
- // didn't load any symbols
delete debugSymbolTable;
debugSymbolTable = NULL;
}
}
}
+void
+Process::clone(ThreadContext *otc, ThreadContext *ntc,
+ Process *np, TheISA::IntReg flags)
+{
+ if (CLONE_VM & flags) {
+ /**
+ * Share the process memory address space between the new process
+ * and the old process. Changes in one will be visible in the other
+ * due to the pointer use.
+ */
+ delete np->pTable;
+ np->pTable = pTable;
+ ntc->getMemProxy().setPageTable(np->pTable);
+
+ delete np->memState;
+ np->memState = memState;
+ } else {
+ /**
+ * Duplicate the process memory address space. The state needs to be
+ * copied over (rather than using pointers to share everything).
+ */
+ typedef std::vector<pair<Addr,Addr>> MapVec;
+ MapVec mappings;
+ pTable->getMappings(&mappings);
+
+ for (auto map : mappings) {
+ Addr paddr, vaddr = map.first;
+ bool alloc_page = !(np->pTable->translate(vaddr, paddr));
+ np->replicatePage(vaddr, paddr, otc, ntc, alloc_page);
+ }
+
+ *np->memState = *memState;
+ }
+
+ if (CLONE_FILES & flags) {
+ /**
+ * The parent and child file descriptors are shared because the
+ * two FDArray pointers are pointing to the same FDArray. Opening
+ * and closing file descriptors will be visible to both processes.
+ */
+ np->fds = fds;
+ } else {
+ /**
+ * Copy the file descriptors from the old process into the new
+ * child process. The file descriptors entry can be opened and
+ * closed independently of the other process being considered. The
+ * host file descriptors are also dup'd so that the flags for the
+ * host file descriptor is independent of the other process.
+ */
+ for (int tgt_fd = 0; tgt_fd < fds->getSize(); tgt_fd++) {
+ std::shared_ptr<FDArray> nfds = np->fds;
+ std::shared_ptr<FDEntry> this_fde = (*fds)[tgt_fd];
+ if (!this_fde) {
+ nfds->setFDEntry(tgt_fd, nullptr);
+ continue;
+ }
+ nfds->setFDEntry(tgt_fd, this_fde->clone());
+
+ auto this_hbfd = std::dynamic_pointer_cast<HBFDEntry>(this_fde);
+ if (!this_hbfd)
+ continue;
+
+ int this_sim_fd = this_hbfd->getSimFD();
+ if (this_sim_fd <= 2)
+ continue;
+
+ int np_sim_fd = dup(this_sim_fd);
+ assert(np_sim_fd != -1);
+
+ auto nhbfd = std::dynamic_pointer_cast<HBFDEntry>((*nfds)[tgt_fd]);
+ nhbfd->setSimFD(np_sim_fd);
+ }
+ }
+
+ if (CLONE_THREAD & flags) {
+ np->_tgid = _tgid;
+ delete np->exitGroup;
+ np->exitGroup = exitGroup;
+ }
+
+ np->argv.insert(np->argv.end(), argv.begin(), argv.end());
+ np->envp.insert(np->envp.end(), envp.begin(), envp.end());
+}
+
void
Process::regStats()
{
using namespace Stats;
- num_syscalls
- .name(name() + ".num_syscalls")
+ numSyscalls
+ .name(name() + ".numSyscalls")
.desc("Number of system calls")
;
}
ThreadContext *
Process::findFreeContext()
{
- for (int id : contextIds) {
- ThreadContext *tc = system->getThreadContext(id);
- if (tc->status() == ThreadContext::Halted)
- return tc;
+ for (auto &it : system->threadContexts) {
+ if (ThreadContext::Halted == it->status())
+ return it;
}
return NULL;
}
+void
+Process::revokeThreadContext(int context_id)
+{
+ std::vector<ContextID>::iterator it;
+ for (it = contextIds.begin(); it != contextIds.end(); it++) {
+ if (*it == context_id) {
+ contextIds.erase(it);
+ return;
+ }
+ }
+ warn("Unable to find thread context to revoke");
+}
+
void
Process::initState()
{
clobber ? PageTableBase::Clobber : PageTableBase::Zero);
}
+void
+Process::replicatePage(Addr vaddr, Addr new_paddr, ThreadContext *old_tc,
+ ThreadContext *new_tc, bool allocate_page)
+{
+ if (allocate_page)
+ new_paddr = system->allocPhysPages(1);
+
+ // Read from old physical page.
+ uint8_t *buf_p = new uint8_t[PageBytes];
+ old_tc->getMemProxy().readBlob(vaddr, buf_p, PageBytes);
+
+ // Create new mapping in process address space by clobbering existing
+ // mapping (if any existed) and then write to the new physical page.
+ bool clobber = true;
+ pTable->map(vaddr, new_paddr, PageBytes, clobber);
+ new_tc->getMemProxy().writeBlob(vaddr, buf_p, PageBytes);
+ delete[] buf_p;
+}
+
bool
Process::fixupStackFault(Addr vaddr)
{
// Check if this is already on the stack and there's just no page there
// yet.
- if (vaddr >= stack_min && vaddr < stack_base) {
+ if (vaddr >= memState->stackMin && vaddr < memState->stackBase) {
allocateMem(roundDown(vaddr, PageBytes), PageBytes);
return true;
}
// We've accessed the next page of the stack, so extend it to include
// this address.
- if (vaddr < stack_min && vaddr >= stack_base - max_stack_size) {
- while (vaddr < stack_min) {
- stack_min -= TheISA::PageBytes;
- if (stack_base - stack_min > max_stack_size)
+ if (vaddr < memState->stackMin
+ && vaddr >= memState->stackBase - maxStackSize) {
+ while (vaddr < memState->stackMin) {
+ memState->stackMin -= TheISA::PageBytes;
+ if (memState->stackBase - memState->stackMin > maxStackSize)
fatal("Maximum stack size exceeded\n");
- allocateMem(stack_min, TheISA::PageBytes);
+ allocateMem(memState->stackMin, TheISA::PageBytes);
inform("Increasing stack size by one page.");
};
return true;
void
Process::serialize(CheckpointOut &cp) const
{
- SERIALIZE_SCALAR(brk_point);
- SERIALIZE_SCALAR(stack_base);
- SERIALIZE_SCALAR(stack_size);
- SERIALIZE_SCALAR(stack_min);
- SERIALIZE_SCALAR(next_thread_stack_base);
- SERIALIZE_SCALAR(mmap_end);
+ SERIALIZE_SCALAR(memState->brkPoint);
+ SERIALIZE_SCALAR(memState->stackBase);
+ SERIALIZE_SCALAR(memState->stackSize);
+ SERIALIZE_SCALAR(memState->stackMin);
+ SERIALIZE_SCALAR(memState->nextThreadStackBase);
+ SERIALIZE_SCALAR(memState->mmapEnd);
pTable->serialize(cp);
/**
* Checkpoints for file descriptors currently do not work. Need to
void
Process::unserialize(CheckpointIn &cp)
{
- UNSERIALIZE_SCALAR(brk_point);
- UNSERIALIZE_SCALAR(stack_base);
- UNSERIALIZE_SCALAR(stack_size);
- UNSERIALIZE_SCALAR(stack_min);
- UNSERIALIZE_SCALAR(next_thread_stack_base);
- UNSERIALIZE_SCALAR(mmap_end);
+ UNSERIALIZE_SCALAR(memState->brkPoint);
+ UNSERIALIZE_SCALAR(memState->stackBase);
+ UNSERIALIZE_SCALAR(memState->stackSize);
+ UNSERIALIZE_SCALAR(memState->stackMin);
+ UNSERIALIZE_SCALAR(memState->nextThreadStackBase);
+ UNSERIALIZE_SCALAR(memState->mmapEnd);
pTable->unserialize(cp);
/**
* Checkpoints for file descriptors currently do not work. Need to
void
Process::syscall(int64_t callnum, ThreadContext *tc, Fault *fault)
{
- num_syscalls++;
+ numSyscalls++;
SyscallDesc *desc = getDesc(callnum);
if (desc == NULL)
// We are allocating the memory area; set the bias to the lowest address
// in the allocated memory region.
- Addr ld_bias = mmapGrowsDown() ? mmap_end - interp_mapsize : mmap_end;
+ Addr *end = &memState->mmapEnd;
+ Addr ld_bias = mmapGrowsDown() ? *end - interp_mapsize : *end;
// Adjust the process mmap area to give the interpreter room; the real
// execve system call would just invoke the kernel's internal mmap
// functions to make these adjustments.
- mmap_end = mmapGrowsDown() ? ld_bias : mmap_end + interp_mapsize;
+ *end = mmapGrowsDown() ? ld_bias : *end + interp_mapsize;
interp->updateBias(ld_bias);
}
{ }
};
+ struct MemState
+ {
+ Addr brkPoint;
+ Addr stackBase;
+ unsigned stackSize;
+ Addr stackMin;
+ Addr nextThreadStackBase;
+ Addr mmapEnd;
+
+ MemState()
+ : brkPoint(0), stackBase(0), stackSize(0), stackMin(0),
+ nextThreadStackBase(0), mmapEnd(0)
+ { }
+
+ MemState&
+ operator=(const MemState &in)
+ {
+ if (this == &in)
+ return *this;
+
+ brkPoint = in.brkPoint;
+ stackBase = in.stackBase;
+ stackSize = in.stackSize;
+ stackMin = in.stackMin;
+ nextThreadStackBase = in.nextThreadStackBase;
+ mmapEnd = in.mmapEnd;
+ return *this;
+ }
+
+ void serialize(CheckpointOut &cp) const;
+ void unserialize(CheckpointIn &cp);
+ };
+
Process(ProcessParams *params, ObjectFile *obj_file);
void serialize(CheckpointOut &cp) const override;
ThreadContext *findFreeContext();
/**
- * Does mmap region grow upward or downward from mmap_end? Most
+ * After delegating a thread context to a child process
+ * no longer should relate to the ThreadContext
+ */
+ void revokeThreadContext(int context_id);
+
+ /**
+ * Does mmap region grow upward or downward from mmapEnd? Most
* platforms grow downward, but a few (such as Alpha) grow upward
* instead, so they can override this method to return false.
*/
*/
bool map(Addr vaddr, Addr paddr, int size, bool cacheable = true);
+ void replicatePage(Addr vaddr, Addr new_paddr, ThreadContext *old_tc,
+ ThreadContext *new_tc, bool alloc_page);
+
+ void clone(ThreadContext *old_tc, ThreadContext *new_tc, Process *new_p,
+ TheISA::IntReg flags);
+
// list of all blocked contexts
std::list<WaitRec> waitList;
// system object which owns this process
System *system;
- Addr brk_point; // top of the data segment
- Addr stack_base; // stack segment base
- unsigned stack_size; // initial stack size
- Addr stack_min; // furthest address accessed from stack base
- Addr max_stack_size; // the maximum size allowed for the stack
- Addr next_thread_stack_base; // addr for next region w/ multithreaded apps
- Addr mmap_end; // base of automatic mmap region allocs
-
- Stats::Scalar num_syscalls; // track how many system calls are executed
+ Stats::Scalar numSyscalls; // track how many system calls are executed
bool useArchPT; // flag for using architecture specific page table
bool kvmInSE; // running KVM requires special initialization
std::vector<EmulatedDriver *> drivers;
std::shared_ptr<FDArray> fds;
+
+ bool *exitGroup;
+
+ Addr maxStackSize;
+ MemState *memState;
+
+ /**
+ * Calls a futex wakeup at the address specified by this pointer when
+ * this process exits.
+ */
+ uint64_t childClearTID;
+
+ // Process was forked with SIGCHLD set.
+ bool *sigchld;
};
#endif // __PROCESS_HH__
std::string name() { return _name; }
+ int getFlags() const { return _flags; }
+
+ void setFlags(int flags) { _flags = flags; }
+
private:
/** System call name (e.g., open, mmap, clone, socket, etc.) */
std::string _name;
return 0;
}
+static void
+exitFutexWake(ThreadContext *tc, uint64_t uaddr)
+{
+ std::map<uint64_t, std::list<ThreadContext *> * >
+ &futex_map = tc->getSystemPtr()->futexMap;
+
+ int wokenUp = 0;
+ std::list<ThreadContext *> * tcWaitList;
+ if (futex_map.count(uaddr)) {
+ tcWaitList = futex_map.find(uaddr)->second;
+ if (tcWaitList->size() > 0) {
+ tcWaitList->front()->activate();
+ tcWaitList->pop_front();
+ wokenUp++;
+ }
+ if (tcWaitList->empty()) {
+ futex_map.erase(uaddr);
+ delete tcWaitList;
+ }
+ }
+ DPRINTF(SyscallVerbose, "exit: FUTEX_WAKE, activated %d waiting "
+ "thread contexts\n", wokenUp);
+}
SyscallReturn
-exitFunc(SyscallDesc *desc, int callnum, Process *process,
- ThreadContext *tc)
+exitFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
{
- if (process->system->numRunningContexts() == 1) {
- // Last running context... exit simulator
+ if (p->system->numRunningContexts() == 1 && !p->childClearTID) {
+ // Last running free-parent context; exit simulator.
int index = 0;
exitSimLoop("target called exit()",
- process->getSyscallArg(tc, index) & 0xff);
+ p->getSyscallArg(tc, index) & 0xff);
} else {
- // other running threads... just halt this one
+ if (p->childClearTID)
+ exitFutexWake(tc, p->childClearTID);
tc->halt();
}
// in Linux at least, brk(0) returns the current break value
// (note that the syscall and the glibc function have different behavior)
if (new_brk == 0)
- return p->brk_point;
+ return p->memState->brkPoint;
- if (new_brk > p->brk_point) {
+ if (new_brk > p->memState->brkPoint) {
// might need to allocate some new pages
- for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
+ for (ChunkGenerator gen(p->memState->brkPoint,
+ new_brk - p->memState->brkPoint,
PageBytes); !gen.done(); gen.next()) {
if (!p->pTable->translate(gen.addr()))
p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes);
}
}
- p->brk_point = new_brk;
+ p->memState->brkPoint = new_brk;
DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n",
- p->brk_point);
- return p->brk_point;
+ p->memState->brkPoint);
+ return p->memState->brkPoint;
}
+SyscallReturn
+setTidAddressFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ int index = 0;
+ uint64_t tidPtr = process->getSyscallArg(tc, index);
+
+ process->childClearTID = tidPtr;
+ return process->pid();
+}
SyscallReturn
closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
return process->egid();
}
-
-SyscallReturn
-cloneFunc(SyscallDesc *desc, int callnum, Process *process,
- ThreadContext *tc)
-{
- int index = 0;
- IntReg flags = process->getSyscallArg(tc, index);
- IntReg newStack = process->getSyscallArg(tc, index);
-
- DPRINTF(SyscallVerbose, "In sys_clone:\n");
- DPRINTF(SyscallVerbose, " Flags=%llx\n", flags);
- DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack);
-
-
- if (flags != 0x10f00) {
- warn("This sys_clone implementation assumes flags "
- "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD "
- "(0x10f00), and may not work correctly with given flags "
- "0x%llx\n", flags);
- }
-
- ThreadContext* ctc; // child thread context
- if ((ctc = process->findFreeContext())) {
- DPRINTF(SyscallVerbose, " Found unallocated thread context\n");
-
- ctc->clearArchRegs();
-
- // Arch-specific cloning code
- #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA
- // Cloning the misc. regs for these archs is enough
- TheISA::copyMiscRegs(tc, ctc);
- #elif THE_ISA == SPARC_ISA
- TheISA::copyRegs(tc, ctc);
-
- // TODO: Explain what this code actually does :-)
- ctc->setIntReg(NumIntArchRegs + 6, 0);
- ctc->setIntReg(NumIntArchRegs + 4, 0);
- ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2);
- ctc->setIntReg(NumIntArchRegs + 5, NWindows);
- ctc->setMiscReg(MISCREG_CWP, 0);
- ctc->setIntReg(NumIntArchRegs + 7, 0);
- ctc->setMiscRegNoEffect(MISCREG_TL, 0);
- ctc->setMiscReg(MISCREG_ASI, ASI_PRIMARY);
-
- for (int y = 8; y < 32; y++)
- ctc->setIntReg(y, tc->readIntReg(y));
- #elif THE_ISA == ARM_ISA
- TheISA::copyRegs(tc, ctc);
- #else
- fatal("sys_clone is not implemented for this ISA\n");
- #endif
-
- // Set up stack register
- ctc->setIntReg(TheISA::StackPointerReg, newStack);
-
- // Set up syscall return values in parent and child
- ctc->setIntReg(ReturnValueReg, 0); // return value, child
-
- // Alpha needs SyscallSuccessReg=0 in child
- #if THE_ISA == ALPHA_ISA
- ctc->setIntReg(TheISA::SyscallSuccessReg, 0);
- #endif
-
- // In SPARC/Linux, clone returns 0 on pseudo-return register if
- // parent, non-zero if child
- #if THE_ISA == SPARC_ISA
- tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0);
- ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
- #endif
-
- ctc->pcState(tc->nextInstAddr());
-
- ctc->activate();
-
- // Should return nonzero child TID in parent's syscall return register,
- // but for our pthread library any non-zero value will work
- return 1;
- } else {
- fatal("Called sys_clone, but no unallocated thread contexts found!\n");
- return 0;
- }
-}
-
SyscallReturn
fallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
{
#include <memory>
#include <string>
+#include "arch/utility.hh"
#include "base/intmath.hh"
#include "base/loader/object_file.hh"
#include "base/misc.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "mem/page_table.hh"
+#include "params/Process.hh"
#include "sim/emul_driver.hh"
#include "sim/process.hh"
#include "sim/syscall_debug_macros.hh"
+#include "sim/syscall_desc.hh"
#include "sim/syscall_emul_buf.hh"
#include "sim/syscall_return.hh"
-class SyscallDesc;
-
//////////////////////////////////////////////////////////////////////
//
// The following emulation functions are generic enough that they
SyscallReturn exitGroupFunc(SyscallDesc *desc, int num,
Process *p, ThreadContext *tc);
+/// Target set_tid_address() handler.
+SyscallReturn setTidAddressFunc(SyscallDesc *desc, int num,
+ Process *p, ThreadContext *tc);
+
/// Target getpagesize() handler.
SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
Process *p, ThreadContext *tc);
SyscallReturn closeFunc(SyscallDesc *desc, int num,
Process *p, ThreadContext *tc);
-/// Target read() handler.
+// Target read() handler.
SyscallReturn readFunc(SyscallDesc *desc, int num,
Process *p, ThreadContext *tc);
SyscallReturn getegidFunc(SyscallDesc *desc, int num,
Process *p, ThreadContext *tc);
-/// Target clone() handler.
-SyscallReturn cloneFunc(SyscallDesc *desc, int num,
- Process *p, ThreadContext *tc);
-
/// Target access() handler
SyscallReturn accessFunc(SyscallDesc *desc, int num,
Process *p, ThreadContext *tc);
std::map<uint64_t, std::list<ThreadContext *> * >
&futex_map = tc->getSystemPtr()->futexMap;
- DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n",
+ DPRINTF(SyscallVerbose, "futex: Address=%llx, op=%d, val=%d\n",
uaddr, op, val);
op &= ~OS::TGT_FUTEX_PRIVATE_FLAG;
if (op == OS::TGT_FUTEX_WAIT) {
if (timeout != 0) {
- warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;"
+ warn("futex: FUTEX_WAIT with non-null timeout unimplemented;"
"we'll wait indefinitely");
}
delete[] buf;
if (val != mem_val) {
- DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, "
+ DPRINTF(SyscallVerbose, "futex: FUTEX_WAKE, read: %d, "
"expected: %d\n", mem_val, val);
return -OS::TGT_EWOULDBLOCK;
}
std::list<ThreadContext *> * >(uaddr, tcWaitList));
}
tcWaitList->push_back(tc);
- DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling "
- "thread context\n");
+ DPRINTF(SyscallVerbose, "futex: FUTEX_WAIT, suspending calling thread "
+ "context on address 0x%lx\n", uaddr);
tc->suspend();
return 0;
} else if (op == OS::TGT_FUTEX_WAKE){
delete tcWaitList;
}
}
- DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting "
- "thread contexts\n", wokenUp);
+ DPRINTF(SyscallVerbose, "futex: FUTEX_WAKE, activated %d waiting "
+ "thread context on address 0x%lx\n",
+ wokenUp, uaddr);
return wokenUp;
} else {
- warn("sys_futex: op %d is not implemented, just returning...", op);
+ warn("futex: op %d is not implemented, just returning...", op);
return 0;
}
new_length = roundUp(new_length, TheISA::PageBytes);
if (new_length > old_length) {
- if ((start + old_length) == process->mmap_end &&
+ if ((start + old_length) == process->memState->mmapEnd &&
(!use_provided_address || provided_address == start)) {
uint64_t diff = new_length - old_length;
- process->allocateMem(process->mmap_end, diff);
- process->mmap_end += diff;
+ process->allocateMem(process->memState->mmapEnd, diff);
+ process->memState->mmapEnd += diff;
return start;
} else {
if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
return -ENOMEM;
} else {
uint64_t new_start = use_provided_address ?
- provided_address : process->mmap_end;
+ provided_address : process->memState->mmapEnd;
process->pTable->remap(start, old_length, new_start);
warn("mremapping to new vaddr %08p-%08p, adding %d\n",
new_start, new_start + new_length,
new_length - old_length,
use_provided_address /* clobber */);
if (!use_provided_address)
- process->mmap_end += new_length;
+ process->memState->mmapEnd += new_length;
if (use_provided_address &&
- new_start + new_length > process->mmap_end) {
+ new_start + new_length > process->memState->mmapEnd) {
// something fishy going on here, at least notify the user
// @todo: increase mmap_end?
warn("mmap region limit exceeded with MREMAP_FIXED\n");
return 0;
}
+template <class OS>
+SyscallReturn
+cloneFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
+{
+ int index = 0;
+ TheISA::IntReg flags = p->getSyscallArg(tc, index);
+ TheISA::IntReg newStack = p->getSyscallArg(tc, index);
+ Addr ptidPtr = p->getSyscallArg(tc, index);
+ Addr ctidPtr = p->getSyscallArg(tc, index);
+ Addr tlsPtr M5_VAR_USED = p->getSyscallArg(tc, index);
+
+ if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) ||
+ ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) ||
+ ((flags & OS::TGT_CLONE_FS) && (flags & OS::TGT_CLONE_NEWNS)) ||
+ ((flags & OS::TGT_CLONE_NEWIPC) && (flags & OS::TGT_CLONE_SYSVSEM)) ||
+ ((flags & OS::TGT_CLONE_NEWPID) && (flags & OS::TGT_CLONE_THREAD)) ||
+ ((flags & OS::TGT_CLONE_VM) && !(newStack)))
+ return -EINVAL;
+
+ ThreadContext *ctc;
+ if (!(ctc = p->findFreeContext()))
+ fatal("clone: no spare thread context in system");
+
+ /**
+ * Note that ProcessParams is generated by swig and there are no other
+ * examples of how to create anything but this default constructor. The
+ * fields are manually initialized instead of passing parameters to the
+ * constructor.
+ */
+ ProcessParams *pp = new ProcessParams();
+ pp->executable.assign(*(new std::string(p->progName())));
+ pp->cmd.push_back(*(new std::string(p->progName())));
+ pp->system = p->system;
+ pp->maxStackSize = p->maxStackSize;
+ pp->cwd.assign(p->getcwd());
+ pp->input.assign("stdin");
+ pp->output.assign("stdout");
+ pp->errout.assign("stderr");
+ pp->uid = p->uid();
+ pp->euid = p->euid();
+ pp->gid = p->gid();
+ pp->egid = p->egid();
+
+ /* Find the first free PID that's less than the maximum */
+ std::set<int> const& pids = p->system->PIDs;
+ int temp_pid = *pids.begin();
+ do {
+ temp_pid++;
+ } while (pids.find(temp_pid) != pids.end());
+ if (temp_pid >= System::maxPID)
+ fatal("temp_pid is too large: %d", temp_pid);
+
+ pp->pid = temp_pid;
+ pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid();
+ Process *cp = pp->create();
+ delete pp;
+
+ Process *owner = ctc->getProcessPtr();
+ ctc->setProcessPtr(cp);
+ cp->assignThreadContext(ctc->contextId());
+ owner->revokeThreadContext(ctc->contextId());
+
+ if (flags & OS::TGT_CLONE_PARENT_SETTID) {
+ BufferArg ptidBuf(ptidPtr, sizeof(long));
+ long *ptid = (long *)ptidBuf.bufferPtr();
+ *ptid = cp->pid();
+ ptidBuf.copyOut(tc->getMemProxy());
+ }
+
+ cp->initState();
+ p->clone(tc, ctc, cp, flags);
+
+ if (flags & OS::TGT_CLONE_CHILD_SETTID) {
+ BufferArg ctidBuf(ctidPtr, sizeof(long));
+ long *ctid = (long *)ctidBuf.bufferPtr();
+ *ctid = cp->pid();
+ ctidBuf.copyOut(ctc->getMemProxy());
+ }
+
+ if (flags & OS::TGT_CLONE_CHILD_CLEARTID)
+ cp->childClearTID = (uint64_t)ctidPtr;
+
+ ctc->clearArchRegs();
+
+#if THE_ISA == ALPHA_ISA
+ TheISA::copyMiscRegs(tc, ctc);
+#elif THE_ISA == SPARC_ISA
+ TheISA::copyRegs(tc, ctc);
+ ctc->setIntReg(TheISA::NumIntArchRegs + 6, 0);
+ ctc->setIntReg(TheISA::NumIntArchRegs + 4, 0);
+ ctc->setIntReg(TheISA::NumIntArchRegs + 3, TheISA::NWindows - 2);
+ ctc->setIntReg(TheISA::NumIntArchRegs + 5, TheISA::NWindows);
+ ctc->setMiscReg(TheISA::MISCREG_CWP, 0);
+ ctc->setIntReg(TheISA::NumIntArchRegs + 7, 0);
+ ctc->setMiscRegNoEffect(TheISA::MISCREG_TL, 0);
+ ctc->setMiscReg(TheISA::MISCREG_ASI, TheISA::ASI_PRIMARY);
+ for (int y = 8; y < 32; y++)
+ ctc->setIntReg(y, tc->readIntReg(y));
+#elif THE_ISA == ARM_ISA or THE_ISA == X86_ISA
+ TheISA::copyRegs(tc, ctc);
+#endif
+
+#if THE_ISA == X86_ISA
+ if (flags & OS::TGT_CLONE_SETTLS) {
+ ctc->setMiscRegNoEffect(TheISA::MISCREG_FS_BASE, tlsPtr);
+ ctc->setMiscRegNoEffect(TheISA::MISCREG_FS_EFF_BASE, tlsPtr);
+ }
+#endif
+
+ if (newStack)
+ ctc->setIntReg(TheISA::StackPointerReg, newStack);
+
+ cp->setSyscallReturn(ctc, 0);
+
+#if THE_ISA == ALPHA_ISA
+ ctc->setIntReg(TheISA::SyscallSuccessReg, 0);
+#elif THE_ISA == SPARC_ISA
+ tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0);
+ ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
+#endif
+
+ ctc->pcState(tc->nextInstAddr());
+ ctc->activate();
+
+ return cp->pid();
+}
/// Target fstatfs() handler.
template <class OS>
// Extend global mmap region if necessary. Note that we ignore the
// start address unless MAP_FIXED is specified.
if (!(tgt_flags & OS::TGT_MAP_FIXED)) {
- start = p->mmapGrowsDown() ? p->mmap_end - length : p->mmap_end;
- p->mmap_end = p->mmapGrowsDown() ? start : p->mmap_end + length;
+ Addr *end = &p->memState->mmapEnd;
+ start = p->mmapGrowsDown() ? *end - length : *end;
+ *end = p->mmapGrowsDown() ? start : *end + length;
}
DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n",
return 0;
}
+
+template <class OS>
+SyscallReturn
+execveFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
+{
+ desc->setFlags(0);
+
+ int index = 0;
+ std::string path;
+ SETranslatingPortProxy & mem_proxy = tc->getMemProxy();
+ if (!mem_proxy.tryReadString(path, p->getSyscallArg(tc, index)))
+ return -EFAULT;
+
+ if (access(path.c_str(), F_OK) == -1)
+ return -EACCES;
+
+ auto read_in = [](std::vector<std::string> & vect,
+ SETranslatingPortProxy & mem_proxy,
+ Addr mem_loc)
+ {
+ for (int inc = 0; ; inc++) {
+ BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr));
+ b.copyIn(mem_proxy);
+
+ if (!*(Addr*)b.bufferPtr())
+ break;
+
+ vect.push_back(std::string());
+ mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr());
+ }
+ };
+
+ /**
+ * Note that ProcessParams is generated by swig and there are no other
+ * examples of how to create anything but this default constructor. The
+ * fields are manually initialized instead of passing parameters to the
+ * constructor.
+ */
+ ProcessParams *pp = new ProcessParams();
+ pp->executable = path;
+ Addr argv_mem_loc = p->getSyscallArg(tc, index);
+ read_in(pp->cmd, mem_proxy, argv_mem_loc);
+ Addr envp_mem_loc = p->getSyscallArg(tc, index);
+ read_in(pp->env, mem_proxy, envp_mem_loc);
+ pp->uid = p->uid();
+ pp->egid = p->egid();
+ pp->euid = p->euid();
+ pp->gid = p->gid();
+ pp->ppid = p->ppid();
+ pp->pid = p->pid();
+ pp->input.assign("cin");
+ pp->output.assign("cout");
+ pp->errout.assign("cerr");
+ pp->cwd.assign(p->getcwd());
+ pp->system = p->system;
+ pp->maxStackSize = p->maxStackSize;
+ /**
+ * Prevent process object creation with identical PIDs (which will trip
+ * a fatal check in Process constructor). The execve call is supposed to
+ * take over the currently executing process' identity but replace
+ * whatever it is doing with a new process image. Instead of hijacking
+ * the process object in the simulator, we create a new process object
+ * and bind to the previous process' thread below (hijacking the thread).
+ */
+ p->system->PIDs.erase(p->pid());
+ Process *new_p = pp->create();
+ delete pp;
+
+ /**
+ * Work through the file descriptor array and close any files marked
+ * close-on-exec.
+ */
+ new_p->fds = p->fds;
+ for (int i = 0; i < new_p->fds->getSize(); i++) {
+ std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i];
+ if (fdep && fdep->getCOE())
+ new_p->fds->closeFDEntry(i);
+ }
+
+ *new_p->sigchld = true;
+
+ delete p;
+ tc->clearArchRegs();
+ tc->setProcessPtr(new_p);
+ new_p->assignThreadContext(tc->contextId());
+ new_p->initState();
+ tc->activate();
+ TheISA::PCState pcState = tc->pcState();
+ tc->setNPC(pcState.instAddr());
+
+ desc->setFlags(SyscallDesc::SuppressReturnValue);
+ return 0;
+}
+
/// Target getrusage() function.
template <class OS>
SyscallReturn