arch,sim-se: Update the PC before emulating a system call.

For most system calls, it doesn't matter if the PC is advanced to the
instruction after the system call instruction before or after the system
call itself is invoked, because the system call itself doesn't interact
with it.

For some system calls however, specifically "clone" and "execve",
advancing the PC *after* the system call complicates things, because it
means the system call needs to set the PC to something that will equal
the desired value only *after* it's advanced.

By setting the PC *before* the system call, the system call can set the
PC to whatever it needs to. This means the new cloned context doesn't
need to advance the PC because it's already advanced, and execve doesn't
need to set NPC, it can leave the PC set to the correct value from the
entry point set during Process initialization.

Change-Id: I830607c2e9adcc22e738178fd3663417512e2e56
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/53983
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Matt Sinclair <mattdsinclair@gmail.com>
Maintainer: Matt Sinclair <mattdsinclair@gmail.com>
Reviewed-by: Kyle Roarty <kyleroarty1716@gmail.com>
This commit is contained in:
Gabe Black
2021-12-10 22:51:28 -08:00
parent 9313294efe
commit 8452e7bf19
5 changed files with 10 additions and 14 deletions

View File

@@ -881,15 +881,15 @@ SupervisorCall::invoke(ThreadContext *tc, const StaticInstPtr &inst)
return;
}
// As of now, there isn't a 32 bit thumb version of this instruction.
assert(!machInst.bigThumb);
tc->getSystemPtr()->workload->syscall(tc);
// Advance the PC since that won't happen automatically.
PCState pc = tc->pcState().as<PCState>();
assert(inst);
inst->advancePC(pc);
tc->pcState(pc);
// As of now, there isn't a 32 bit thumb version of this instruction.
assert(!machInst.bigThumb);
tc->getSystemPtr()->workload->syscall(tc);
}
bool

View File

@@ -157,11 +157,12 @@ RiscvFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
if (isInterrupt() && bits(tc->readMiscReg(tvec), 1, 0) == 1)
addr += 4 * _code;
pc_state.set(addr);
tc->pcState(pc_state);
} else {
invokeSE(tc, inst);
inst->advancePC(pc_state);
tc->pcState(pc_state);
invokeSE(tc, inst);
}
tc->pcState(pc_state);
}
void

View File

@@ -120,7 +120,7 @@ EmuLinux::syscall(ThreadContext *tc)
Addr eip = pc.pc();
const auto &vsyscall = proc32->getVSyscallPage();
if (eip >= vsyscall.base && eip < vsyscall.base + vsyscall.size) {
pc.npc(vsyscall.base + vsyscall.vsysexitOffset);
pc.set(vsyscall.base + vsyscall.vsysexitOffset);
tc->pcState(pc);
}
syscallDescs32.get(rax)->doSyscall(tc);

View File

@@ -71,11 +71,12 @@ UnimpFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
void
SESyscallFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
tc->getSystemPtr()->workload->syscall(tc);
// Move the PC forward since that doesn't happen automatically.
std::unique_ptr<PCStateBase> pc(tc->pcState().clone());
inst->advancePC(*pc);
tc->pcState(*pc);
tc->getSystemPtr()->workload->syscall(tc);
}
void

View File

@@ -1703,9 +1703,6 @@ cloneFunc(SyscallDesc *desc, ThreadContext *tc, RegVal flags, RegVal newStack,
desc->returnInto(ctc, 0);
std::unique_ptr<PCStateBase> cpc(tc->pcState().clone());
cpc->advance();
ctc->pcState(*cpc);
ctc->activate();
if (flags & OS::TGT_CLONE_VFORK) {
@@ -2267,9 +2264,6 @@ execveFunc(SyscallDesc *desc, ThreadContext *tc,
new_p->init();
new_p->initState();
tc->activate();
std::unique_ptr<PCStateBase> pc_state(tc->pcState().clone());
pc_state->advance();
tc->pcState(*pc_state);
return SyscallReturn();
}