ntdll: Switch to the kernel stack for syscalls on ARM64.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-06-11 11:17:36 +02:00
parent 25b093f384
commit 08c4419a49
2 changed files with 268 additions and 162 deletions

View File

@ -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"

View File

@ -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;
}