kernel/x86_64: add setup_compat_signal_frame.
* add compatibility signal types. Change-Id: I665020234be0ba2ccbb33bdbc338c11a214ab6e8
This commit is contained in:
@@ -31,6 +31,12 @@ bool arch_on_signal_stack(Thread *thread);
|
||||
status_t arch_setup_signal_frame(Thread *thread, struct sigaction *action,
|
||||
struct signal_frame_data *signalFrameData);
|
||||
int64 arch_restore_signal_frame(struct signal_frame_data* signalFrameData);
|
||||
#ifdef _COMPAT_MODE
|
||||
status_t arch_setup_compat_signal_frame(Thread *thread,
|
||||
struct sigaction *action, struct compat_signal_frame_data *signalFrameData);
|
||||
int64 arch_restore_compat_signal_frame(
|
||||
struct compat_signal_frame_data* signalFrameData);
|
||||
#endif
|
||||
|
||||
void arch_store_fork_frame(struct arch_fork_arg *arg);
|
||||
void arch_restore_fork_frame(struct arch_fork_arg *arg);
|
||||
|
||||
@@ -51,6 +51,30 @@ arch_thread_set_current_thread(Thread* t)
|
||||
}
|
||||
|
||||
|
||||
#ifdef _COMPAT_MODE
|
||||
|
||||
|
||||
static inline void
|
||||
arch_thread_set_ds(unsigned short ds)
|
||||
{
|
||||
asm volatile("mov %0, %%ds" : : "r" (ds) : "memory");
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
arch_thread_set_es(unsigned short es)
|
||||
{
|
||||
asm volatile("mov %0, %%es" : : "r" (es) : "memory");
|
||||
}
|
||||
|
||||
// override empty macro
|
||||
#undef arch_syscall_64_bit_return_value
|
||||
void arch_syscall_64_bit_return_value(void);
|
||||
|
||||
|
||||
#endif // _COMPAT_MODE
|
||||
|
||||
|
||||
#else // __x86_64__
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2018, Haiku Inc. All rights reserved.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _KERNEL_COMPAT_ARCH_SIGNAL_H
|
||||
#define _KERNEL_COMPAT_ARCH_SIGNAL_H
|
||||
|
||||
|
||||
typedef struct packed_fp_stack {
|
||||
unsigned char st0[10];
|
||||
unsigned char st1[10];
|
||||
unsigned char st2[10];
|
||||
unsigned char st3[10];
|
||||
unsigned char st4[10];
|
||||
unsigned char st5[10];
|
||||
unsigned char st6[10];
|
||||
unsigned char st7[10];
|
||||
} packed_fp_stack;
|
||||
|
||||
typedef struct packed_mmx_regs {
|
||||
unsigned char mm0[10];
|
||||
unsigned char mm1[10];
|
||||
unsigned char mm2[10];
|
||||
unsigned char mm3[10];
|
||||
unsigned char mm4[10];
|
||||
unsigned char mm5[10];
|
||||
unsigned char mm6[10];
|
||||
unsigned char mm7[10];
|
||||
} packed_mmx_regs;
|
||||
|
||||
typedef struct xmmx_regs {
|
||||
unsigned char xmm0[16];
|
||||
unsigned char xmm1[16];
|
||||
unsigned char xmm2[16];
|
||||
unsigned char xmm3[16];
|
||||
unsigned char xmm4[16];
|
||||
unsigned char xmm5[16];
|
||||
unsigned char xmm6[16];
|
||||
unsigned char xmm7[16];
|
||||
} xmmx_regs;
|
||||
|
||||
typedef struct compat_stack_t {
|
||||
uint32 ss_sp;
|
||||
uint32 ss_size;
|
||||
int ss_flags;
|
||||
} compat_stack_t;
|
||||
|
||||
typedef struct compat_old_extended_regs {
|
||||
unsigned short fp_control;
|
||||
unsigned short _reserved1;
|
||||
unsigned short fp_status;
|
||||
unsigned short _reserved2;
|
||||
unsigned short fp_tag;
|
||||
unsigned short _reserved3;
|
||||
uint32 fp_eip;
|
||||
unsigned short fp_cs;
|
||||
unsigned short fp_opcode;
|
||||
uint32 fp_datap;
|
||||
unsigned short fp_ds;
|
||||
unsigned short _reserved4;
|
||||
union {
|
||||
packed_fp_stack fp;
|
||||
packed_mmx_regs mmx;
|
||||
} fp_mmx;
|
||||
} compat_old_extended_regs;
|
||||
|
||||
typedef struct compat_new_extended_regs {
|
||||
unsigned short fp_control;
|
||||
unsigned short fp_status;
|
||||
unsigned short fp_tag;
|
||||
unsigned short fp_opcode;
|
||||
uint32 fp_eip;
|
||||
unsigned short fp_cs;
|
||||
unsigned short res_14_15;
|
||||
uint32 fp_datap;
|
||||
unsigned short fp_ds;
|
||||
unsigned short _reserved_22_23;
|
||||
uint32 mxcsr;
|
||||
uint32 _reserved_28_31;
|
||||
union {
|
||||
fp_stack fp;
|
||||
mmx_regs mmx;
|
||||
} fp_mmx;
|
||||
xmmx_regs xmmx;
|
||||
unsigned char _reserved_288_511[224];
|
||||
} compat_new_extended_regs;
|
||||
|
||||
typedef struct compat_extended_regs {
|
||||
union {
|
||||
compat_old_extended_regs old_format;
|
||||
compat_new_extended_regs new_format;
|
||||
} state;
|
||||
uint32 format;
|
||||
} compat_extended_regs;
|
||||
|
||||
struct compat_vregs {
|
||||
uint32 eip;
|
||||
uint32 eflags;
|
||||
uint32 eax;
|
||||
uint32 ecx;
|
||||
uint32 edx;
|
||||
uint32 esp;
|
||||
uint32 ebp;
|
||||
uint32 _reserved_1;
|
||||
compat_extended_regs xregs;
|
||||
uint32 edi;
|
||||
uint32 esi;
|
||||
uint32 ebx;
|
||||
};
|
||||
|
||||
|
||||
#endif // _KERNEL_COMPAT_ARCH_SIGNAL_H
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright 2018, Haiku Inc. All rights reserved.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _KERNEL_COMPAT_KSIGNAL_H
|
||||
#define _KERNEL_COMPAT_KSIGNAL_H
|
||||
|
||||
|
||||
#include <compat/signal_compat.h>
|
||||
#include <compat/arch/x86/signal_compat.h>
|
||||
|
||||
|
||||
typedef struct compat_vregs compat_mcontext_t;
|
||||
|
||||
typedef struct __compat_ucontext_t {
|
||||
uint32 uc_link;
|
||||
sigset_t uc_sigmask;
|
||||
compat_stack_t uc_stack;
|
||||
compat_mcontext_t uc_mcontext;
|
||||
} _PACKED compat_ucontext_t;
|
||||
|
||||
union compat_sigval {
|
||||
int sival_int;
|
||||
uint32 sival_ptr;
|
||||
};
|
||||
|
||||
|
||||
typedef struct __compat_siginfo_t {
|
||||
int si_signo; /* signal number */
|
||||
int si_code; /* signal code */
|
||||
int si_errno; /* if non zero, an error number associated with
|
||||
this signal */
|
||||
pid_t si_pid; /* sending process ID */
|
||||
uid_t si_uid; /* real user ID of sending process */
|
||||
uint32 si_addr; /* address of faulting instruction */
|
||||
int si_status; /* exit value or signal */
|
||||
uint32 si_band; /* band event for SIGPOLL */
|
||||
union compat_sigval si_value; /* signal value */
|
||||
} compat_siginfo_t;
|
||||
|
||||
struct compat_signal_frame_data {
|
||||
compat_siginfo_t info;
|
||||
compat_ucontext_t context;
|
||||
uint32 user_data;
|
||||
uint32 handler;
|
||||
bool siginfo_handler;
|
||||
char _pad[3];
|
||||
int32 thread_flags;
|
||||
uint64 syscall_restart_return_value;
|
||||
uint8 syscall_restart_parameters[SYSCALL_RESTART_PARAMETER_SIZE];
|
||||
uint32 commpage_address;
|
||||
} _PACKED;
|
||||
|
||||
|
||||
static_assert(sizeof(compat_stack_t) == 12,
|
||||
"size of compat_stack_t mismatch");
|
||||
static_assert(sizeof(compat_mcontext_t) == 560,
|
||||
"size of compat_mcontext_t mismatch");
|
||||
static_assert(sizeof(compat_ucontext_t) == 584,
|
||||
"size of compat_ucontext_t mismatch");
|
||||
static_assert(sizeof(compat_siginfo_t) == 36,
|
||||
"size of compat_siginfo_t mismatch");
|
||||
static_assert(sizeof(struct compat_signal_frame_data) == 680,
|
||||
"size of compat_signal_frame_data mismatch");
|
||||
|
||||
|
||||
inline status_t
|
||||
copy_ref_var_from_user(union sigval* userSigval, union sigval &sigval)
|
||||
{
|
||||
if (!IS_USER_ADDRESS(userSigval))
|
||||
return B_BAD_ADDRESS;
|
||||
Thread* thread = thread_get_current_thread();
|
||||
bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
|
||||
if (compatMode) {
|
||||
compat_sigval compat_sigval;
|
||||
if (user_memcpy(&compat_sigval, userSigval, sizeof(compat_sigval))
|
||||
< B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
sigval.sival_ptr = (void*)(addr_t)compat_sigval.sival_ptr;
|
||||
} else if (user_memcpy(&sigval, userSigval, sizeof(union sigval)) < B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
copy_ref_var_to_user(siginfo_t &info, siginfo_t* userInfo)
|
||||
{
|
||||
if (!IS_USER_ADDRESS(userInfo))
|
||||
return B_BAD_ADDRESS;
|
||||
Thread* thread = thread_get_current_thread();
|
||||
bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
|
||||
if (compatMode) {
|
||||
compat_siginfo_t compat_info;
|
||||
compat_info.si_signo = info.si_signo;
|
||||
compat_info.si_code = info.si_code;
|
||||
compat_info.si_errno = info.si_errno;
|
||||
compat_info.si_pid = info.si_pid;
|
||||
compat_info.si_uid = info.si_uid;
|
||||
compat_info.si_addr = (addr_t)info.si_addr;
|
||||
compat_info.si_status = info.si_status;
|
||||
compat_info.si_band = info.si_band;
|
||||
compat_info.si_value.sival_ptr = (addr_t)info.si_value.sival_ptr;
|
||||
if (user_memcpy(userInfo, &compat_info, sizeof(compat_info))
|
||||
< B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
} else if (user_memcpy(userInfo, &info, sizeof(info)) < B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
copy_ref_var_from_user(stack_t* userStack, stack_t &stack)
|
||||
{
|
||||
if (!IS_USER_ADDRESS(userStack))
|
||||
return B_BAD_ADDRESS;
|
||||
Thread* thread = thread_get_current_thread();
|
||||
bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
|
||||
if (compatMode) {
|
||||
compat_stack_t compatStack;
|
||||
if (user_memcpy(&compatStack, userStack, sizeof(compatStack))
|
||||
< B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
stack.ss_sp = (void*)(addr_t)compatStack.ss_sp;
|
||||
stack.ss_size = compatStack.ss_size;
|
||||
stack.ss_flags = compatStack.ss_flags;
|
||||
} else if (user_memcpy(&stack, userStack, sizeof(stack_t)) < B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
copy_ref_var_to_user(stack_t &stack, stack_t* userStack)
|
||||
{
|
||||
if (!IS_USER_ADDRESS(userStack))
|
||||
return B_BAD_ADDRESS;
|
||||
Thread* thread = thread_get_current_thread();
|
||||
bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
|
||||
if (compatMode) {
|
||||
compat_stack_t compatStack;
|
||||
compatStack.ss_sp = (addr_t)stack.ss_sp;
|
||||
compatStack.ss_size = stack.ss_size;
|
||||
compatStack.ss_flags = stack.ss_flags;
|
||||
if (user_memcpy(userStack, &compatStack, sizeof(compatStack))
|
||||
< B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
} else if (user_memcpy(userStack, &stack, sizeof(stack)) < B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
#endif // _KERNEL_COMPAT_KSIGNAL_H
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2018, Haiku Inc. All rights reserved.
|
||||
*
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _KERNEL_COMPAT_SIGNAL_H
|
||||
#define _KERNEL_COMPAT_SIGNAL_H
|
||||
|
||||
|
||||
struct compat_sigaction {
|
||||
union {
|
||||
uint32 sa_handler;
|
||||
uint32 sa_sigaction;
|
||||
};
|
||||
sigset_t sa_mask;
|
||||
int sa_flags;
|
||||
uint32 sa_userdata; /* will be passed to the signal
|
||||
handler, BeOS extension */
|
||||
} _PACKED;
|
||||
|
||||
|
||||
#endif // _KERNEL_COMPAT_SIGNAL_H
|
||||
@@ -18,6 +18,9 @@
|
||||
#include <debug.h>
|
||||
#include <kernel.h>
|
||||
#include <ksignal.h>
|
||||
#ifdef _COMPAT_MODE
|
||||
# include <compat/ksignal_compat.h>
|
||||
#endif
|
||||
#include <int.h>
|
||||
#include <team.h>
|
||||
#include <thread.h>
|
||||
@@ -88,11 +91,33 @@ x86_restart_syscall(iframe* frame)
|
||||
}
|
||||
|
||||
|
||||
#ifdef _COMPAT_MODE
|
||||
|
||||
|
||||
static inline void
|
||||
set_fs_register(uint32 segment)
|
||||
{
|
||||
asm("movl %0,%%fs" :: "r" (segment));
|
||||
}
|
||||
|
||||
|
||||
#endif // _COMPAT_MODE
|
||||
|
||||
|
||||
void
|
||||
x86_set_tls_context(Thread* thread)
|
||||
{
|
||||
// Set FS segment base address to the TLS segment.
|
||||
x86_write_msr(IA32_MSR_FS_BASE, thread->user_local_storage);
|
||||
#ifdef _COMPAT_MODE
|
||||
if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
|
||||
unsigned index = x86_64_set_user_tls_segment_base(
|
||||
smp_get_current_cpu(), thread->user_local_storage);
|
||||
set_fs_register((index << 3) | DPL_USER);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
// Set FS segment base address to the TLS segment.
|
||||
x86_write_msr(IA32_MSR_FS_BASE, thread->user_local_storage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -109,6 +134,24 @@ arch_randomize_stack_pointer(addr_t value)
|
||||
}
|
||||
|
||||
|
||||
#ifdef _COMPAT_MODE
|
||||
|
||||
|
||||
static addr_t
|
||||
arch_compat_randomize_stack_pointer(addr_t value)
|
||||
{
|
||||
STATIC_ASSERT(MAX_RANDOM_VALUE >= B_PAGE_SIZE - 1);
|
||||
value -= random_value() & (B_PAGE_SIZE - 1);
|
||||
return (value & ~addr_t(0xf)) - 4;
|
||||
// This means, result % 16 == 12, which is what esp should adhere to
|
||||
// when a function is entered for the stack to be considered aligned to
|
||||
// 16 byte.
|
||||
}
|
||||
|
||||
|
||||
#endif // _COMPAT_MODE
|
||||
|
||||
|
||||
static uint8*
|
||||
get_signal_stack(Thread* thread, iframe* frame, struct sigaction* action,
|
||||
size_t spaceNeeded)
|
||||
@@ -218,27 +261,55 @@ arch_thread_enter_userspace(Thread* thread, addr_t entry, void* args1,
|
||||
TRACE("arch_thread_enter_userspace: entry %#lx, args %p %p, "
|
||||
"stackTop %#lx\n", entry, args1, args2, stackTop);
|
||||
|
||||
stackTop = arch_randomize_stack_pointer(stackTop - sizeof(codeAddr));
|
||||
|
||||
// Copy the address of the stub that calls exit_thread() when the thread
|
||||
// entry function returns to the top of the stack to act as the return
|
||||
// address. The stub is inside commpage.
|
||||
addr_t commPageAddress = (addr_t)thread->team->commpage_address;
|
||||
set_ac();
|
||||
codeAddr = ((addr_t*)commPageAddress)[COMMPAGE_ENTRY_X86_THREAD_EXIT]
|
||||
+ commPageAddress;
|
||||
clear_ac();
|
||||
if (user_memcpy((void*)stackTop, (const void*)&codeAddr, sizeof(codeAddr))
|
||||
|
||||
#ifdef _COMPAT_MODE
|
||||
if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
|
||||
uint32 args[3];
|
||||
stackTop = arch_compat_randomize_stack_pointer(stackTop - sizeof(args));
|
||||
|
||||
set_ac();
|
||||
args[0] = ((addr_t*)commPageAddress)[COMMPAGE_ENTRY_X86_THREAD_EXIT]
|
||||
+ commPageAddress;
|
||||
clear_ac();
|
||||
args[1] = (uint32)(addr_t)args1;
|
||||
args[2] = (uint32)(addr_t)args2;
|
||||
if (user_memcpy((void *)stackTop, args, sizeof(args)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
stackTop = arch_randomize_stack_pointer(stackTop - sizeof(codeAddr));
|
||||
|
||||
set_ac();
|
||||
codeAddr = ((addr_t*)commPageAddress)[COMMPAGE_ENTRY_X86_THREAD_EXIT]
|
||||
+ commPageAddress;
|
||||
clear_ac();
|
||||
if (user_memcpy((void*)stackTop, (const void*)&codeAddr, sizeof(codeAddr))
|
||||
!= B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
// Prepare the user iframe.
|
||||
iframe frame = {};
|
||||
frame.type = IFRAME_TYPE_SYSCALL;
|
||||
frame.si = (uint64)args2;
|
||||
frame.di = (uint64)args1;
|
||||
frame.ip = entry;
|
||||
frame.cs = USER_CODE_SELECTOR;
|
||||
#ifdef _COMPAT_MODE
|
||||
if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
|
||||
frame.cs = USER32_CODE_SELECTOR;
|
||||
arch_thread_set_ds(USER_DATA_SELECTOR);
|
||||
arch_thread_set_es(USER_DATA_SELECTOR);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
frame.si = (uint64)args2;
|
||||
frame.di = (uint64)args1;
|
||||
frame.cs = USER_CODE_SELECTOR;
|
||||
}
|
||||
frame.flags = X86_EFLAGS_RESERVED1 | X86_EFLAGS_INTERRUPT
|
||||
| (3 << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT);
|
||||
frame.sp = stackTop;
|
||||
@@ -394,3 +465,120 @@ arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
|
||||
// restored.
|
||||
return frame->ax;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _COMPAT_MODE
|
||||
|
||||
status_t
|
||||
arch_setup_compat_signal_frame(Thread* thread, struct sigaction* action,
|
||||
struct compat_signal_frame_data* signalFrameData)
|
||||
{
|
||||
iframe* frame = x86_get_current_iframe();
|
||||
if (!IFRAME_IS_USER(frame)) {
|
||||
panic("arch_setup_compat_signal_frame(): No user iframe!");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// Store the register state.
|
||||
signalFrameData->context.uc_mcontext.eax = frame->ax;
|
||||
signalFrameData->context.uc_mcontext.ebx = frame->bx;
|
||||
signalFrameData->context.uc_mcontext.ecx = frame->cx;
|
||||
signalFrameData->context.uc_mcontext.edx = frame->dx;
|
||||
signalFrameData->context.uc_mcontext.edi = frame->di;
|
||||
signalFrameData->context.uc_mcontext.esi = frame->si;
|
||||
signalFrameData->context.uc_mcontext.ebp = frame->bp;
|
||||
signalFrameData->context.uc_mcontext.esp = frame->user_sp;
|
||||
signalFrameData->context.uc_mcontext.eip = frame->ip;
|
||||
signalFrameData->context.uc_mcontext.eflags = frame->flags;
|
||||
x86_fnsave((void *)(&signalFrameData->context.uc_mcontext.xregs));
|
||||
|
||||
// Fill in signalFrameData->context.uc_stack.
|
||||
stack_t stack;
|
||||
signal_get_user_stack(frame->user_sp, &stack);
|
||||
signalFrameData->context.uc_stack.ss_sp = (addr_t)stack.ss_sp;
|
||||
signalFrameData->context.uc_stack.ss_size = stack.ss_size;
|
||||
signalFrameData->context.uc_stack.ss_flags = stack.ss_flags;
|
||||
|
||||
// Store syscall_restart_return_value.
|
||||
signalFrameData->syscall_restart_return_value = frame->orig_rax;
|
||||
|
||||
// Get the stack to use and copy the frame data to it.
|
||||
uint32 stackFrame[2];
|
||||
uint8* userStack = get_signal_stack(thread, frame, action,
|
||||
sizeof(*signalFrameData) + sizeof(stackFrame));
|
||||
|
||||
compat_signal_frame_data* userSignalFrameData
|
||||
= (compat_signal_frame_data*)(userStack + sizeof(stackFrame));
|
||||
|
||||
if (user_memcpy(userSignalFrameData, signalFrameData,
|
||||
sizeof(*signalFrameData)) != B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
// prepare the user stack frame for a function call to the signal handler
|
||||
// wrapper function
|
||||
stackFrame[0] = frame->ip;
|
||||
stackFrame[1] = (addr_t)userSignalFrameData;
|
||||
// parameter: pointer to signal frame data
|
||||
|
||||
if (user_memcpy(userStack, stackFrame, sizeof(stackFrame)) != B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
// Update Thread::user_signal_context, now that everything seems to have
|
||||
// gone fine.
|
||||
thread->user_signal_context = (ucontext_t*)&userSignalFrameData->context;
|
||||
|
||||
// Set up the iframe to execute the signal handler wrapper on our prepared
|
||||
// stack. First argument points to the frame data.
|
||||
addr_t* commPageAddress = (addr_t*)thread->team->commpage_address;
|
||||
frame->user_sp = (addr_t)userStack;
|
||||
set_ac();
|
||||
|
||||
// from x86/arch_commpage_defs.h
|
||||
#define COMPAT_COMMPAGE_ENTRY_X86_SIGNAL_HANDLER \
|
||||
(COMMPAGE_ENTRY_FIRST_ARCH_SPECIFIC + 3)
|
||||
frame->ip = commPageAddress[COMPAT_COMMPAGE_ENTRY_X86_SIGNAL_HANDLER]
|
||||
+ (addr_t)commPageAddress;
|
||||
clear_ac();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
int64
|
||||
arch_restore_compat_signal_frame(struct compat_signal_frame_data* signalFrameData)
|
||||
{
|
||||
iframe* frame = x86_get_current_iframe();
|
||||
|
||||
frame->orig_rax = signalFrameData->syscall_restart_return_value;
|
||||
frame->ax = signalFrameData->context.uc_mcontext.eax;
|
||||
frame->bx = signalFrameData->context.uc_mcontext.ebx;
|
||||
frame->cx = signalFrameData->context.uc_mcontext.ecx;
|
||||
frame->dx = signalFrameData->context.uc_mcontext.edx;
|
||||
frame->di = signalFrameData->context.uc_mcontext.edi;
|
||||
frame->si = signalFrameData->context.uc_mcontext.esi;
|
||||
frame->bp = signalFrameData->context.uc_mcontext.ebp;
|
||||
frame->user_sp = signalFrameData->context.uc_mcontext.esp;
|
||||
frame->ip = signalFrameData->context.uc_mcontext.eip;
|
||||
frame->flags = (frame->flags & ~(uint64)X86_EFLAGS_USER_FLAGS)
|
||||
| (signalFrameData->context.uc_mcontext.eflags & X86_EFLAGS_USER_FLAGS);
|
||||
|
||||
x86_frstor((void*)(&signalFrameData->context.uc_mcontext.xregs));
|
||||
|
||||
// The syscall return code overwrites frame->ax with the return value of
|
||||
// the syscall, need to return it here to ensure the correct value is
|
||||
// restored.
|
||||
return frame->ax;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_syscall_64_bit_return_value(void)
|
||||
{
|
||||
Thread* thread = thread_get_current_thread();
|
||||
if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0)
|
||||
atomic_or(&thread->flags, THREAD_FLAGS_64_BIT_SYSCALL_RETURN);
|
||||
}
|
||||
|
||||
#endif // _COMPAT_MODE
|
||||
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
|
||||
|
||||
#include <ksignal.h>
|
||||
#ifdef _COMPAT_MODE
|
||||
# include <compat/ksignal.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
@@ -908,6 +911,61 @@ setup_signal_frame(Thread* thread, struct sigaction* action, Signal* signal,
|
||||
}
|
||||
|
||||
|
||||
#ifdef _COMPAT_MODE
|
||||
|
||||
static status_t
|
||||
setup_compat_signal_frame(Thread* thread, struct sigaction* action, Signal* signal,
|
||||
sigset_t signalMask)
|
||||
{
|
||||
// prepare the data, we need to copy onto the user stack
|
||||
struct compat_signal_frame_data frameData;
|
||||
|
||||
// signal info
|
||||
frameData.info.si_signo = signal->Number();
|
||||
frameData.info.si_code = signal->SignalCode();
|
||||
frameData.info.si_errno = signal->ErrorCode();
|
||||
frameData.info.si_pid = signal->SendingProcess();
|
||||
frameData.info.si_uid = signal->SendingUser();
|
||||
frameData.info.si_addr = (addr_t)signal->Address();
|
||||
frameData.info.si_status = signal->Status();
|
||||
frameData.info.si_band = signal->PollBand();
|
||||
frameData.info.si_value.sival_ptr = (addr_t)signal->UserValue().sival_ptr;
|
||||
|
||||
// context
|
||||
frameData.context.uc_link = (addr_t)thread->user_signal_context;
|
||||
frameData.context.uc_sigmask = signalMask;
|
||||
// uc_stack and uc_mcontext are filled in by the architecture specific code.
|
||||
|
||||
// user data
|
||||
frameData.user_data = (addr_t)action->sa_userdata;
|
||||
|
||||
// handler function
|
||||
frameData.siginfo_handler = (action->sa_flags & SA_SIGINFO) != 0;
|
||||
frameData.handler = frameData.siginfo_handler
|
||||
? (addr_t)action->sa_sigaction : (addr_t)action->sa_handler;
|
||||
|
||||
// thread flags -- save the and clear the thread's syscall restart related
|
||||
// flags
|
||||
frameData.thread_flags = atomic_and(&thread->flags,
|
||||
~(THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_64_BIT_SYSCALL_RETURN));
|
||||
|
||||
// syscall restart related fields
|
||||
memcpy(frameData.syscall_restart_parameters,
|
||||
thread->syscall_restart.parameters,
|
||||
sizeof(frameData.syscall_restart_parameters));
|
||||
|
||||
// commpage address
|
||||
frameData.commpage_address = (addr_t)thread->team->commpage_address;
|
||||
|
||||
// syscall_restart_return_value is filled in by the architecture specific
|
||||
// code.
|
||||
|
||||
return arch_setup_compat_signal_frame(thread, action, &frameData);
|
||||
}
|
||||
|
||||
#endif // _COMPAT_MODE
|
||||
|
||||
|
||||
/*! Actually handles pending signals -- i.e. the thread will exit, a custom
|
||||
signal handler is prepared, or whatever the signal demands.
|
||||
The function will not return, when a deadly signal is encountered. The
|
||||
@@ -1258,6 +1316,11 @@ handle_signals(Thread* thread)
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
#ifdef _COMPAT_MODE
|
||||
if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0)
|
||||
setup_compat_signal_frame(thread, &handler, signal, oldBlockMask);
|
||||
else
|
||||
#endif
|
||||
setup_signal_frame(thread, &handler, signal, oldBlockMask);
|
||||
|
||||
// Reset sigsuspend_original_unblocked_mask. It would have been set by
|
||||
|
||||
Reference in New Issue
Block a user