mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-06 05:10:36 +00:00
ntdll: Switch to the kernel stack for syscalls on ARM64.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
25b093f384
commit
08c4419a49
|
@ -134,18 +134,24 @@ static pthread_key_t teb_key;
|
|||
|
||||
struct syscall_frame
|
||||
{
|
||||
ULONG64 x29;
|
||||
ULONG64 thunk_addr;
|
||||
ULONG64 x0, x1, x2, x3, x4, x5, x6, x7, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28;
|
||||
ULONG64 thunk_x29;
|
||||
ULONG64 ret_addr;
|
||||
ULONG64 x[29]; /* 000 */
|
||||
ULONG64 fp; /* 0e8 */
|
||||
ULONG64 lr; /* 0f0 */
|
||||
ULONG64 sp; /* 0f8 */
|
||||
ULONG64 pc; /* 100 */
|
||||
ULONG64 cpsr; /* 108 */
|
||||
ULONG64 restore_flags; /* 110 */
|
||||
ULONG fpcr; /* 118 */
|
||||
ULONG fpsr; /* 11c */
|
||||
NEON128 v[32]; /* 120 */
|
||||
};
|
||||
|
||||
C_ASSERT( sizeof( struct syscall_frame ) == 0x320 );
|
||||
|
||||
struct arm64_thread_data
|
||||
{
|
||||
void *exit_frame; /* 02f0 exit frame pointer */
|
||||
struct syscall_frame *syscall_frame; /* 02f8 frame pointer on syscall entry */
|
||||
CONTEXT *context; /* 0300 context to set with SIGUSR2 */
|
||||
};
|
||||
|
||||
C_ASSERT( sizeof(struct arm64_thread_data) <= sizeof(((struct ntdll_thread_data *)0)->cpu_data) );
|
||||
|
@ -157,6 +163,12 @@ static inline struct arm64_thread_data *arm64_thread_data(void)
|
|||
return (struct arm64_thread_data *)ntdll_get_thread_data()->cpu_data;
|
||||
}
|
||||
|
||||
static BOOL is_inside_syscall( ucontext_t *sigcontext )
|
||||
{
|
||||
return ((char *)SP_sig(sigcontext) >= (char *)ntdll_get_thread_data()->kernel_stack &&
|
||||
(char *)SP_sig(sigcontext) <= (char *)arm64_thread_data()->syscall_frame);
|
||||
}
|
||||
|
||||
extern void raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, void *dispatcher );
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -379,19 +391,19 @@ static void save_fpu( CONTEXT *context, ucontext_t *sigcontext )
|
|||
*
|
||||
* Restore the FPU context to a sigcontext.
|
||||
*/
|
||||
static void restore_fpu( CONTEXT *context, ucontext_t *sigcontext )
|
||||
static void restore_fpu( struct syscall_frame *frame, ucontext_t *sigcontext )
|
||||
{
|
||||
#ifdef linux
|
||||
struct fpsimd_context *fp = get_fpsimd_context( sigcontext );
|
||||
|
||||
if (!fp) return;
|
||||
fp->fpcr = context->Fpcr;
|
||||
fp->fpsr = context->Fpsr;
|
||||
memcpy( fp->vregs, context->V, sizeof(fp->vregs) );
|
||||
fp->fpcr = frame->fpcr;
|
||||
fp->fpsr = frame->fpsr;
|
||||
memcpy( fp->vregs, frame->v, sizeof(fp->vregs) );
|
||||
#elif defined(__APPLE__)
|
||||
sigcontext->uc_mcontext->__ns.__fpcr = context->Fpcr;
|
||||
sigcontext->uc_mcontext->__ns.__fpsr = context->Fpsr;
|
||||
memcpy( sigcontext->uc_mcontext->__ns.__v, context->V, sizeof(context->V) );
|
||||
sigcontext->uc_mcontext->__ns.__fpcr = frame->fpcr;
|
||||
sigcontext->uc_mcontext->__ns.__fpsr = frame->fpsr;
|
||||
memcpy( sigcontext->uc_mcontext->__ns.__v, frame->v, sizeof(frame->v) );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -403,6 +415,7 @@ static void restore_fpu( CONTEXT *context, ucontext_t *sigcontext )
|
|||
*/
|
||||
void signal_restore_full_cpu_context(void)
|
||||
{
|
||||
raise( SIGUSR2 );
|
||||
}
|
||||
|
||||
|
||||
|
@ -412,20 +425,46 @@ void signal_restore_full_cpu_context(void)
|
|||
*/
|
||||
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
|
||||
{
|
||||
struct syscall_frame *frame = arm64_thread_data()->syscall_frame;
|
||||
NTSTATUS ret = STATUS_SUCCESS;
|
||||
BOOL self = (handle == GetCurrentThread());
|
||||
DWORD flags = context->ContextFlags & ~CONTEXT_ARM64;
|
||||
|
||||
if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_ARM64))) self = FALSE;
|
||||
if (self && (flags & CONTEXT_DEBUG_REGISTERS)) self = FALSE;
|
||||
|
||||
if (!self) ret = set_thread_context( handle, context, &self, IMAGE_FILE_MACHINE_ARM64 );
|
||||
|
||||
if (self && ret == STATUS_SUCCESS)
|
||||
if (!self)
|
||||
{
|
||||
arm64_thread_data()->syscall_frame = NULL;
|
||||
InterlockedExchangePointer( (void **)&arm64_thread_data()->context, (void *)context );
|
||||
raise( SIGUSR2 );
|
||||
ret = set_thread_context( handle, context, &self, IMAGE_FILE_MACHINE_ARM64 );
|
||||
if (ret || !self) return ret;
|
||||
}
|
||||
return ret;
|
||||
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
memcpy( frame->x, context->u.X, sizeof(context->u.X[0]) * 18 );
|
||||
/* skip x18 */
|
||||
memcpy( frame->x + 19, context->u.X + 19, sizeof(context->u.X[0]) * 10 );
|
||||
}
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
frame->fp = context->u.s.Fp;
|
||||
frame->lr = context->u.s.Lr;
|
||||
frame->sp = context->Sp;
|
||||
frame->pc = context->Pc;
|
||||
frame->cpsr = context->Cpsr;
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
frame->fpcr = context->Fpcr;
|
||||
frame->fpsr = context->Fpsr;
|
||||
memcpy( frame->v, context->V, sizeof(frame->v) );
|
||||
}
|
||||
if (flags & CONTEXT_ARM64_X18)
|
||||
{
|
||||
frame->x[18] = context->u.X[18];
|
||||
}
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS) FIXME( "debug registers not supported\n" );
|
||||
frame->restore_flags |= flags & ~CONTEXT_INTEGER;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
@ -450,21 +489,25 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
|||
{
|
||||
if (needed_flags & CONTEXT_INTEGER)
|
||||
{
|
||||
memset( context->u.X, 0, sizeof(context->u.X[0]) * 18 );
|
||||
context->u.X[18] = (DWORD64)NtCurrentTeb();
|
||||
memcpy( context->u.X + 19, &frame->x19, sizeof(context->u.X[0]) * 10 );
|
||||
memcpy( context->u.X, frame->x, sizeof(context->u.X[0]) * 29 );
|
||||
context->ContextFlags |= CONTEXT_INTEGER;
|
||||
}
|
||||
if (needed_flags & CONTEXT_CONTROL)
|
||||
{
|
||||
context->u.s.Fp = frame->x29;
|
||||
context->u.s.Lr = frame->ret_addr;
|
||||
context->Sp = (ULONG64)(frame + 1);
|
||||
context->Pc = frame->thunk_addr;
|
||||
context->Cpsr = 0;
|
||||
context->u.s.Fp = frame->fp;
|
||||
context->u.s.Lr = frame->lr;
|
||||
context->Sp = frame->sp;
|
||||
context->Pc = frame->pc;
|
||||
context->Cpsr = frame->cpsr;
|
||||
context->ContextFlags |= CONTEXT_CONTROL;
|
||||
}
|
||||
if (needed_flags & CONTEXT_FLOATING_POINT) FIXME( "floating point not supported\n" );
|
||||
if (needed_flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
context->Fpcr = frame->fpcr;
|
||||
context->Fpsr = frame->fpsr;
|
||||
memcpy( context->V, frame->v, sizeof(context->V) );
|
||||
context->ContextFlags |= CONTEXT_FLOATING_POINT;
|
||||
}
|
||||
if (needed_flags & CONTEXT_DEBUG_REGISTERS) FIXME( "debug registers not supported\n" );
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
|
@ -600,71 +643,65 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
|
|||
/***********************************************************************
|
||||
* call_user_apc_dispatcher
|
||||
*/
|
||||
__ASM_GLOBAL_FUNC( call_user_apc_dispatcher,
|
||||
"mov x19, x0\n\t" /* context */
|
||||
"mov x20, x1\n\t" /* arg1 */
|
||||
"mov x21, x2\n\t" /* arg2 */
|
||||
"mov x22, x3\n\t" /* arg3 */
|
||||
"mov x23, x4\n\t" /* func */
|
||||
"mov x24, x5\n\t" /* dispatcher */
|
||||
"mov x25, x6\n\t" /* status */
|
||||
"bl " __ASM_NAME("NtCurrentTeb") "\n\t"
|
||||
"add x26, x0, #0x2f8\n\t" /* arm64_thread_data()->syscall_frame */
|
||||
"cbz x19, 1f\n\t"
|
||||
"ldr x0, [x19, #0x100]\n\t" /* context.Sp */
|
||||
"sub x0, x0, #0x430\n\t" /* sizeof(CONTEXT) + offsetof(frame,thunk_x29) */
|
||||
"str xzr, [x26]\n\t"
|
||||
"mov sp, x0\n\t"
|
||||
"b 2f\n"
|
||||
"1:\tldr x0, [x26]\n\t"
|
||||
"sub sp, x0, #0x390\n\t"
|
||||
"mov w2, #0x400000\n\t" /* context.ContextFlags = CONTEXT_FULL */
|
||||
"movk w2, #7\n\t"
|
||||
"str w2, [sp]\n\t"
|
||||
"mov x1, sp\n\t"
|
||||
"mov x0, #~1\n\t"
|
||||
"bl " __ASM_NAME("NtGetContextThread") "\n\t"
|
||||
"str x25, [sp, #8]\n\t" /* context.X0 = status */
|
||||
"str xzr, [x26]\n\t"
|
||||
"mov x0, sp\n" /* context */
|
||||
"2:\tldr lr, [x0, #0xf8]\n\t" /* context.Lr */
|
||||
"mov x1, x20\n\t" /* arg1 */
|
||||
"mov x2, x21\n\t" /* arg2 */
|
||||
"mov x3, x22\n\t" /* arg3 */
|
||||
"mov x4, x23\n\t" /* func */
|
||||
"br x24" )
|
||||
NTSTATUS WINAPI call_user_apc_dispatcher( CONTEXT *context, ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3,
|
||||
PNTAPCFUNC func,
|
||||
void (WINAPI *dispatcher)(CONTEXT*,ULONG_PTR,ULONG_PTR,ULONG_PTR,PNTAPCFUNC),
|
||||
NTSTATUS status )
|
||||
{
|
||||
struct syscall_frame *frame = arm64_thread_data()->syscall_frame;
|
||||
ULONG64 sp = context ? context->Sp : frame->sp;
|
||||
struct apc_stack_layout { CONTEXT context; } *stack;
|
||||
|
||||
sp &= ~15;
|
||||
stack = (struct apc_stack_layout *)sp - 1;
|
||||
if (context)
|
||||
{
|
||||
memmove( &stack->context, context, sizeof(stack->context) );
|
||||
NtSetContextThread( GetCurrentThread(), &stack->context );
|
||||
}
|
||||
else
|
||||
{
|
||||
stack->context.ContextFlags = CONTEXT_FULL;
|
||||
NtGetContextThread( GetCurrentThread(), &stack->context );
|
||||
stack->context.u.s.X0 = status;
|
||||
}
|
||||
frame->sp = (ULONG64)stack;
|
||||
frame->pc = (ULONG64)dispatcher;
|
||||
frame->x[0] = (ULONG64)&stack->context;
|
||||
frame->x[1] = arg1;
|
||||
frame->x[2] = arg2;
|
||||
frame->x[3] = arg3;
|
||||
frame->x[4] = (ULONG64)func;
|
||||
frame->restore_flags |= CONTEXT_CONTROL | CONTEXT_INTEGER;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* call_raise_user_exception_dispatcher
|
||||
*/
|
||||
__ASM_GLOBAL_FUNC( call_raise_user_exception_dispatcher,
|
||||
"mov x2, x0\n\t" /* dispatcher */
|
||||
"b " __ASM_NAME("call_user_exception_dispatcher") )
|
||||
void WINAPI call_raise_user_exception_dispatcher( NTSTATUS (WINAPI *dispatcher)(void) )
|
||||
{
|
||||
arm64_thread_data()->syscall_frame->pc = (UINT64)dispatcher;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* call_user_exception_dispatcher
|
||||
*/
|
||||
__ASM_GLOBAL_FUNC( call_user_exception_dispatcher,
|
||||
"mov x19, x0\n\t"
|
||||
"mov x20, x1\n\t"
|
||||
"mov x21, x2\n\t"
|
||||
"bl " __ASM_NAME("NtCurrentTeb") "\n\t"
|
||||
"add x4, x0, #0x2f8\n\t" /* arm64_thread_data()->syscall_frame */
|
||||
"ldr x5, [x4]\n\t"
|
||||
"str xzr, [x4]\n\t"
|
||||
"mov x0, x19\n\t"
|
||||
"mov x1, x20\n\t"
|
||||
"mov x2, x21\n\t"
|
||||
"ldp x19, x20, [x5, #80]\n\t" /* frame->x19,x20 */
|
||||
"ldp x21, x22, [x5, #96]\n\t" /* frame->x21,x22 */
|
||||
"ldp x23, x24, [x5, #112]\n\t" /* frame->x23,x24 */
|
||||
"ldp x25, x26, [x5, #128]\n\t" /* frame->x25,x26 */
|
||||
"ldp x27, x28, [x5, #144]\n\t" /* frame->x27,x28 */
|
||||
"ldp x29, x30, [x5, #160]\n\t" /* frame->thunk_x29,ret_addr */
|
||||
"add sp, x5, #176\n\t"
|
||||
"br x2" )
|
||||
NTSTATUS WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context,
|
||||
NTSTATUS (WINAPI *dispatcher)(EXCEPTION_RECORD*,CONTEXT*) )
|
||||
{
|
||||
struct syscall_frame *frame = arm64_thread_data()->syscall_frame;
|
||||
NTSTATUS status = NtSetContextThread( GetCurrentThread(), context );
|
||||
|
||||
if (status) return status;
|
||||
frame->x[0] = (ULONG64)rec;
|
||||
frame->x[1] = (ULONG64)context;
|
||||
frame->pc = (ULONG64)dispatcher;
|
||||
frame->restore_flags |= CONTEXT_INTEGER | CONTEXT_CONTROL;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -677,7 +714,7 @@ static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec )
|
|||
struct syscall_frame *frame = arm64_thread_data()->syscall_frame;
|
||||
DWORD i;
|
||||
|
||||
if (!frame) return FALSE;
|
||||
if (!is_inside_syscall( context )) return FALSE;
|
||||
|
||||
TRACE( "code=%x flags=%x addr=%p pc=%p tid=%04x\n",
|
||||
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
|
||||
|
@ -720,23 +757,13 @@ static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec )
|
|||
}
|
||||
else
|
||||
{
|
||||
TRACE( "returning to user mode ip=%p ret=%08x\n", (void *)frame->ret_addr, rec->ExceptionCode );
|
||||
TRACE( "returning to user mode ip=%p ret=%08x\n", (void *)frame->pc, rec->ExceptionCode );
|
||||
for (i = 18; i < 29; i++) REGn_sig( i, context ) = frame->x[i];
|
||||
REGn_sig(0, context) = rec->ExceptionCode;
|
||||
REGn_sig(19, context) = frame->x19;
|
||||
REGn_sig(20, context) = frame->x20;
|
||||
REGn_sig(21, context) = frame->x21;
|
||||
REGn_sig(22, context) = frame->x22;
|
||||
REGn_sig(23, context) = frame->x23;
|
||||
REGn_sig(24, context) = frame->x24;
|
||||
REGn_sig(25, context) = frame->x25;
|
||||
REGn_sig(26, context) = frame->x26;
|
||||
REGn_sig(27, context) = frame->x27;
|
||||
REGn_sig(28, context) = frame->x28;
|
||||
FP_sig(context) = frame->x29;
|
||||
LR_sig(context) = frame->ret_addr;
|
||||
SP_sig(context) = (ULONG64)&frame->thunk_x29;
|
||||
PC_sig(context) = frame->thunk_addr;
|
||||
arm64_thread_data()->syscall_frame = NULL;
|
||||
FP_sig(context) = frame->fp;
|
||||
LR_sig(context) = frame->lr;
|
||||
SP_sig(context) = frame->sp;
|
||||
PC_sig(context) = frame->pc;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -919,9 +946,19 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
|
|||
{
|
||||
CONTEXT context;
|
||||
|
||||
save_context( &context, sigcontext );
|
||||
wait_suspend( &context );
|
||||
restore_context( &context, sigcontext );
|
||||
if (is_inside_syscall( sigcontext ))
|
||||
{
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
NtGetContextThread( GetCurrentThread(), &context );
|
||||
wait_suspend( &context );
|
||||
NtSetContextThread( GetCurrentThread(), &context );
|
||||
}
|
||||
else
|
||||
{
|
||||
save_context( &context, sigcontext );
|
||||
wait_suspend( &context );
|
||||
restore_context( &context, sigcontext );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -932,11 +969,19 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
|
|||
*/
|
||||
static void usr2_handler( int signal, siginfo_t *siginfo, void *sigcontext )
|
||||
{
|
||||
CONTEXT *context = InterlockedExchangePointer( (void **)&arm64_thread_data()->context, NULL );
|
||||
if (!context) return;
|
||||
if ((context->ContextFlags & ~CONTEXT_ARM64) & CONTEXT_FLOATING_POINT)
|
||||
restore_fpu( context, sigcontext );
|
||||
restore_context( context, sigcontext );
|
||||
struct syscall_frame *frame = arm64_thread_data()->syscall_frame;
|
||||
ucontext_t *context = sigcontext;
|
||||
DWORD i;
|
||||
|
||||
if (!is_inside_syscall( sigcontext )) return;
|
||||
|
||||
FP_sig(context) = frame->fp;
|
||||
LR_sig(context) = frame->lr;
|
||||
SP_sig(context) = frame->sp;
|
||||
PC_sig(context) = frame->pc;
|
||||
PSTATE_sig(context) = frame->cpsr;
|
||||
for (i = 0; i <= 28; i++) REGn_sig( i, context ) = frame->x[i];
|
||||
restore_fpu( frame, context );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1003,6 +1048,9 @@ void signal_init_thread( TEB *teb )
|
|||
void signal_init_process(void)
|
||||
{
|
||||
struct sigaction sig_act;
|
||||
void *kernel_stack = (char *)ntdll_get_thread_data()->kernel_stack + kernel_stack_size;
|
||||
|
||||
arm64_thread_data()->syscall_frame = (struct syscall_frame *)kernel_stack - 1;
|
||||
|
||||
sig_act.sa_mask = server_block_set;
|
||||
sig_act.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK;
|
||||
|
@ -1086,8 +1134,13 @@ __ASM_GLOBAL_FUNC( signal_start_thread,
|
|||
/* store exit frame */
|
||||
"mov x29, sp\n\t"
|
||||
"str x29, [x4, #0x2f0]\n\t" /* arm64_thread_data()->exit_frame */
|
||||
/* set syscall frame */
|
||||
"ldr x8, [x4, #0x2f8]\n\t" /* arm64_thread_data()->syscall_frame */
|
||||
"cbnz x8, 1f\n\t"
|
||||
"sub x8, sp, #0x320\n\t" /* sizeof(struct syscall_frame) */
|
||||
"str x8, [x4, #0x2f8]\n\t" /* arm64_thread_data()->syscall_frame */
|
||||
/* switch to thread stack */
|
||||
"ldr x5, [x4, #8]\n\t" /* teb->Tib.StackBase */
|
||||
"1:\tldr x5, [x4, #8]\n\t" /* teb->Tib.StackBase */
|
||||
"sub sp, x5, #0x1000\n\t"
|
||||
/* attach dlls */
|
||||
"mov x3, x4\n\t"
|
||||
|
|
|
@ -1712,27 +1712,55 @@ static void output_syscall_dispatcher(void)
|
|||
output( "6:\t.long %s\n", asm_name("KeServiceDescriptorTable") );
|
||||
break;
|
||||
case CPU_ARM64:
|
||||
output( "\tstp x29, x30, [sp,#-160]!\n" );
|
||||
output_cfi( "\t.cfi_def_cfa_offset 160\n" );
|
||||
output_cfi( "\t.cfi_offset 29, -160\n" );
|
||||
output_cfi( "\t.cfi_offset 30, -152\n" );
|
||||
output( "\tmov x29, sp\n" );
|
||||
output_cfi( "\t.cfi_def_cfa_register 29\n" );
|
||||
output( "\tstp x27, x28, [sp, #144]\n" );
|
||||
output_cfi( "\t.cfi_offset 27, -16\n" );
|
||||
output_cfi( "\t.cfi_offset 28, -8\n" );
|
||||
output( "\tstp x25, x26, [sp, #128]\n" );
|
||||
output_cfi( "\t.cfi_offset 25, -32\n" );
|
||||
output_cfi( "\t.cfi_offset 26, -24\n" );
|
||||
output( "\tstp x23, x24, [sp, #112]\n" );
|
||||
output_cfi( "\t.cfi_offset 23, -48\n" );
|
||||
output_cfi( "\t.cfi_offset 24, -40\n" );
|
||||
output( "\tstp x21, x22, [sp, #96]\n" );
|
||||
output_cfi( "\t.cfi_offset 21, -64\n" );
|
||||
output_cfi( "\t.cfi_offset 22, -56\n" );
|
||||
output( "\tstp x19, x20, [sp, #80]\n" );
|
||||
output_cfi( "\t.cfi_offset 19, -80\n" );
|
||||
output_cfi( "\t.cfi_offset 20, -72\n" );
|
||||
/* FIXME: use x18 directly instead */
|
||||
output( "\tstp x0, x1, [sp, #-96]!\n" );
|
||||
output( "\tstp x2, x3, [sp, #16]\n" );
|
||||
output( "\tstp x4, x5, [sp, #32]\n" );
|
||||
output( "\tstp x6, x7, [sp, #48]\n" );
|
||||
output( "\tstp x8, x9, [sp, #64]\n" );
|
||||
output( "\tstr lr, [sp, #80]\n" );
|
||||
output( "\tbl %s\n", asm_name("NtCurrentTeb") );
|
||||
output( "\tmov x18, x0\n" );
|
||||
output( "\tldp x2, x3, [sp, #16]\n" );
|
||||
output( "\tldp x4, x5, [sp, #32]\n" );
|
||||
output( "\tldp x6, x7, [sp, #48]\n" );
|
||||
output( "\tldp x8, x9, [sp, #64]\n" );
|
||||
output( "\tldr lr, [sp, #80]\n" );
|
||||
output( "\tldp x0, x1, [sp], #96\n" );
|
||||
|
||||
output( "\tldr x10, [x18, #0x2f8]\n" ); /* arm64_thread_data()->syscall_frame */
|
||||
output( "\tstp x18, x19, [x10, #0x90]\n" );
|
||||
output( "\tstp x20, x21, [x10, #0xa0]\n" );
|
||||
output( "\tstp x22, x23, [x10, #0xb0]\n" );
|
||||
output( "\tstp x24, x25, [x10, #0xc0]\n" );
|
||||
output( "\tstp x26, x27, [x10, #0xd0]\n" );
|
||||
output( "\tstp x28, x29, [x10, #0xe0]\n" );
|
||||
output( "\tmov x19, sp\n" );
|
||||
output( "\tstp x9, x19, [x10, #0xf0]\n" );
|
||||
output( "\tmrs x9, NZCV\n" );
|
||||
output( "\tstp lr, x9, [x10, #0x100]\n" );
|
||||
output( "\tstr xzr, [x10, #0x110]\n" ); /* frame->restore_flags */
|
||||
output( "\tmrs x9, FPCR\n" );
|
||||
output( "\tstr w9, [x10, #0x118]\n" );
|
||||
output( "\tmrs x9, FPSR\n" );
|
||||
output( "\tstr w9, [x10, #0x11c]\n" );
|
||||
output( "\tstp q0, q1, [x10, #0x120]\n" );
|
||||
output( "\tstp q2, q3, [x10, #0x140]\n" );
|
||||
output( "\tstp q4, q5, [x10, #0x160]\n" );
|
||||
output( "\tstp q6, q7, [x10, #0x180]\n" );
|
||||
output( "\tstp q8, q9, [x10, #0x1a0]\n" );
|
||||
output( "\tstp q10, q11, [x10, #0x1c0]\n" );
|
||||
output( "\tstp q12, q13, [x10, #0x1e0]\n" );
|
||||
output( "\tstp q14, q15, [x10, #0x200]\n" );
|
||||
output( "\tstp q16, q17, [x10, #0x220]\n" );
|
||||
output( "\tstp q18, q19, [x10, #0x240]\n" );
|
||||
output( "\tstp q20, q21, [x10, #0x260]\n" );
|
||||
output( "\tstp q22, q23, [x10, #0x280]\n" );
|
||||
output( "\tstp q24, q25, [x10, #0x2a0]\n" );
|
||||
output( "\tstp q26, q27, [x10, #0x2c0]\n" );
|
||||
output( "\tstp q28, q29, [x10, #0x2e0]\n" );
|
||||
output( "\tstp q30, q31, [x10, #0x300]\n" );
|
||||
output( "\tmov sp, x10\n" );
|
||||
output( "\tand x20, x8, #0xfff\n" ); /* syscall number */
|
||||
output( "\tubfx x21, x8, #12, #2\n" ); /* syscall table number */
|
||||
output( "\tadrp x16, %s\n", arm64_page(asm_name("KeServiceDescriptorTable")) );
|
||||
|
@ -1741,41 +1769,64 @@ static void output_syscall_dispatcher(void)
|
|||
output( "\tldr x16, [x21, #16]\n" ); /* table->ServiceLimit */
|
||||
output( "\tcmp x20, x16\n" );
|
||||
output( "\tbcs 4f\n" );
|
||||
output( "\tstp x6, x7, [sp, #64]\n" );
|
||||
output( "\tstp x4, x5, [sp, #48]\n" );
|
||||
output( "\tstp x2, x3, [sp, #32]\n" );
|
||||
output( "\tstp x0, x1, [sp, #16]\n" );
|
||||
output( "\tbl %s\n", asm_name("NtCurrentTeb") );
|
||||
output( "\tadd x19, x0, #0x2f8\n" ); /* arm64_thread_data()->syscall_frame */
|
||||
output( "\tstr x29, [x19]\n" );
|
||||
output( "\tldp x0, x1, [sp, #16]\n" );
|
||||
output( "\tldp x2, x3, [sp, #32]\n" );
|
||||
output( "\tldp x4, x5, [sp, #48]\n" );
|
||||
output( "\tldp x6, x7, [sp, #64]\n" );
|
||||
output( "\tmov x22, sp\n" );
|
||||
output( "\tldr x16, [x21, #24]\n" ); /* table->ArgumentTable */
|
||||
output( "\tldrb w9, [x16, x20]\n" );
|
||||
output( "\tsubs x9, x9, #64\n" );
|
||||
output( "\tbls 2f\n" );
|
||||
output( "\tadd x11, x29, #176\n" );
|
||||
output( "\tsub sp, sp, x9\n" );
|
||||
output( "\ttbz x9, #3, 1f\n" );
|
||||
output( "\tsub sp, sp, #8\n" );
|
||||
output( "1:\tsub x9, x9, #8\n" );
|
||||
output( "\tldr x10, [x11, x9]\n" );
|
||||
output( "\tldr x10, [x19, x9]\n" );
|
||||
output( "\tstr x10, [sp, x9]\n" );
|
||||
output( "\tcbnz x9, 1b\n" );
|
||||
output( "2:\tldr x16, [x21]\n" ); /* table->ServiceTable */
|
||||
output( "\tldr x16, [x16, x20, lsl 3]\n" );
|
||||
output( "\tblr x16\n" );
|
||||
output( "\tmov sp, x29\n" );
|
||||
output( "\tstr xzr, [x19]\n" );
|
||||
output( "3:\tldp x19, x20, [sp, #80]\n" );
|
||||
output( "\tldp x21, x22, [sp, #96]\n" );
|
||||
output( "\tldp x23, x24, [sp, #112]\n" );
|
||||
output( "\tldp x25, x26, [sp, #128]\n" );
|
||||
output( "\tldp x27, x28, [sp, #144]\n" );
|
||||
output( "\tldp x29, x30, [sp], #160\n" );
|
||||
output( "\tret\n" );
|
||||
output( "\tmov sp, x22\n" );
|
||||
output( "3:\tldp x18, x19, [sp, #0x90]\n" );
|
||||
output( "\tldp x20, x21, [sp, #0xa0]\n" );
|
||||
output( "\tldp x22, x23, [sp, #0xb0]\n" );
|
||||
output( "\tldp x24, x25, [sp, #0xc0]\n" );
|
||||
output( "\tldp x26, x27, [sp, #0xd0]\n" );
|
||||
output( "\tldp x28, x29, [sp, #0xe0]\n" );
|
||||
output( "\tldr x16, [sp, #0x110]\n" ); /* frame->restore_flags */
|
||||
output( "\ttbz x16, #2, 1f\n" ); /* CONTEXT_FLOATING_POINT */
|
||||
output( "\tldp q0, q1, [sp, #0x120]\n" );
|
||||
output( "\tldp q2, q3, [sp, #0x140]\n" );
|
||||
output( "\tldp q4, q5, [sp, #0x160]\n" );
|
||||
output( "\tldp q6, q7, [sp, #0x180]\n" );
|
||||
output( "\tldp q8, q9, [sp, #0x1a0]\n" );
|
||||
output( "\tldp q10, q11, [sp, #0x1c0]\n" );
|
||||
output( "\tldp q12, q13, [sp, #0x1e0]\n" );
|
||||
output( "\tldp q14, q15, [sp, #0x200]\n" );
|
||||
output( "\tldp q16, q17, [sp, #0x220]\n" );
|
||||
output( "\tldp q18, q19, [sp, #0x240]\n" );
|
||||
output( "\tldp q20, q21, [sp, #0x260]\n" );
|
||||
output( "\tldp q22, q23, [sp, #0x280]\n" );
|
||||
output( "\tldp q24, q25, [sp, #0x2a0]\n" );
|
||||
output( "\tldp q26, q27, [sp, #0x2c0]\n" );
|
||||
output( "\tldp q28, q29, [sp, #0x2e0]\n" );
|
||||
output( "\tldp q30, q31, [sp, #0x300]\n" );
|
||||
output( "\tldr w9, [x10, #0x118]\n" );
|
||||
output( "\tmsr FPCR, x9\n" );
|
||||
output( "\tldr w9, [x10, #0x11c]\n" );
|
||||
output( "\tmsr FPSR, x9\n" );
|
||||
output( "1:\ttbz x16, #1, 1f\n" ); /* CONTEXT_INTEGER */
|
||||
output( "\tldp x0, x1, [sp, #0x00]\n" );
|
||||
output( "\tldp x2, x3, [sp, #0x10]\n" );
|
||||
output( "\tldp x4, x5, [sp, #0x20]\n" );
|
||||
output( "\tldp x6, x7, [sp, #0x30]\n" );
|
||||
output( "\tldp x8, x9, [sp, #0x40]\n" );
|
||||
output( "\tldp x10, x11, [sp, #0x50]\n" );
|
||||
output( "\tldp x12, x13, [sp, #0x60]\n" );
|
||||
output( "\tldp x14, x15, [sp, #0x70]\n" );
|
||||
output( "1:\tldp x16, x17, [sp, #0x100]\n" );
|
||||
output( "\tmsr NZCV, x17\n" );
|
||||
output( "\tldp x30, x17, [sp, #0xf0]\n" );
|
||||
output( "\tmov sp, x17\n" );
|
||||
output( "\tret x16\n" );
|
||||
output( "4:\tmov x0, #0x%x\n", invalid_param & 0xffff0000 );
|
||||
output( "\tmovk x0, #0x%x\n", invalid_param & 0x0000ffff );
|
||||
output( "\tb 3b\n" );
|
||||
|
@ -1892,15 +1943,9 @@ void output_syscalls( DLLSPEC *spec )
|
|||
output( "\tbx ip\n" );
|
||||
break;
|
||||
case CPU_ARM64:
|
||||
output( "\tstp x29, x30, [sp,#-16]!\n" );
|
||||
output_cfi( "\t.cfi_def_cfa_offset 16\n" );
|
||||
output_cfi( "\t.cfi_offset 29, -16\n" );
|
||||
output_cfi( "\t.cfi_offset 30, -8\n" );
|
||||
output( "\tmov x8, #%u\n", i );
|
||||
output( "\tadrp x16, %s\n", arm64_page( asm_name("__wine_syscall_dispatcher") ) );
|
||||
output( "\tldr x16, [x16, #%s]\n", arm64_pageoff( asm_name("__wine_syscall_dispatcher") ) );
|
||||
output( "\tblr x16\n");
|
||||
output( "\tldp x29, x30, [sp], #16\n" );
|
||||
output( "\tmov x9, x30\n" );
|
||||
output( "\tbl %s\n", asm_name("__wine_syscall" ));
|
||||
output( "\tret\n" );
|
||||
break;
|
||||
default:
|
||||
|
@ -1940,6 +1985,14 @@ void output_syscalls( DLLSPEC *spec )
|
|||
if (UsePIC) output( "2:\t.long %s-1b-%u\n", asm_name("__wine_syscall_dispatcher"), thumb_mode ? 4 : 8 );
|
||||
output_function_size( "__wine_syscall" );
|
||||
break;
|
||||
case CPU_ARM64:
|
||||
output( "\t.align %d\n", get_alignment(16) );
|
||||
output( "\t%s\n", func_declaration("__wine_syscall") );
|
||||
output( "%s:\n", asm_name("__wine_syscall") );
|
||||
output( "\tadrp x16, %s\n", arm64_page( asm_name("__wine_syscall_dispatcher") ) );
|
||||
output( "\tldr x16, [x16, #%s]\n", arm64_pageoff( asm_name("__wine_syscall_dispatcher") ) );
|
||||
output( "\tbr x16\n");
|
||||
output_function_size( "__wine_syscall" );
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue