-
Notifications
You must be signed in to change notification settings - Fork 599
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
Showing
1 changed file
with
48 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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,33 +304,59 @@ static int get_tm_regs(pid_t pid, user_fpregs_struct_t *fpregs) | |
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; | ||
} | ||
Check warning on line 334 in compel/arch/ppc64/src/lib/infect.c GitHub Actions / build
|
||
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; | ||
|