kernel32: Reimplement fiber switching in assembly.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
3b1bf387eb
commit
adac42bad6
dlls/kernel32
|
@ -21,14 +21,8 @@
|
|||
* - proper handling of 16-bit stack and signal stack
|
||||
*/
|
||||
|
||||
/* Fortify source chokes on siglongjmp stack switching, so disable it */
|
||||
#undef _FORTIFY_SOURCE
|
||||
#define _FORTIFY_SOURCE 0
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define NONAMELESSUNION
|
||||
|
@ -37,31 +31,144 @@
|
|||
#include "winerror.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/exception.h"
|
||||
#include "wine/library.h"
|
||||
#include "wine/asm.h"
|
||||
|
||||
struct fiber_data
|
||||
{
|
||||
LPVOID param; /* 00 fiber param */
|
||||
void *except; /* 04 saved exception handlers list */
|
||||
void *stack_base; /* 08 top of fiber stack */
|
||||
void *stack_limit; /* 0c fiber stack low-water mark */
|
||||
void *stack_allocation; /* 10 base of the fiber stack allocation */
|
||||
sigjmp_buf jmpbuf; /* 14 setjmp buffer (on Windows: CONTEXT) */
|
||||
DWORD flags; /* fiber flags */
|
||||
LPFIBER_START_ROUTINE start; /* start routine */
|
||||
void **fls_slots; /* fiber storage slots */
|
||||
LPVOID param; /* 00/00 fiber param */
|
||||
void *except; /* 04/08 saved exception handlers list */
|
||||
void *stack_base; /* 08/10 top of fiber stack */
|
||||
void *stack_limit; /* 0c/18 fiber stack low-water mark */
|
||||
void *stack_allocation; /* 10/20 base of the fiber stack allocation */
|
||||
CONTEXT context; /* 14/30 fiber context */
|
||||
DWORD flags; /* fiber flags */
|
||||
LPFIBER_START_ROUTINE start; /* start routine */
|
||||
void **fls_slots; /* fiber storage slots */
|
||||
};
|
||||
|
||||
|
||||
/* call the fiber initial function once we have switched stack */
|
||||
static void start_fiber( void *arg )
|
||||
extern void WINAPI switch_fiber( CONTEXT *old, CONTEXT *new );
|
||||
#ifdef __i386__
|
||||
__ASM_STDCALL_FUNC( switch_fiber, 8,
|
||||
"movl 4(%esp),%ecx\n\t" /* old */
|
||||
"movl %edi,0x9c(%ecx)\n\t" /* old->Edi */
|
||||
"movl %esi,0xa0(%ecx)\n\t" /* old->Esi */
|
||||
"movl %ebx,0xa4(%ecx)\n\t" /* old->Ebx */
|
||||
"movl %ebp,0xb4(%ecx)\n\t" /* old->Ebp */
|
||||
"movl 0(%esp),%eax\n\t"
|
||||
"movl %eax,0xb8(%ecx)\n\t" /* old->Eip */
|
||||
"leal 12(%esp),%eax\n\t"
|
||||
"movl %eax,0xc4(%ecx)\n\t" /* old->Esp */
|
||||
"movl 8(%esp),%ecx\n\t" /* new */
|
||||
"movl 0x9c(%ecx),%edi\n\t" /* new->Edi */
|
||||
"movl 0xa0(%ecx),%esi\n\t" /* new->Esi */
|
||||
"movl 0xa4(%ecx),%ebx\n\t" /* new->Ebx */
|
||||
"movl 0xb4(%ecx),%ebp\n\t" /* new->Ebp */
|
||||
"movl 0xc4(%ecx),%esp\n\t" /* new->Esp */
|
||||
"jmp *0xb8(%ecx)" ) /* new->Eip */
|
||||
#elif defined(__x86_64__)
|
||||
__ASM_STDCALL_FUNC( switch_fiber, 8,
|
||||
"movq %rbx,0x90(%rcx)\n\t" /* old->Rbx */
|
||||
"leaq 0x8(%rsp),%rax\n\t"
|
||||
"movq %rax,0x98(%rcx)\n\t" /* old->Rsp */
|
||||
"movq %rbp,0xa0(%rcx)\n\t" /* old->Rbp */
|
||||
"movq %rsi,0xa8(%rcx)\n\t" /* old->Rsi */
|
||||
"movq %rdi,0xb0(%rcx)\n\t" /* old->Rdi */
|
||||
"movq %r12,0xd8(%rcx)\n\t" /* old->R12 */
|
||||
"movq %r13,0xe0(%rcx)\n\t" /* old->R13 */
|
||||
"movq %r14,0xe8(%rcx)\n\t" /* old->R14 */
|
||||
"movq %r15,0xf0(%rcx)\n\t" /* old->R15 */
|
||||
"movq (%rsp),%rax\n\t"
|
||||
"movq %rax,0xf8(%rcx)\n\t" /* old->Rip */
|
||||
"movdqa %xmm6,0x200(%rcx)\n\t" /* old->Xmm6 */
|
||||
"movdqa %xmm7,0x210(%rcx)\n\t" /* old->Xmm7 */
|
||||
"movdqa %xmm8,0x220(%rcx)\n\t" /* old->Xmm8 */
|
||||
"movdqa %xmm9,0x230(%rcx)\n\t" /* old->Xmm9 */
|
||||
"movdqa %xmm10,0x240(%rcx)\n\t" /* old->Xmm10 */
|
||||
"movdqa %xmm11,0x250(%rcx)\n\t" /* old->Xmm11 */
|
||||
"movdqa %xmm12,0x260(%rcx)\n\t" /* old->Xmm12 */
|
||||
"movdqa %xmm13,0x270(%rcx)\n\t" /* old->Xmm13 */
|
||||
"movdqa %xmm14,0x280(%rcx)\n\t" /* old->Xmm14 */
|
||||
"movdqa %xmm15,0x290(%rcx)\n\t" /* old->Xmm15 */
|
||||
"movq 0x90(%rdx),%rbx\n\t" /* new->Rbx */
|
||||
"movq 0xa0(%rdx),%rbp\n\t" /* new->Rbp */
|
||||
"movq 0xa8(%rdx),%rsi\n\t" /* new->Rsi */
|
||||
"movq 0xb0(%rdx),%rdi\n\t" /* new->Rdi */
|
||||
"movq 0xd8(%rdx),%r12\n\t" /* new->R12 */
|
||||
"movq 0xe0(%rdx),%r13\n\t" /* new->R13 */
|
||||
"movq 0xe8(%rdx),%r14\n\t" /* new->R14 */
|
||||
"movq 0xf0(%rdx),%r15\n\t" /* new->R15 */
|
||||
"movdqa 0x200(%rdx),%xmm6\n\t" /* new->Xmm6 */
|
||||
"movdqa 0x210(%rdx),%xmm7\n\t" /* new->Xmm7 */
|
||||
"movdqa 0x220(%rdx),%xmm8\n\t" /* new->Xmm8 */
|
||||
"movdqa 0x230(%rdx),%xmm9\n\t" /* new->Xmm9 */
|
||||
"movdqa 0x240(%rdx),%xmm10\n\t" /* new->Xmm10 */
|
||||
"movdqa 0x250(%rdx),%xmm11\n\t" /* new->Xmm11 */
|
||||
"movdqa 0x260(%rdx),%xmm12\n\t" /* new->Xmm12 */
|
||||
"movdqa 0x270(%rdx),%xmm13\n\t" /* new->Xmm13 */
|
||||
"movdqa 0x280(%rdx),%xmm14\n\t" /* new->Xmm14 */
|
||||
"movdqa 0x290(%rdx),%xmm15\n\t" /* new->Xmm15 */
|
||||
"movq 0x98(%rdx),%rsp\n\t" /* new->Rsp */
|
||||
"jmp *0xf8(%rdx)" ) /* new->Rip */
|
||||
#elif defined(__arm__)
|
||||
__ASM_STDCALL_FUNC( switch_fiber, 8,
|
||||
"str r4, [r0, #0x14]\n\t" /* old->R4 */
|
||||
"str r5, [r0, #0x18]\n\t" /* old->R5 */
|
||||
"str r6, [r0, #0x1c]\n\t" /* old->R6 */
|
||||
"str r7, [r0, #0x20]\n\t" /* old->R7 */
|
||||
"str r8, [r0, #0x24]\n\t" /* old->R8 */
|
||||
"str r9, [r0, #0x28]\n\t" /* old->R9 */
|
||||
"str r10, [r0, #0x2c]\n\t" /* old->R10 */
|
||||
"str r11, [r0, #0x30]\n\t" /* old->R11 */
|
||||
"str sp, [r0, #0x38]\n\t" /* old->Sp */
|
||||
"str lr, [r0, #0x40]\n\t" /* old->Pc */
|
||||
"ldr r4, [r1, #0x14]\n\t" /* new->R4 */
|
||||
"ldr r5, [r1, #0x18]\n\t" /* new->R5 */
|
||||
"ldr r6, [r1, #0x1c]\n\t" /* new->R6 */
|
||||
"ldr r7, [r1, #0x20]\n\t" /* new->R7 */
|
||||
"ldr r8, [r1, #0x24]\n\t" /* new->R8 */
|
||||
"ldr r9, [r1, #0x28]\n\t" /* new->R9 */
|
||||
"ldr r10, [r1, #0x2c]\n\t" /* new->R10 */
|
||||
"ldr r11, [r1, #0x30]\n\t" /* new->R11 */
|
||||
"ldr sp, [r1, #0x38]\n\t" /* new->Sp */
|
||||
"ldr r2, [r1, #0x40]\n\t" /* new->Pc */
|
||||
"bx r2" )
|
||||
#elif defined(__aarch64__)
|
||||
__ASM_STDCALL_FUNC( switch_fiber, 8,
|
||||
"stp x19, x20, [x0, #0xa0]\n\t" /* old->X19,X20 */
|
||||
"stp x21, x22, [x0, #0xb0]\n\t" /* old->X21,X22 */
|
||||
"stp x23, x24, [x0, #0xc0]\n\t" /* old->X23,X24 */
|
||||
"stp x25, x26, [x0, #0xd0]\n\t" /* old->X25,X26 */
|
||||
"stp x27, x28, [x0, #0xe0]\n\t" /* old->X27,X28 */
|
||||
"str x29, [x0, #0xf0]\n\t" /* old->Fp */
|
||||
"mov x2, sp\n\t"
|
||||
"str x2, [x0, #0x100]\n\t" /* old->Sp */
|
||||
"str x30, [x0, #0x108]\n\t" /* old->Pc */
|
||||
"ldp x19, x20, [x1, #0xa0]\n\t" /* new->X19,X20 */
|
||||
"ldp x21, x22, [x1, #0xb0]\n\t" /* new->X21,X22 */
|
||||
"ldp x23, x24, [x1, #0xc0]\n\t" /* new->X23,X24 */
|
||||
"ldp x25, x26, [x1, #0xd0]\n\t" /* new->X25,X26 */
|
||||
"ldp x27, x28, [x1, #0xe0]\n\t" /* new->X27,X28 */
|
||||
"ldr x29, [x1, #0xf0]\n\t" /* new->Fp */
|
||||
"ldr x2, [x1, #0x100]\n\t" /* new->Sp */
|
||||
"ldr x30, [x1, #0x108]\n\t" /* new->Pc */
|
||||
"mov sp, x2\n\t"
|
||||
"ret" )
|
||||
#else
|
||||
void WINAPI switch_fiber( CONTEXT *old, CONTEXT *new )
|
||||
{
|
||||
struct fiber_data *fiber = arg;
|
||||
DbgBreakPoint();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* call the fiber initial function once we have switched stack */
|
||||
static void CDECL start_fiber(void)
|
||||
{
|
||||
struct fiber_data *fiber = NtCurrentTeb()->Tib.u.FiberData;
|
||||
LPFIBER_START_ROUTINE start = fiber->start;
|
||||
|
||||
__TRY
|
||||
{
|
||||
fiber->start = NULL;
|
||||
start( fiber->param );
|
||||
ExitThread( 1 );
|
||||
}
|
||||
|
@ -72,6 +179,23 @@ static void start_fiber( void *arg )
|
|||
__ENDTRY
|
||||
}
|
||||
|
||||
static void init_fiber_context( struct fiber_data *fiber )
|
||||
{
|
||||
#ifdef __i386__
|
||||
fiber->context.Esp = (ULONG_PTR)fiber->stack_base - 4;
|
||||
fiber->context.Eip = (ULONG_PTR)start_fiber;
|
||||
#elif defined(__x86_64__)
|
||||
fiber->context.Rsp = (ULONG_PTR)fiber->stack_base - 0x28;
|
||||
fiber->context.Rip = (ULONG_PTR)start_fiber;
|
||||
#elif defined(__arm__)
|
||||
fiber->context.Sp = (ULONG_PTR)fiber->stack_base;
|
||||
fiber->context.Pc = (ULONG_PTR)start_fiber;
|
||||
#elif defined(__aarch64__)
|
||||
fiber->context.Sp = (ULONG_PTR)fiber->stack_base;
|
||||
fiber->context.Pc = (ULONG_PTR)start_fiber;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* CreateFiber (KERNEL32.@)
|
||||
|
@ -92,7 +216,7 @@ LPVOID WINAPI CreateFiberEx( SIZE_T stack_commit, SIZE_T stack_reserve, DWORD fl
|
|||
INITIAL_TEB stack;
|
||||
NTSTATUS status;
|
||||
|
||||
if (!(fiber = HeapAlloc( GetProcessHeap(), 0, sizeof(*fiber) )))
|
||||
if (!(fiber = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*fiber) )))
|
||||
{
|
||||
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||||
return NULL;
|
||||
|
@ -111,7 +235,7 @@ LPVOID WINAPI CreateFiberEx( SIZE_T stack_commit, SIZE_T stack_reserve, DWORD fl
|
|||
fiber->except = (void *)-1;
|
||||
fiber->start = start;
|
||||
fiber->flags = flags;
|
||||
fiber->fls_slots = NULL;
|
||||
init_fiber_context( fiber );
|
||||
return fiber;
|
||||
}
|
||||
|
||||
|
@ -199,19 +323,13 @@ void WINAPI SwitchToFiber( LPVOID fiber )
|
|||
/* stack_allocation and stack_base never change */
|
||||
|
||||
/* FIXME: should save floating point context if requested in fiber->flags */
|
||||
if (!sigsetjmp( current_fiber->jmpbuf, 0 ))
|
||||
{
|
||||
NtCurrentTeb()->Tib.u.FiberData = new_fiber;
|
||||
NtCurrentTeb()->Tib.ExceptionList = new_fiber->except;
|
||||
NtCurrentTeb()->Tib.StackBase = new_fiber->stack_base;
|
||||
NtCurrentTeb()->Tib.StackLimit = new_fiber->stack_limit;
|
||||
NtCurrentTeb()->DeallocationStack = new_fiber->stack_allocation;
|
||||
NtCurrentTeb()->FlsSlots = new_fiber->fls_slots;
|
||||
if (new_fiber->start) /* first time */
|
||||
wine_switch_to_stack( start_fiber, new_fiber, new_fiber->stack_base );
|
||||
else
|
||||
siglongjmp( new_fiber->jmpbuf, 1 );
|
||||
}
|
||||
NtCurrentTeb()->Tib.u.FiberData = new_fiber;
|
||||
NtCurrentTeb()->Tib.ExceptionList = new_fiber->except;
|
||||
NtCurrentTeb()->Tib.StackBase = new_fiber->stack_base;
|
||||
NtCurrentTeb()->Tib.StackLimit = new_fiber->stack_limit;
|
||||
NtCurrentTeb()->DeallocationStack = new_fiber->stack_allocation;
|
||||
NtCurrentTeb()->FlsSlots = new_fiber->fls_slots;
|
||||
switch_fiber( ¤t_fiber->context, &new_fiber->context );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
|
Loading…
Reference in New Issue