diff options
Diffstat (limited to 'src')
33 files changed, 833 insertions, 285 deletions
diff --git a/src/arch/alpha/linux/process.cc b/src/arch/alpha/linux/process.cc index 4a5dbd24f..dbfbcaf6a 100644 --- a/src/arch/alpha/linux/process.cc +++ b/src/arch/alpha/linux/process.cc @@ -440,7 +440,7 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = { /* 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), diff --git a/src/arch/alpha/process.cc b/src/arch/alpha/process.cc index 582dbb57d..64d0b54a9 100644 --- a/src/arch/alpha/process.cc +++ b/src/arch/alpha/process.cc @@ -50,19 +50,20 @@ using namespace std; 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); } @@ -130,15 +131,15 @@ AlphaProcess::argsInit(int intSize, int pageSize) 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; @@ -153,7 +154,7 @@ AlphaProcess::argsInit(int intSize, int pageSize) 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); @@ -170,7 +171,7 @@ AlphaProcess::argsInit(int intSize, int pageSize) setSyscallArg(tc, 0, argc); setSyscallArg(tc, 1, argv_array_base); - tc->setIntReg(StackPointerReg, stack_min); + tc->setIntReg(StackPointerReg, memState->stackMin); tc->pcState(getStartPC()); } diff --git a/src/arch/arm/linux/process.cc b/src/arch/arm/linux/process.cc index b8f40be81..9bca571e5 100644 --- a/src/arch/arm/linux/process.cc +++ b/src/arch/arm/linux/process.cc @@ -241,7 +241,7 @@ static SyscallDesc syscallDescs32[] = { /* 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), diff --git a/src/arch/arm/process.cc b/src/arch/arm/process.cc index 2fd5cc935..fd0243c44 100644 --- a/src/arch/arm/process.cc +++ b/src/arch/arm/process.cc @@ -70,34 +70,36 @@ ArmProcess32::ArmProcess32(ProcessParams *params, ObjectFile *objFile, 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 @@ -300,15 +302,16 @@ ArmProcess::argsInit(int pageSize, IntRegIndex spIndex) 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; @@ -329,7 +332,7 @@ ArmProcess::argsInit(int pageSize, IntRegIndex spIndex) 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 @@ -375,7 +378,7 @@ ArmProcess::argsInit(int pageSize, IntRegIndex spIndex) 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); @@ -401,8 +404,8 @@ ArmProcess::argsInit(int pageSize, IntRegIndex spIndex) 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 diff --git a/src/arch/generic/types.hh b/src/arch/generic/types.hh index 2de8ca7b4..78ead6832 100644 --- a/src/arch/generic/types.hh +++ b/src/arch/generic/types.hh @@ -148,6 +148,12 @@ class SimplePCState : public PCStateBase npc(val + sizeof(MachInst)); }; + void + setNPC(Addr val) + { + npc(val); + } + SimplePCState() {} SimplePCState(Addr val) { set(val); } diff --git a/src/arch/mips/process.cc b/src/arch/mips/process.cc index c1943bf39..4993b3c68 100644 --- a/src/arch/mips/process.cc +++ b/src/arch/mips/process.cc @@ -53,17 +53,18 @@ MipsProcess::MipsProcess(ProcessParams * params, ObjectFile *objFile) { // 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 @@ -140,15 +141,15 @@ MipsProcess::argsInit(int pageSize) 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; @@ -159,7 +160,7 @@ MipsProcess::argsInit(int pageSize) 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); @@ -184,7 +185,7 @@ MipsProcess::argsInit(int pageSize) setSyscallArg(tc, 0, argc); setSyscallArg(tc, 1, argv_array_base); - tc->setIntReg(StackPointerReg, stack_min); + tc->setIntReg(StackPointerReg, memState->stackMin); tc->pcState(getStartPC()); } diff --git a/src/arch/power/process.cc b/src/arch/power/process.cc index 7359fbf9a..5a32218ef 100644 --- a/src/arch/power/process.cc +++ b/src/arch/power/process.cc @@ -51,17 +51,18 @@ using namespace PowerISA; 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 @@ -185,15 +186,16 @@ PowerProcess::argsInit(int intSize, int pageSize) 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; @@ -212,7 +214,7 @@ PowerProcess::argsInit(int intSize, int pageSize) 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 @@ -257,12 +259,12 @@ PowerProcess::argsInit(int intSize, int pageSize) 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 diff --git a/src/arch/riscv/process.cc b/src/arch/riscv/process.cc index 6bc328325..8b168cb35 100644 --- a/src/arch/riscv/process.cc +++ b/src/arch/riscv/process.cc @@ -56,16 +56,16 @@ RiscvProcess::RiscvProcess(ProcessParams * params, { // 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 @@ -124,18 +124,19 @@ RiscvProcess::argsInit(int pageSize) 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()) @@ -160,7 +161,7 @@ RiscvProcess::argsInit(int pageSize) } } - 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) { @@ -211,7 +212,7 @@ RiscvProcess::argsInit(int pageSize) } ThreadContext *tc = system->getThreadContext(contextIds[0]); - tc->setIntReg(StackPointerReg, stack_min); + tc->setIntReg(StackPointerReg, memState->stackMin); tc->pcState(getStartPC()); } diff --git a/src/arch/sparc/linux/syscalls.cc b/src/arch/sparc/linux/syscalls.cc index 6825b2abb..7fdc922ef 100644 --- a/src/arch/sparc/linux/syscalls.cc +++ b/src/arch/sparc/linux/syscalls.cc @@ -305,7 +305,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = { /* 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 @@ -611,7 +611,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = { /* 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), diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc index a8359a9ce..a64bc587f 100644 --- a/src/arch/sparc/process.cc +++ b/src/arch/sparc/process.cc @@ -59,11 +59,12 @@ SparcProcess::SparcProcess(ProcessParams * params, ObjectFile *objFile, { // 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; @@ -324,15 +325,16 @@ SparcProcess::argsInit(int pageSize) 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; @@ -356,9 +358,9 @@ SparcProcess::argsInit(int pageSize) 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 @@ -397,7 +399,7 @@ SparcProcess::argsInit(int pageSize) // 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]); @@ -405,7 +407,7 @@ SparcProcess::argsInit(int pageSize) // 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. @@ -414,7 +416,7 @@ SparcProcess::argsInit(int pageSize) tc->pcState(getStartPC()); // Align the "stack_min" to a page boundary. - stack_min = roundDown(stack_min, pageSize); + memState->stackMin = roundDown(memState->stackMin, pageSize); } void diff --git a/src/arch/sparc/process.hh b/src/arch/sparc/process.hh index efdc0f443..96901fde3 100644 --- a/src/arch/sparc/process.hh +++ b/src/arch/sparc/process.hh @@ -79,10 +79,10 @@ class Sparc32Process : public SparcProcess { // 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(); @@ -109,10 +109,10 @@ class Sparc64Process : public SparcProcess { // 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(); diff --git a/src/arch/x86/linux/process.cc b/src/arch/x86/linux/process.cc index 56688fc89..c2d67eb81 100644 --- a/src/arch/x86/linux/process.cc +++ b/src/arch/x86/linux/process.cc @@ -276,10 +276,10 @@ static SyscallDesc syscallDescs64[] = { /* 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), @@ -438,7 +438,7 @@ static SyscallDesc syscallDescs64[] = { /* 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), @@ -542,6 +542,12 @@ X86_64LinuxProcess::X86_64LinuxProcess(ProcessParams * params, 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), @@ -554,7 +560,7 @@ static SyscallDesc syscallDescs32[] = { /* 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), @@ -663,7 +669,7 @@ static SyscallDesc syscallDescs32[] = { /* 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), @@ -801,7 +807,7 @@ static SyscallDesc syscallDescs32[] = { /* 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), @@ -873,3 +879,9 @@ I386LinuxProcess::I386LinuxProcess(ProcessParams * params, ObjectFile *objFile) : 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); +} diff --git a/src/arch/x86/linux/process.hh b/src/arch/x86/linux/process.hh index 70370960b..bafa9cc6c 100644 --- a/src/arch/x86/linux/process.hh +++ b/src/arch/x86/linux/process.hh @@ -44,6 +44,9 @@ #include "arch/x86/process.hh" #include "sim/process.hh" +struct ProcessParams; +struct ThreadContext; + namespace X86ISA { class X86_64LinuxProcess : public X86_64Process @@ -51,6 +54,8 @@ 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 @@ -58,6 +63,8 @@ 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 diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc index 35ea70430..a929897ca 100644 --- a/src/arch/x86/process.cc +++ b/src/arch/x86/process.cc @@ -100,8 +100,17 @@ X86Process::X86Process(ProcessParams * params, ObjectFile *objFile, : 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, @@ -117,10 +126,10 @@ 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. @@ -130,7 +139,7 @@ X86_64Process::X86_64Process(ProcessParams *params, ObjectFile *objFile, // 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 @@ -159,10 +168,10 @@ I386Process::I386Process(ProcessParams *params, ObjectFile *objFile, 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. @@ -172,7 +181,7 @@ I386Process::I386Process(ProcessParams *params, ObjectFile *objFile, // 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* @@ -946,18 +955,21 @@ X86Process::argsInit(int pageSize, 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; @@ -976,7 +988,7 @@ X86Process::argsInit(int pageSize, 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 @@ -1023,14 +1035,14 @@ X86Process::argsInit(int pageSize, 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 @@ -1074,6 +1086,14 @@ X86_64Process::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val) 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) { @@ -1098,3 +1118,11 @@ I386Process::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val) 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; +} diff --git a/src/arch/x86/process.hh b/src/arch/x86/process.hh index 9e3fafbdd..4240ee625 100644 --- a/src/arch/x86/process.hh +++ b/src/arch/x86/process.hh @@ -82,6 +82,21 @@ namespace X86ISA 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 @@ -97,6 +112,20 @@ namespace X86ISA 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; @@ -108,6 +137,8 @@ namespace X86ISA /// 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 @@ -123,6 +154,20 @@ namespace X86ISA 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; @@ -134,6 +179,8 @@ namespace X86ISA 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); }; /** diff --git a/src/arch/x86/types.hh b/src/arch/x86/types.hh index 6451056ee..954f9f16e 100644 --- a/src/arch/x86/types.hh +++ b/src/arch/x86/types.hh @@ -305,6 +305,13 @@ namespace X86ISA 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; } diff --git a/src/cpu/checker/thread_context.hh b/src/cpu/checker/thread_context.hh index 0313d079b..7b09dde90 100644 --- a/src/cpu/checker/thread_context.hh +++ b/src/cpu/checker/thread_context.hh @@ -130,6 +130,8 @@ class CheckerThreadContext : public ThreadContext Process *getProcessPtr() { return actualTC->getProcessPtr(); } + void setProcessPtr(Process *p) { actualTC->setProcessPtr(p); } + PortProxy &getPhysProxy() { return actualTC->getPhysProxy(); } FSTranslatingPortProxy &getVirtProxy() @@ -254,6 +256,12 @@ class CheckerThreadContext : public ThreadContext return actualTC->pcState(val); } + void setNPC(Addr val) + { + checkerTC->setNPC(val); + actualTC->setNPC(val); + } + void pcStateNoRecord(const TheISA::PCState &val) { return actualTC->pcState(val); diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh index 0321f57f7..78b88ac2a 100755 --- a/src/cpu/o3/thread_context.hh +++ b/src/cpu/o3/thread_context.hh @@ -119,6 +119,8 @@ class O3ThreadContext : public ThreadContext /** 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(); diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index 9ef00ab3f..bdf93b0e4 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -355,6 +355,12 @@ class SimpleThread : public ThreadState return _pcState.nextInstAddr(); } + void + setNPC(Addr val) + { + _pcState.setNPC(val); + } + MicroPC microPC() { diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh index ecbd1a41e..bb6b54c08 100644 --- a/src/cpu/thread_context.hh +++ b/src/cpu/thread_context.hh @@ -161,6 +161,8 @@ class ThreadContext virtual Process *getProcessPtr() = 0; + virtual void setProcessPtr(Process *p) = 0; + virtual Status status() const = 0; virtual void setStatus(Status new_status) = 0; @@ -223,6 +225,14 @@ class ThreadContext 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; @@ -360,6 +370,8 @@ class ProxyThreadContext : public ThreadContext 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); } diff --git a/src/cpu/thread_state.hh b/src/cpu/thread_state.hh index 3a35d444a..5cbc3322b 100644 --- a/src/cpu/thread_state.hh +++ b/src/cpu/thread_state.hh @@ -107,6 +107,21 @@ struct ThreadState : public Serializable { 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 diff --git a/src/gpu-compute/shader.cc b/src/gpu-compute/shader.cc index e47edce2c..6deaaab94 100644 --- a/src/gpu-compute/shader.cc +++ b/src/gpu-compute/shader.cc @@ -79,18 +79,19 @@ Shader::mmap(int length) 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); diff --git a/src/mem/page_table.cc b/src/mem/page_table.cc index 8ff640837..0abe8eaf3 100644 --- a/src/mem/page_table.cc +++ b/src/mem/page_table.cc @@ -104,6 +104,13 @@ FuncPageTable::remap(Addr vaddr, int64_t size, Addr new_vaddr) } 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) { assert(pageOffset(vaddr) == 0); diff --git a/src/mem/page_table.hh b/src/mem/page_table.hh index 9b24c0efa..0d0a75ef5 100644 --- a/src/mem/page_table.hh +++ b/src/mem/page_table.hh @@ -194,6 +194,9 @@ class PageTableBase : public Serializable pTableCache[2].valid = false; } } + + virtual void getMappings(std::vector<std::pair<Addr, Addr>> + *addr_mappings) {}; }; /** @@ -239,6 +242,8 @@ class FuncPageTable : public PageTableBase void serialize(CheckpointOut &cp) const override; void unserialize(CheckpointIn &cp) override; + + void getMappings(std::vector<std::pair<Addr, Addr>> *addr_maps) override; }; /** diff --git a/src/mem/se_translating_port_proxy.hh b/src/mem/se_translating_port_proxy.hh index bb823a75b..5ac6b5286 100644 --- a/src/mem/se_translating_port_proxy.hh +++ b/src/mem/se_translating_port_proxy.hh @@ -83,6 +83,8 @@ class SETranslatingPortProxy : public PortProxy 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; diff --git a/src/sim/Process.py b/src/sim/Process.py index 9c4ee4760..743e5247c 100644 --- a/src/sim/Process.py +++ b/src/sim/Process.py @@ -40,7 +40,7 @@ class Process(SimObject): 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') diff --git a/src/sim/fd_array.cc b/src/sim/fd_array.cc index d73707054..9b6cbb573 100644 --- a/src/sim/fd_array.cc +++ b/src/sim/fd_array.cc @@ -322,6 +322,13 @@ FDArray::getFDEntry(int tgt_fd) 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) { diff --git a/src/sim/fd_array.hh b/src/sim/fd_array.hh index 1d57c4654..a41e078e7 100644 --- a/src/sim/fd_array.hh +++ b/src/sim/fd_array.hh @@ -104,6 +104,14 @@ class FDArray 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. * Used to "close" the target file descriptor. diff --git a/src/sim/process.cc b/src/sim/process.cc index caf986123..7cfaf6530 100644 --- a/src/sim/process.cc +++ b/src/sim/process.cc @@ -95,9 +95,6 @@ using namespace TheISA; 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 ? @@ -113,10 +110,10 @@ Process::Process(ProcessParams * params, ObjectFile * obj_file) _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); @@ -124,14 +121,29 @@ Process::Process(ProcessParams * params, ObjectFile * obj_file) 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; } @@ -139,14 +151,98 @@ Process::Process(ProcessParams * params, ObjectFile * obj_file) } 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() { SimObject::regStats(); using namespace Stats; - num_syscalls - .name(name() + ".num_syscalls") + numSyscalls + .name(name() + ".numSyscalls") .desc("Number of system calls") ; } @@ -154,15 +250,27 @@ Process::regStats() 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() { if (contextIds.empty()) @@ -193,24 +301,44 @@ Process::allocateMem(Addr vaddr, int64_t size, bool clobber) 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; @@ -221,12 +349,12 @@ Process::fixupStackFault(Addr vaddr) 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 @@ -244,12 +372,12 @@ Process::serialize(CheckpointOut &cp) const 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 @@ -278,7 +406,7 @@ Process::map(Addr vaddr, Addr paddr, int size, bool cacheable) void Process::syscall(int64_t callnum, ThreadContext *tc, Fault *fault) { - num_syscalls++; + numSyscalls++; SyscallDesc *desc = getDesc(callnum); if (desc == NULL) @@ -318,12 +446,13 @@ Process::updateBias() // 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); } diff --git a/src/sim/process.hh b/src/sim/process.hh index fa2eff6fa..9dc29dcb0 100644 --- a/src/sim/process.hh +++ b/src/sim/process.hh @@ -72,6 +72,39 @@ class Process : public SimObject { } }; + 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; @@ -140,7 +173,13 @@ class Process : public SimObject 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. */ @@ -161,6 +200,12 @@ class Process : public SimObject */ 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; @@ -170,15 +215,7 @@ class Process : public SimObject // 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 @@ -209,6 +246,20 @@ class Process : public SimObject 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__ diff --git a/src/sim/syscall_desc.hh b/src/sim/syscall_desc.hh index b4d24e672..d72803e43 100644 --- a/src/sim/syscall_desc.hh +++ b/src/sim/syscall_desc.hh @@ -107,6 +107,10 @@ class SyscallDesc { 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; diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc index c6b89b0c7..07899ec9a 100644 --- a/src/sim/syscall_emul.cc +++ b/src/sim/syscall_emul.cc @@ -74,18 +74,41 @@ ignoreFunc(SyscallDesc *desc, int callnum, Process *process, 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(); } @@ -130,11 +153,12 @@ brkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) // 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); @@ -159,12 +183,22 @@ brkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) } } - 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) @@ -860,89 +894,6 @@ getegidFunc(SyscallDesc *desc, int callnum, Process *process, 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) { diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh index e0cbbe786..8a34c3415 100644 --- a/src/sim/syscall_emul.hh +++ b/src/sim/syscall_emul.hh @@ -81,6 +81,7 @@ #include <memory> #include <string> +#include "arch/utility.hh" #include "base/intmath.hh" #include "base/loader/object_file.hh" #include "base/misc.hh" @@ -90,14 +91,14 @@ #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 @@ -130,6 +131,10 @@ SyscallReturn exitFunc(SyscallDesc *desc, int num, 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); @@ -142,7 +147,7 @@ SyscallReturn brkFunc(SyscallDesc *desc, int num, 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); @@ -272,10 +277,6 @@ SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 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); @@ -304,14 +305,14 @@ futexFunc(SyscallDesc *desc, int callnum, Process *process, 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"); } @@ -321,7 +322,7 @@ futexFunc(SyscallDesc *desc, int callnum, Process *process, 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; } @@ -336,8 +337,8 @@ futexFunc(SyscallDesc *desc, int callnum, Process *process, 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){ @@ -355,11 +356,12 @@ futexFunc(SyscallDesc *desc, int callnum, Process *process, 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; } @@ -883,11 +885,11 @@ mremapFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 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)) { @@ -895,7 +897,7 @@ mremapFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 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, @@ -905,9 +907,9 @@ mremapFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 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"); @@ -1179,6 +1181,132 @@ statfsFunc(SyscallDesc *desc, int callnum, Process *process, 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> @@ -1329,8 +1457,9 @@ mmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, // 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", @@ -1584,6 +1713,100 @@ utimesFunc(SyscallDesc *desc, int callnum, Process *process, 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 |