240 lines
9.2 KiB
Diff
240 lines
9.2 KiB
Diff
--- dlls/ntdll/unix/signal_x86_64.c
|
|
+++ dlls/ntdll/unix/signal_x86_64.c
|
|
@@ -152,6 +152,9 @@ __ASM_GLOBAL_FUNC( alloc_fs_sel,
|
|
|
|
#elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__)
|
|
|
|
+#include <machine/cpufunc.h>
|
|
+#include <machine/segments.h>
|
|
+#include <machine/specialreg.h>
|
|
#include <machine/trap.h>
|
|
|
|
#define RAX_sig(context) ((context)->uc_mcontext.mc_rax)
|
|
@@ -469,7 +472,7 @@ static inline struct amd64_thread_data *amd64_thread_data(void)
|
|
return (struct amd64_thread_data *)ntdll_get_thread_data()->cpu_data;
|
|
}
|
|
|
|
-#ifdef __linux__
|
|
+#if defined(__linux__) || defined(__FreeBSD__)
|
|
static inline TEB *get_current_teb(void)
|
|
{
|
|
unsigned long rsp;
|
|
@@ -1654,7 +1657,7 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback,
|
|
"movq %rsp,0x328(%r8)\n\t" /* amd64_thread_data()->syscall_frame */
|
|
/* switch to user stack */
|
|
"movq %rdi,%rsp\n\t" /* user_rsp */
|
|
-#ifdef __linux__
|
|
+#if defined(__linux__) || defined(__FreeBSD__)
|
|
"testl $12,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */
|
|
"jz 1f\n\t"
|
|
"movw 0x338(%r13),%fs\n" /* amd64_thread_data()->fs */
|
|
@@ -2375,6 +2378,16 @@ static void ldt_set_entry( WORD sel, LDT_ENTRY entry )
|
|
|
|
#if defined(__APPLE__)
|
|
if (i386_set_ldt(index, (union ldt_entry *)&entry, 1) < 0) perror("i386_set_ldt");
|
|
+#elif defined(__FreeBSD__)
|
|
+ struct i386_ldt_args p;
|
|
+ p.start = index;
|
|
+ p.descs = (struct user_segment_descriptor *)&entry;
|
|
+ p.num = 1;
|
|
+ if (sysarch(I386_SET_LDT, &p) == -1)
|
|
+ {
|
|
+ perror("i386_set_ldt");
|
|
+ exit(1);
|
|
+ }
|
|
#else
|
|
fprintf( stderr, "No LDT support on this platform\n" );
|
|
exit(1);
|
|
@@ -2485,6 +2498,38 @@ static void *mac_thread_gsbase(void)
|
|
}
|
|
#endif
|
|
|
|
+#ifdef __FreeBSD__
|
|
+static __siginfohandler_t *libthr_signal_handlers[_SIG_MAXSIG];
|
|
+
|
|
+/* occasionally signals happen right between %fs reset to GUFS32_SEL and fsbase correction,
|
|
+which results in fsbase being wrong on handler entry; we'll just restore fsbase ourselves */
|
|
+static void libthr_sighandler_wrapper(int sig, siginfo_t *info, void *_ucp) {
|
|
+ struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&get_current_teb()->GdiTebBatch;
|
|
+ amd64_set_fsbase(((struct amd64_thread_data *)thread_data->cpu_data)->pthread_teb);
|
|
+ libthr_signal_handlers[sig - 1](sig, info, _ucp);
|
|
+}
|
|
+
|
|
+extern int __sys_sigaction(int, const struct sigaction *, struct sigaction *);
|
|
+
|
|
+static int wrap_libthr_signal_handlers(void) {
|
|
+ struct sigaction act;
|
|
+ int sig;
|
|
+
|
|
+ for (sig = 1; sig <= _SIG_MAXSIG; sig++) {
|
|
+
|
|
+ if (__sys_sigaction(sig, NULL, &act) == -1) return -1;
|
|
+ if (act.sa_sigaction != NULL) {
|
|
+
|
|
+ libthr_signal_handlers[sig - 1] = act.sa_sigaction;
|
|
+ act.sa_sigaction = libthr_sighandler_wrapper;
|
|
+
|
|
+ if (__sys_sigaction(sig, &act, NULL) == -1) return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
|
|
/**********************************************************************
|
|
* signal_init_process
|
|
@@ -2550,6 +2595,37 @@ void signal_init_process(void)
|
|
break;
|
|
}
|
|
}
|
|
+#elif defined(__FreeBSD__)
|
|
+ if (wow_teb)
|
|
+ {
|
|
+ u_int p[4];
|
|
+ u_int cpu_stdext_feature;
|
|
+
|
|
+ LDT_ENTRY fs32_entry = ldt_make_entry(wow_teb, page_size - 1, LDT_FLAGS_DATA | LDT_FLAGS_32BIT);
|
|
+
|
|
+ cs32_sel = GSEL(GUCODE32_SEL, SEL_UPL);
|
|
+
|
|
+ amd64_thread_data()->fs = LSEL(first_ldt_entry, SEL_UPL);
|
|
+ ldt_set_entry(amd64_thread_data()->fs, fs32_entry);
|
|
+
|
|
+ syscall_flags |= SYSCALL_HAVE_PTHREAD_TEB;
|
|
+
|
|
+ do_cpuid(0, p);
|
|
+ if (p[0] >= 7)
|
|
+ {
|
|
+ cpuid_count(7, 0, p);
|
|
+ cpu_stdext_feature = p[1];
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ cpu_stdext_feature = 0;
|
|
+ }
|
|
+
|
|
+ if (cpu_stdext_feature & CPUID_STDEXT_FSGSBASE)
|
|
+ {
|
|
+ syscall_flags |= SYSCALL_HAVE_WRFSGSBASE;
|
|
+ }
|
|
+ }
|
|
#endif
|
|
|
|
sig_act.sa_mask = server_block_set;
|
|
@@ -2574,6 +2650,9 @@ void signal_init_process(void)
|
|
#ifdef __APPLE__
|
|
sig_act.sa_sigaction = sigsys_handler;
|
|
if (sigaction( SIGSYS, &sig_act, NULL ) == -1) goto error;
|
|
+#endif
|
|
+#ifdef __FreeBSD__
|
|
+ if (wrap_libthr_signal_handlers() == -1) goto error;
|
|
#endif
|
|
return;
|
|
|
|
@@ -2603,7 +2682,8 @@ void init_syscall_frame( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend,
|
|
arch_prctl( ARCH_GET_FS, &thread_data->pthread_teb );
|
|
if (fs32_sel) alloc_fs_sel( fs32_sel >> 3, get_wow_teb( teb ));
|
|
#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
|
|
- amd64_set_gsbase( teb );
|
|
+ amd64_set_gsbase(teb);
|
|
+ amd64_get_fsbase(&thread_data->pthread_teb);
|
|
#elif defined(__NetBSD__)
|
|
sysarch( X86_64_SET_GSBASE, &teb );
|
|
#elif defined (__APPLE__)
|
|
@@ -2818,6 +2898,30 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
|
|
"syscall\n\t"
|
|
"leaq -0x98(%rbp),%rcx\n"
|
|
"2:\n\t"
|
|
+#elif defined(__FreeBSD__)
|
|
+ "testl $12,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */
|
|
+ "jz 2f\n\t"
|
|
+ "movq $0x13,%rsi\n\t" /* GSEL(GUFS32_SEL, SEL_UPL) */
|
|
+ "movq %rsi,%fs\n\t"
|
|
+ "movq %gs:0x320,%rsi\n\t" /* amd64_thread_data()->pthread_teb */
|
|
+ "testl $8,%r14d\n\t" /* SYSCALL_HAVE_WRFSGSBASE */
|
|
+ "jz 1f\n\t"
|
|
+ "wrfsbase %rsi\n\t"
|
|
+ "jmp 2f\n"
|
|
+ "1:\n\t"
|
|
+ "pushq %r8\n\t"
|
|
+ "pushq %r9\n\t"
|
|
+ "pushq %r10\n\t"
|
|
+ "pushq %r11\n\t"
|
|
+ "movq $0xa5,%rax\n\t" /* sysarch */
|
|
+ "movq $0x81,%rdi\n\t" /* AMD64_SET_FSBASE */
|
|
+ "syscall\n\t"
|
|
+ "popq %r11\n\t"
|
|
+ "popq %r10\n\t"
|
|
+ "popq %r9\n\t"
|
|
+ "popq %r8\n\t"
|
|
+ "leaq -0x98(%rbp),%rcx\n"
|
|
+ "2:\n\t"
|
|
#endif
|
|
"movq 0x00(%rcx),%rax\n\t"
|
|
"movq 0x18(%rcx),%r11\n\t" /* 2nd argument */
|
|
@@ -2863,10 +2967,15 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
|
|
"movq 0x20(%rcx),%rsi\n\t"
|
|
"movq 0x08(%rcx),%rbx\n\t"
|
|
"leaq 0x70(%rcx),%rsp\n\t" /* %rsp > frame means no longer inside syscall */
|
|
-#ifdef __linux__
|
|
+#if defined(__linux__) || defined(__FreeBSD__)
|
|
"testl $12,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */
|
|
"jz 1f\n\t"
|
|
"movw %gs:0x338,%fs\n" /* amd64_thread_data()->fs */
|
|
+# ifdef __FreeBSD__
|
|
+ /* reset %ss (after sysret) for AMD */
|
|
+ "movq $0x3b,%r14\n\t" /* GSEL(GUDATA_SEL, SEL_UPL) */
|
|
+ "movq %r14,%ss\n\t"
|
|
+# endif
|
|
"1:\n\t"
|
|
#endif
|
|
"testl $0x10000,%edx\n\t" /* RESTORE_FLAGS_INSTRUMENTATION */
|
|
@@ -3103,6 +3212,29 @@ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher,
|
|
"mov $158,%eax\n\t" /* SYS_arch_prctl */
|
|
"syscall\n\t"
|
|
"2:\n\t"
|
|
+#elif defined(__FreeBSD__)
|
|
+ "testl $12,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */
|
|
+ "jz 2f\n\t"
|
|
+ "movq $0x13,%rsi\n\t" /* GSEL(GUFS32_SEL, SEL_UPL) */
|
|
+ "movq %rsi,%fs\n\t"
|
|
+ "movq %gs:0x320,%rsi\n\t" /* amd64_thread_data()->pthread_teb */
|
|
+ "testl $8,%r14d\n\t" /* SYSCALL_HAVE_WRFSGSBASE */
|
|
+ "jz 1f\n\t"
|
|
+ "wrfsbase %rsi\n\t"
|
|
+ "jmp 2f\n"
|
|
+ "1:\n\t"
|
|
+ "pushq %r8\n\t"
|
|
+ "pushq %r9\n\t"
|
|
+ "pushq %r10\n\t"
|
|
+ "pushq %r11\n\t"
|
|
+ "movq $0xa5,%rax\n\t" /* sysarch */
|
|
+ "movq $0x81,%rdi\n\t" /* AMD64_SET_FSBASE */
|
|
+ "syscall\n\t"
|
|
+ "popq %r11\n\t"
|
|
+ "popq %r10\n\t"
|
|
+ "popq %r9\n\t"
|
|
+ "popq %r8\n\t"
|
|
+ "2:\n\t"
|
|
#endif
|
|
"movq %r8,%rdi\n\t" /* args */
|
|
"callq *(%r10,%rdx,8)\n\t"
|
|
@@ -3127,10 +3259,15 @@ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher,
|
|
/* switch to user stack */
|
|
"movq 0x88(%rcx),%rsp\n\t"
|
|
__ASM_CFI(".cfi_restore_state\n\t")
|
|
-#ifdef __linux__
|
|
+#if defined(__linux__) || defined(__FreeBSD__)
|
|
"testl $12,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */
|
|
"jz 1f\n\t"
|
|
"movw %gs:0x338,%fs\n" /* amd64_thread_data()->fs */
|
|
+# ifdef __FreeBSD__
|
|
+ /* reset %ss (after sysret) for AMD */
|
|
+ "movq $0x3b,%r14\n\t" /* GSEL(GUDATA_SEL, SEL_UPL) */
|
|
+ "movq %r14,%ss\n\t"
|
|
+# endif
|
|
"1:\n\t"
|
|
#endif
|
|
"movq 0x60(%rcx),%r14\n\t"
|