mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-28 12:36:47 +00:00
x86: add 32-bit sigframe for rt_sigreturn
I tried to split this patch as much as it goes, but still it's quite huge. Mostly it has many compatible structures declarations. Lesser it contains adaptation to new native/compat sigframe duality. The only logic that changed by this patch is the order of creating sigframe in construct_sigframe. Cc: Cyrill Gorcunov <gorcunov@openvz.org> Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com> Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com> Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
This commit is contained in:
parent
d58750c946
commit
5aba43bdb7
6 changed files with 272 additions and 47 deletions
|
|
@ -496,7 +496,9 @@ static void show_rt_xsave_frame(struct xsave_struct *x)
|
|||
|
||||
int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core)
|
||||
{
|
||||
fpu_state_t *fpu_state = &sigframe->fpu_state;
|
||||
fpu_state_t *fpu_state = core_is_compat(core) ?
|
||||
&sigframe->compat.fpu_state :
|
||||
&sigframe->native.fpu_state;
|
||||
struct xsave_struct *x = &fpu_state->xsave;
|
||||
|
||||
/*
|
||||
|
|
@ -584,51 +586,83 @@ void *mmap_seized(struct parasite_ctl *ctl,
|
|||
return (void *)map;
|
||||
}
|
||||
|
||||
int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r)
|
||||
#ifdef CONFIG_X86_64
|
||||
#define CPREG32(d) f->compat.uc.uc_mcontext.d = r->d
|
||||
#else
|
||||
#define CPREG32(d) f->uc.uc_mcontext.d = r->d
|
||||
#endif
|
||||
static void restore_compat_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r)
|
||||
{
|
||||
/* FIXME: rt_sigcontext for compatible tasks */
|
||||
if (r->gpregs_case != USER_X86_REGS_CASE_T__NATIVE) {
|
||||
pr_err("Can't prepare rt_sigframe for compatible task restore\n");
|
||||
return -1;
|
||||
}
|
||||
CPREG32(gs);
|
||||
CPREG32(fs);
|
||||
CPREG32(es);
|
||||
CPREG32(ds);
|
||||
|
||||
#define CPREG1(d) f->uc.uc_mcontext.d = r->d
|
||||
#define CPREG2(d, s) f->uc.uc_mcontext.d = r->s
|
||||
CPREG32(di); CPREG32(si); CPREG32(bp); CPREG32(sp); CPREG32(bx);
|
||||
CPREG32(dx); CPREG32(cx); CPREG32(ip); CPREG32(ax);
|
||||
CPREG32(cs);
|
||||
CPREG32(ss);
|
||||
CPREG32(flags);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
CPREG1(r8);
|
||||
CPREG1(r9);
|
||||
CPREG1(r10);
|
||||
CPREG1(r11);
|
||||
CPREG1(r12);
|
||||
CPREG1(r13);
|
||||
CPREG1(r14);
|
||||
CPREG1(r15);
|
||||
f->is_native = false;
|
||||
#endif
|
||||
}
|
||||
#undef CPREG32
|
||||
|
||||
CPREG2(rdi, di);
|
||||
CPREG2(rsi, si);
|
||||
CPREG2(rbp, bp);
|
||||
CPREG2(rbx, bx);
|
||||
CPREG2(rdx, dx);
|
||||
CPREG2(rax, ax);
|
||||
CPREG2(rcx, cx);
|
||||
CPREG2(rsp, sp);
|
||||
CPREG2(rip, ip);
|
||||
CPREG2(eflags, flags);
|
||||
#ifdef CONFIG_X86_64
|
||||
#define CPREG64(d, s) f->native.uc.uc_mcontext.d = r->s
|
||||
static void restore_native_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r)
|
||||
{
|
||||
CPREG64(rdi, di);
|
||||
CPREG64(rsi, si);
|
||||
CPREG64(rbp, bp);
|
||||
CPREG64(rsp, sp);
|
||||
CPREG64(rbx, bx);
|
||||
CPREG64(rdx, dx);
|
||||
CPREG64(rcx, cx);
|
||||
CPREG64(rip, ip);
|
||||
CPREG64(rax, ax);
|
||||
|
||||
CPREG1(cs);
|
||||
CPREG1(ss);
|
||||
CPREG64(r8, r8);
|
||||
CPREG64(r9, r9);
|
||||
CPREG64(r10, r10);
|
||||
CPREG64(r11, r11);
|
||||
CPREG64(r12, r12);
|
||||
CPREG64(r13, r13);
|
||||
CPREG64(r14, r14);
|
||||
CPREG64(r15, r15);
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
CPREG1(gs);
|
||||
CPREG1(fs);
|
||||
CPREG1(es);
|
||||
CPREG1(ds);
|
||||
#endif
|
||||
CPREG64(cs, cs);
|
||||
|
||||
CPREG64(eflags, flags);
|
||||
|
||||
f->is_native = true;
|
||||
}
|
||||
#undef CPREG64
|
||||
|
||||
int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r)
|
||||
{
|
||||
switch (r->gpregs_case) {
|
||||
case USER_X86_REGS_CASE_T__NATIVE:
|
||||
restore_native_gpregs(f, r);
|
||||
break;
|
||||
case USER_X86_REGS_CASE_T__COMPAT:
|
||||
restore_compat_gpregs(f, r);
|
||||
break;
|
||||
default:
|
||||
pr_err("Can't prepare rt_sigframe: regs_case corrupt\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else /* !CONFIG_X86_64 */
|
||||
int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r)
|
||||
{
|
||||
restore_compat_gpregs(f, r);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Copied from the gdb header gdb/nat/x86-dregs.h */
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,39 @@
|
|||
: "memory")
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
static inline void
|
||||
__setup_sas_compat(struct ucontext_ia32* uc, ThreadSasEntry *sas)
|
||||
{
|
||||
uc->uc_stack.ss_sp = (compat_uptr_t)(sas)->ss_sp;
|
||||
uc->uc_stack.ss_flags = (int)(sas)->ss_flags;
|
||||
uc->uc_stack.ss_size = (compat_size_t)(sas)->ss_size;
|
||||
}
|
||||
|
||||
static inline void
|
||||
__setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
if (sigframe->is_native) {
|
||||
struct rt_ucontext *uc = &sigframe->native.uc;
|
||||
|
||||
uc->uc_stack.ss_sp = (void *)decode_pointer((sas)->ss_sp);
|
||||
uc->uc_stack.ss_flags = (int)(sas)->ss_flags;
|
||||
uc->uc_stack.ss_size = (size_t)(sas)->ss_size;
|
||||
} else {
|
||||
__setup_sas_compat(&sigframe->compat.uc, sas);
|
||||
}
|
||||
#else
|
||||
__setup_sas_compat(&sigframe->uc, sas);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void _setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas)
|
||||
{
|
||||
if (sas)
|
||||
__setup_sas(sigframe, sas);
|
||||
}
|
||||
#define setup_sas _setup_sas
|
||||
|
||||
int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r);
|
||||
int restore_nonsigframe_gpregs(UserX86RegsEntry *r);
|
||||
|
||||
|
|
|
|||
|
|
@ -39,24 +39,141 @@ struct rt_sigcontext {
|
|||
unsigned long reserved1[8];
|
||||
};
|
||||
|
||||
struct rt_sigcontext_32 {
|
||||
uint32_t gs;
|
||||
uint32_t fs;
|
||||
uint32_t es;
|
||||
uint32_t ds;
|
||||
uint32_t di;
|
||||
uint32_t si;
|
||||
uint32_t bp;
|
||||
uint32_t sp;
|
||||
uint32_t bx;
|
||||
uint32_t dx;
|
||||
uint32_t cx;
|
||||
uint32_t ax;
|
||||
uint32_t trapno;
|
||||
uint32_t err;
|
||||
uint32_t ip;
|
||||
uint32_t cs;
|
||||
uint32_t flags;
|
||||
uint32_t sp_at_signal;
|
||||
uint32_t ss;
|
||||
|
||||
uint32_t fpstate;
|
||||
uint32_t oldmask;
|
||||
uint32_t cr2;
|
||||
};
|
||||
|
||||
#include "sigframe-common.h"
|
||||
|
||||
struct rt_sigframe {
|
||||
/*
|
||||
* XXX: move declarations to generic sigframe.h or sigframe-compat.h
|
||||
* when (if) other architectures will support compatible C/R
|
||||
*/
|
||||
|
||||
typedef u32 compat_uptr_t;
|
||||
typedef u32 compat_size_t;
|
||||
typedef u32 compat_sigset_word;
|
||||
|
||||
#define _COMPAT_NSIG 64
|
||||
#define _COMPAT_NSIG_BPW 32
|
||||
#define _COMPAT_NSIG_WORDS (_COMPAT_NSIG / _COMPAT_NSIG_BPW)
|
||||
|
||||
typedef struct {
|
||||
compat_sigset_word sig[_COMPAT_NSIG_WORDS];
|
||||
} compat_sigset_t;
|
||||
|
||||
typedef struct compat_siginfo {
|
||||
int si_signo;
|
||||
int si_errno;
|
||||
int si_code;
|
||||
int _pad[128/sizeof(int) - 3];
|
||||
} compat_siginfo_t;
|
||||
|
||||
static inline void __always_unused __check_compat_sigset_t(void)
|
||||
{
|
||||
BUILD_BUG_ON(sizeof(compat_sigset_t) != sizeof(k_rtsigset_t));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
#define rt_sigframe_ia32 rt_sigframe
|
||||
#endif
|
||||
|
||||
typedef struct compat_sigaltstack {
|
||||
compat_uptr_t ss_sp;
|
||||
int ss_flags;
|
||||
compat_size_t ss_size;
|
||||
} compat_stack_t;
|
||||
|
||||
struct ucontext_ia32 {
|
||||
unsigned int uc_flags;
|
||||
unsigned int uc_link;
|
||||
compat_stack_t uc_stack;
|
||||
struct rt_sigcontext_32 uc_mcontext;
|
||||
k_rtsigset_t uc_sigmask; /* mask last for extensibility */
|
||||
};
|
||||
|
||||
struct rt_sigframe_ia32 {
|
||||
uint32_t pretcode;
|
||||
int32_t sig;
|
||||
uint32_t pinfo;
|
||||
uint32_t puc;
|
||||
#ifdef CONFIG_X86_64
|
||||
compat_siginfo_t info;
|
||||
#else
|
||||
struct rt_siginfo info;
|
||||
#endif
|
||||
struct ucontext_ia32 uc;
|
||||
char retcode[8];
|
||||
|
||||
/* fp state follows here */
|
||||
fpu_state_t fpu_state;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
struct rt_sigframe_64 {
|
||||
char *pretcode;
|
||||
struct rt_ucontext uc;
|
||||
struct rt_siginfo info;
|
||||
|
||||
/* fp state follows here */
|
||||
fpu_state_t fpu_state;
|
||||
};
|
||||
|
||||
#define RT_SIGFRAME_UC(rt_sigframe) (&rt_sigframe->uc)
|
||||
#define RT_SIGFRAME_REGIP(rt_sigframe) (rt_sigframe)->uc.uc_mcontext.rip
|
||||
#define RT_SIGFRAME_FPU(rt_sigframe) (&(rt_sigframe)->fpu_state)
|
||||
struct rt_sigframe {
|
||||
union {
|
||||
struct rt_sigframe_ia32 compat;
|
||||
struct rt_sigframe_64 native;
|
||||
};
|
||||
bool is_native;
|
||||
};
|
||||
|
||||
#define RT_SIGFRAME_UC_SIGMASK(rt_sigframe) \
|
||||
((rt_sigframe->is_native) ? \
|
||||
(&rt_sigframe->native.uc.uc_sigmask) : \
|
||||
(&rt_sigframe->compat.uc.uc_sigmask))
|
||||
|
||||
#define RT_SIGFRAME_REGIP(rt_sigframe) \
|
||||
((rt_sigframe->is_native) ? \
|
||||
(rt_sigframe)->native.uc.uc_mcontext.rip : \
|
||||
(rt_sigframe)->compat.uc.uc_mcontext.ip)
|
||||
|
||||
#define RT_SIGFRAME_FPU(rt_sigframe) \
|
||||
((rt_sigframe->is_native) ? \
|
||||
(&(rt_sigframe)->native.fpu_state) : \
|
||||
(&(rt_sigframe)->compat.fpu_state))
|
||||
|
||||
#define RT_SIGFRAME_HAS_FPU(rt_sigframe) (RT_SIGFRAME_FPU(rt_sigframe)->has_fpu)
|
||||
|
||||
#define RT_SIGFRAME_OFFSET(rt_sigframe) 8
|
||||
/*
|
||||
* Sigframe offset is different for native/compat tasks.
|
||||
* Offsets calculations one may see at kernel:
|
||||
* - compatible is in sys32_rt_sigreturn at arch/x86/ia32/ia32_signal.c
|
||||
* - native is in sys_rt_sigreturn at arch/x86/kernel/signal.c
|
||||
*/
|
||||
#define RT_SIGFRAME_OFFSET(rt_sigframe) ((rt_sigframe->is_native) ? 8 : 4 )
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#define ARCH_RT_SIGRETURN(new_sp) \
|
||||
asm volatile( \
|
||||
"movq %0, %%rax \n" \
|
||||
|
|
@ -67,6 +184,13 @@ struct rt_sigframe {
|
|||
: "r"(new_sp) \
|
||||
: "rax","rsp","memory")
|
||||
#else /* CONFIG_X86_64 */
|
||||
#define RT_SIGFRAME_UC(rt_sigframe) (&rt_sigframe->uc)
|
||||
#define RT_SIGFRAME_OFFSET(rt_sigframe) 4
|
||||
#define RT_SIGFRAME_REGIP(rt_sigframe) \
|
||||
(unsigned long)(rt_sigframe)->uc.uc_mcontext.ip
|
||||
#define RT_SIGFRAME_FPU(rt_sigframe) (&(rt_sigframe)->fpu_state)
|
||||
#define RT_SIGFRAME_HAS_FPU(rt_sigframe) (RT_SIGFRAME_FPU(rt_sigframe)->has_fpu)
|
||||
|
||||
#define ARCH_RT_SIGRETURN(new_sp) \
|
||||
asm volatile( \
|
||||
"movl %0, %%eax \n" \
|
||||
|
|
|
|||
|
|
@ -10,6 +10,22 @@
|
|||
|
||||
#include "images/core.pb-c.h"
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
static inline int core_is_compat(CoreEntry *c)
|
||||
{
|
||||
switch (c->thread_info->gpregs->mode) {
|
||||
case USER_X86_REGS_MODE__NATIVE:
|
||||
return 0;
|
||||
case USER_X86_REGS_MODE__COMPAT:
|
||||
return 1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#else /* CONFIG_X86_64 */
|
||||
static inline int core_is_compat(CoreEntry *c) { return 0; }
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
typedef void rt_signalfn_t(int, siginfo_t *, void *);
|
||||
typedef rt_signalfn_t *rt_sighandler_t;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,15 +7,24 @@
|
|||
#include "log.h"
|
||||
|
||||
int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe,
|
||||
struct rt_sigframe *rsigframe)
|
||||
struct rt_sigframe *rsigframe)
|
||||
{
|
||||
fpu_state_t *fpu_state = RT_SIGFRAME_FPU(rsigframe);
|
||||
/*
|
||||
* Use local sigframe to check native/compat type,
|
||||
* but set address for rsigframe.
|
||||
*/
|
||||
fpu_state_t *fpu_state = (sigframe->is_native) ?
|
||||
&rsigframe->native.fpu_state :
|
||||
&rsigframe->compat.fpu_state;
|
||||
unsigned long addr = (unsigned long)(void *)&fpu_state->xsave;
|
||||
|
||||
if ((addr % 64ul) == 0ul) {
|
||||
sigframe->uc.uc_mcontext.fpstate = &fpu_state->xsave;
|
||||
if (sigframe->is_native && (addr % 64ul) == 0ul) {
|
||||
sigframe->native.uc.uc_mcontext.fpstate = &fpu_state->xsave;
|
||||
} else if (!sigframe->is_native && (addr % 32ul) == 0ul) {
|
||||
sigframe->compat.uc.uc_mcontext.fpstate = (uint32_t)addr;
|
||||
} else {
|
||||
pr_err("Unaligned address passed: %lx\n", addr);
|
||||
pr_err("Unaligned address passed: %lx (native %d)\n",
|
||||
addr, sigframe->is_native);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "restore.h"
|
||||
#include "images/core.pb-c.h"
|
||||
|
||||
#ifndef setup_sas
|
||||
static inline void setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas)
|
||||
{
|
||||
if (sas) {
|
||||
|
|
@ -14,20 +15,28 @@ static inline void setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas)
|
|||
#undef UC
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef RT_SIGFRAME_UC_SIGMASK
|
||||
#define RT_SIGFRAME_UC_SIGMASK(sigframe) \
|
||||
(k_rtsigset_t*)&RT_SIGFRAME_UC(sigframe)->uc_sigmask
|
||||
#endif
|
||||
|
||||
int construct_sigframe(struct rt_sigframe *sigframe,
|
||||
struct rt_sigframe *rsigframe,
|
||||
k_rtsigset_t *blkset,
|
||||
CoreEntry *core)
|
||||
{
|
||||
k_rtsigset_t *blk_sigset = RT_SIGFRAME_UC_SIGMASK(sigframe);
|
||||
k_rtsigset_t *blk_sigset;
|
||||
|
||||
/*
|
||||
* Copy basic register set in the first place: this will set
|
||||
* rt_sigframe type: native/compat.
|
||||
*/
|
||||
if (restore_gpregs(sigframe, CORE_THREAD_ARCH_INFO(core)->gpregs))
|
||||
return -1;
|
||||
|
||||
blk_sigset = RT_SIGFRAME_UC_SIGMASK(sigframe);
|
||||
if (blkset)
|
||||
memcpy(blk_sigset, blkset, sizeof(k_rtsigset_t));
|
||||
else
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue