mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-01-23 02:14:37 +00:00
compel: Add support for ppc64le scv syscalls
Power ISA 3.0 added a new syscall instruction. Kernel 5.9 added corresponding support. Add CRIU support to recognize the new instruction and kernel ABI changes to properly dump and restore threads executing in syscalls. Without this change threads executing in syscalls using the scv instruction will not be restored to re-execute the syscall, they will be restored to execute the following instruction and will return unexpected error codes (ERESTARTSYS, etc) to user code. Signed-off-by: Younes Manton <ymanton@ca.ibm.com>
This commit is contained in:
parent
d06c9b5cda
commit
59fcfa80d8
1 changed files with 47 additions and 21 deletions
|
|
@ -11,6 +11,7 @@
|
|||
#include "log.h"
|
||||
#include "common/bug.h"
|
||||
#include "common/page.h"
|
||||
#include "common/err.h"
|
||||
#include "infect.h"
|
||||
#include "infect-priv.h"
|
||||
|
||||
|
|
@ -303,34 +304,59 @@ out_free:
|
|||
return -1; /* still failing the checkpoint */
|
||||
}
|
||||
|
||||
static int __get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
|
||||
{
|
||||
pr_info("Dumping GP/FPU registers for %d\n", pid);
|
||||
/*
|
||||
* This is inspired by kernel function check_syscall_restart in
|
||||
* arch/powerpc/kernel/signal.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is inspired by kernel function check_syscall_restart in
|
||||
* arch/powerpc/kernel/signal.c
|
||||
*/
|
||||
#ifndef TRAP
|
||||
#define TRAP(r) ((r).trap & ~0xF)
|
||||
#endif
|
||||
|
||||
if (TRAP(*regs) == 0x0C00 && regs->ccr & 0x10000000) {
|
||||
/* Restart the system call */
|
||||
switch (regs->gpr[3]) {
|
||||
case ERESTARTNOHAND:
|
||||
case ERESTARTSYS:
|
||||
case ERESTARTNOINTR:
|
||||
regs->gpr[3] = regs->orig_gpr3;
|
||||
regs->nip -= 4;
|
||||
break;
|
||||
case ERESTART_RESTARTBLOCK:
|
||||
pr_warn("Will restore %d with interrupted system call\n", pid);
|
||||
regs->gpr[3] = EINTR;
|
||||
break;
|
||||
}
|
||||
static bool trap_is_scv(user_regs_struct_t *regs)
|
||||
{
|
||||
return TRAP(*regs) == 0x3000;
|
||||
}
|
||||
|
||||
static bool trap_is_syscall(user_regs_struct_t *regs)
|
||||
{
|
||||
return trap_is_scv(regs) || TRAP(*regs) == 0x0C00;
|
||||
}
|
||||
|
||||
static void handle_syscall(pid_t pid, user_regs_struct_t *regs)
|
||||
{
|
||||
unsigned long ret = regs->gpr[3];
|
||||
|
||||
if (trap_is_scv(regs)) {
|
||||
if (!IS_ERR_VALUE(ret))
|
||||
return;
|
||||
ret = -ret;
|
||||
} else if (!(regs->ccr & 0x10000000)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Restart or interrupt the system call */
|
||||
switch (ret) {
|
||||
case ERESTARTNOHAND:
|
||||
case ERESTARTSYS:
|
||||
case ERESTARTNOINTR:
|
||||
regs->gpr[3] = regs->orig_gpr3;
|
||||
regs->nip -= 4;
|
||||
break;
|
||||
case ERESTART_RESTARTBLOCK:
|
||||
pr_warn("Will restore %d with interrupted system call\n", pid);
|
||||
regs->gpr[3] = trap_is_scv(regs) ? -EINTR : EINTR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int __get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
|
||||
{
|
||||
pr_info("Dumping GP/FPU registers for %d\n", pid);
|
||||
|
||||
if (trap_is_syscall(regs))
|
||||
handle_syscall(pid, regs);
|
||||
|
||||
/* Resetting trap since we are now coming from user space. */
|
||||
regs->trap = 0;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue