[CRIU] [PATCHv1 05/26] x86: add 32-bit sigframe for rt_sigreturn
Dmitry Safonov
dsafonov at virtuozzo.com
Thu Jun 16 03:53:22 PDT 2016
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 at openvz.org>
Signed-off-by: Dmitry Safonov <dsafonov at virtuozzo.com>
---
criu/arch/x86/crtools.c | 122 +++++++++++++++++---------
criu/arch/x86/include/asm/restorer.h | 165 +++++++++++++++++++++++++++++++++--
criu/arch/x86/include/asm/types.h | 17 +++-
criu/sigframe.c | 17 +++-
4 files changed, 269 insertions(+), 52 deletions(-)
diff --git a/criu/arch/x86/crtools.c b/criu/arch/x86/crtools.c
index b33764a9ad4c..eb5b9592125d 100644
--- a/criu/arch/x86/crtools.c
+++ b/criu/arch/x86/crtools.c
@@ -482,7 +482,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;
/*
@@ -570,60 +572,100 @@ 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);
-
- CPREG1(cs);
- CPREG1(ss);
-
-#ifdef CONFIG_X86_32
- CPREG1(gs);
- CPREG1(fs);
- CPREG1(es);
- CPREG1(ds);
-#endif
+#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);
+
+ CPREG64(r8, r8);
+ CPREG64(r9, r9);
+ CPREG64(r10, r10);
+ CPREG64(r11, r11);
+ CPREG64(r12, r12);
+ CPREG64(r13, r13);
+ CPREG64(r14, r14);
+ CPREG64(r15, r15);
+
+ 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
int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe,
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 = (u32)addr;
} else {
pr_err("Unaligned address passed: %lx\n", addr);
return -1;
diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h
index 3c17fc67516b..9c57512696fd 100644
--- a/criu/arch/x86/include/asm/restorer.h
+++ b/criu/arch/x86/include/asm/restorer.h
@@ -36,19 +36,138 @@ struct rt_sigcontext {
unsigned long reserved1[8];
};
+struct rt_sigcontext_32 {
+ u32 gs;
+ u32 fs;
+ u32 es;
+ u32 ds;
+ u32 di;
+ u32 si;
+ u32 bp;
+ u32 sp;
+ u32 bx;
+ u32 dx;
+ u32 cx;
+ u32 ax;
+ u32 trapno;
+ u32 err;
+ u32 ip;
+ u32 cs;
+ u32 flags;
+ u32 sp_at_signal;
+ u32 ss;
+
+ u32 fpstate;
+ u32 oldmask;
+ u32 cr2;
+};
+
#define SIGFRAME_MAX_OFFSET 8
#include "sigframe.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;
+
+#ifdef CONFIG_X86_64
+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));
+}
+#else
+#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 {
+ u32 pretcode;
+ int sig;
+ u32 pinfo;
+ u32 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;
};
-#ifdef CONFIG_X86_64
+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)
+
+/*
+ * 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 )
+
#define ARCH_RT_SIGRETURN(new_sp) \
asm volatile( \
"movq %0, %%rax \n" \
@@ -105,7 +224,8 @@ struct rt_sigframe {
: \
: "r"(ret) \
: "memory")
-#else /* CONFIG_X86_64 */
+#else /* !CONFIG_X86_64 */
+
#define ARCH_RT_SIGRETURN(new_sp) \
asm volatile( \
"movl %0, %%eax \n" \
@@ -133,14 +253,47 @@ struct rt_sigframe {
: \
: "r"(ret) \
: "memory")
-#endif /* CONFIG_X86_64 */
#define RT_SIGFRAME_UC(rt_sigframe) (&rt_sigframe->uc)
-#define RT_SIGFRAME_REGIP(rt_sigframe) (rt_sigframe)->uc.uc_mcontext.rip
+#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)
+#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
+}
-#define RT_SIGFRAME_OFFSET(rt_sigframe) 8
+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);
diff --git a/criu/arch/x86/include/asm/types.h b/criu/arch/x86/include/asm/types.h
index 75621a7d046e..3b328244624b 100644
--- a/criu/arch/x86/include/asm/types.h
+++ b/criu/arch/x86/include/asm/types.h
@@ -139,7 +139,19 @@ static inline bool user_regs_native(user_regs_struct_t *pregs)
((pregs)->native.name) : ((pregs)->compat.name))
#define set_user_reg(pregs, name, val) ((user_regs_native(pregs)) ? \
((pregs)->native.name = (val)) : ((pregs)->compat.name = (val)))
-#else
+static inline int core_is_compat(CoreEntry *c)
+{
+ switch (c->thread_info->gpregs->gpregs_case)
+ {
+ case USER_X86_REGS_CASE_T__NATIVE:
+ return 0;
+ case USER_X86_REGS_CASE_T__COMPAT:
+ return 1;
+ default:
+ return -1;
+ }
+}
+#else /* !CONFIG_X86_64 */
typedef struct {
union {
user_regs_struct32 native;
@@ -148,7 +160,8 @@ typedef struct {
#define user_regs_native(pregs) true
#define get_user_reg(pregs, name) ((pregs)->native.name)
#define set_user_reg(pregs, name, val) ((pregs)->native.name = val)
-#endif
+static inline int core_is_compat(CoreEntry *c) { return 0; }
+#endif /* !CONFIG_X86_64 */
typedef struct {
unsigned short cwd;
diff --git a/criu/sigframe.c b/criu/sigframe.c
index 72eaee965ecf..be471a806efb 100644
--- a/criu/sigframe.c
+++ b/criu/sigframe.c
@@ -6,6 +6,7 @@
#include "images/core.pb-c.h"
+#ifndef setup_sas
static inline void setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas)
{
if (sas) {
@@ -17,16 +18,27 @@ 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,
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 (core->tc)
memcpy(blk_sigset, &core->tc->blk_sigset, sizeof(k_rtsigset_t));
else if (core->thread_core->has_blk_sigset) {
@@ -42,9 +54,6 @@ int construct_sigframe(struct rt_sigframe *sigframe,
if (sigreturn_prep_fpu_frame(sigframe, rsigframe))
return -1;
- if (restore_gpregs(sigframe, CORE_THREAD_ARCH_INFO(core)->gpregs))
- return -1;
-
setup_sas(sigframe, core->thread_core->sas);
return 0;
--
2.8.3
More information about the CRIU
mailing list