Commit 5aba43bd authored by Dmitry Safonov's avatar Dmitry Safonov Committed by Andrei Vagin

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: 's avatarDmitry Safonov <dsafonov@virtuozzo.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent d58750c9
...@@ -496,7 +496,9 @@ static void show_rt_xsave_frame(struct xsave_struct *x) ...@@ -496,7 +496,9 @@ static void show_rt_xsave_frame(struct xsave_struct *x)
int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core) 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; struct xsave_struct *x = &fpu_state->xsave;
/* /*
...@@ -584,51 +586,83 @@ void *mmap_seized(struct parasite_ctl *ctl, ...@@ -584,51 +586,83 @@ void *mmap_seized(struct parasite_ctl *ctl,
return (void *)map; 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 */ CPREG32(gs);
if (r->gpregs_case != USER_X86_REGS_CASE_T__NATIVE) { CPREG32(fs);
pr_err("Can't prepare rt_sigframe for compatible task restore\n"); CPREG32(es);
return -1; CPREG32(ds);
}
#define CPREG1(d) f->uc.uc_mcontext.d = r->d CPREG32(di); CPREG32(si); CPREG32(bp); CPREG32(sp); CPREG32(bx);
#define CPREG2(d, s) f->uc.uc_mcontext.d = r->s CPREG32(dx); CPREG32(cx); CPREG32(ip); CPREG32(ax);
CPREG32(cs);
CPREG32(ss);
CPREG32(flags);
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
CPREG1(r8); f->is_native = false;
CPREG1(r9);
CPREG1(r10);
CPREG1(r11);
CPREG1(r12);
CPREG1(r13);
CPREG1(r14);
CPREG1(r15);
#endif #endif
}
#undef CPREG32
CPREG2(rdi, di); #ifdef CONFIG_X86_64
CPREG2(rsi, si); #define CPREG64(d, s) f->native.uc.uc_mcontext.d = r->s
CPREG2(rbp, bp); static void restore_native_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r)
CPREG2(rbx, bx); {
CPREG2(rdx, dx); CPREG64(rdi, di);
CPREG2(rax, ax); CPREG64(rsi, si);
CPREG2(rcx, cx); CPREG64(rbp, bp);
CPREG2(rsp, sp); CPREG64(rsp, sp);
CPREG2(rip, ip); CPREG64(rbx, bx);
CPREG2(eflags, flags); CPREG64(rdx, dx);
CPREG64(rcx, cx);
CPREG1(cs); CPREG64(rip, ip);
CPREG1(ss); CPREG64(rax, ax);
#ifdef CONFIG_X86_32 CPREG64(r8, r8);
CPREG1(gs); CPREG64(r9, r9);
CPREG1(fs); CPREG64(r10, r10);
CPREG1(es); CPREG64(r11, r11);
CPREG1(ds); CPREG64(r12, r12);
#endif 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; 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 */ /* Copied from the gdb header gdb/nat/x86-dregs.h */
......
...@@ -74,6 +74,39 @@ ...@@ -74,6 +74,39 @@
: "memory") : "memory")
#endif /* CONFIG_X86_64 */ #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_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r);
int restore_nonsigframe_gpregs(UserX86RegsEntry *r); int restore_nonsigframe_gpregs(UserX86RegsEntry *r);
......
...@@ -39,24 +39,141 @@ struct rt_sigcontext { ...@@ -39,24 +39,141 @@ struct rt_sigcontext {
unsigned long reserved1[8]; 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" #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; char *pretcode;
struct rt_ucontext uc; struct rt_ucontext uc;
struct rt_siginfo info; struct rt_siginfo info;
/* fp state follows here */
fpu_state_t fpu_state; fpu_state_t fpu_state;
}; };
#define RT_SIGFRAME_UC(rt_sigframe) (&rt_sigframe->uc) struct rt_sigframe {
#define RT_SIGFRAME_REGIP(rt_sigframe) (rt_sigframe)->uc.uc_mcontext.rip union {
#define RT_SIGFRAME_FPU(rt_sigframe) (&(rt_sigframe)->fpu_state) 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_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) \ #define ARCH_RT_SIGRETURN(new_sp) \
asm volatile( \ asm volatile( \
"movq %0, %%rax \n" \ "movq %0, %%rax \n" \
...@@ -67,6 +184,13 @@ struct rt_sigframe { ...@@ -67,6 +184,13 @@ struct rt_sigframe {
: "r"(new_sp) \ : "r"(new_sp) \
: "rax","rsp","memory") : "rax","rsp","memory")
#else /* CONFIG_X86_64 */ #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) \ #define ARCH_RT_SIGRETURN(new_sp) \
asm volatile( \ asm volatile( \
"movl %0, %%eax \n" \ "movl %0, %%eax \n" \
......
...@@ -10,6 +10,22 @@ ...@@ -10,6 +10,22 @@
#include "images/core.pb-c.h" #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 void rt_signalfn_t(int, siginfo_t *, void *);
typedef rt_signalfn_t *rt_sighandler_t; typedef rt_signalfn_t *rt_sighandler_t;
......
...@@ -7,15 +7,24 @@ ...@@ -7,15 +7,24 @@
#include "log.h" #include "log.h"
int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe, 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; unsigned long addr = (unsigned long)(void *)&fpu_state->xsave;
if ((addr % 64ul) == 0ul) { if (sigframe->is_native && (addr % 64ul) == 0ul) {
sigframe->uc.uc_mcontext.fpstate = &fpu_state->xsave; 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 { } else {
pr_err("Unaligned address passed: %lx\n", addr); pr_err("Unaligned address passed: %lx (native %d)\n",
addr, sigframe->is_native);
return -1; return -1;
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "restore.h" #include "restore.h"
#include "images/core.pb-c.h" #include "images/core.pb-c.h"
#ifndef setup_sas
static inline void setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas) static inline void setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas)
{ {
if (sas) { if (sas) {
...@@ -14,20 +15,28 @@ static inline void setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas) ...@@ -14,20 +15,28 @@ static inline void setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas)
#undef UC #undef UC
} }
} }
#endif
#ifndef RT_SIGFRAME_UC_SIGMASK
#define RT_SIGFRAME_UC_SIGMASK(sigframe) \ #define RT_SIGFRAME_UC_SIGMASK(sigframe) \
(k_rtsigset_t*)&RT_SIGFRAME_UC(sigframe)->uc_sigmask (k_rtsigset_t*)&RT_SIGFRAME_UC(sigframe)->uc_sigmask
#endif
int construct_sigframe(struct rt_sigframe *sigframe, int construct_sigframe(struct rt_sigframe *sigframe,
struct rt_sigframe *rsigframe, struct rt_sigframe *rsigframe,
k_rtsigset_t *blkset, k_rtsigset_t *blkset,
CoreEntry *core) 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)) if (restore_gpregs(sigframe, CORE_THREAD_ARCH_INFO(core)->gpregs))
return -1; return -1;
blk_sigset = RT_SIGFRAME_UC_SIGMASK(sigframe);
if (blkset) if (blkset)
memcpy(blk_sigset, blkset, sizeof(k_rtsigset_t)); memcpy(blk_sigset, blkset, sizeof(k_rtsigset_t));
else else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment