diff --git a/include/winnt.h b/include/winnt.h index d824e71a7cf..08fb64c405e 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -2314,6 +2314,14 @@ extern inline struct _TEB * WINAPI NtCurrentTeb(void) __asm mov teb, eax; return teb; } +#elif defined(__powerpc__) +extern inline struct _TEB * WINAPI NtCurrentTeb(void); +extern inline struct _TEB * WINAPI NtCurrentTeb(void) +{ + struct _TEB *teb; + __asm__("\tmr %0, 13" : "=r" (teb)); + return teb; +} #else extern struct _TEB * WINAPI NtCurrentTeb(void); #endif diff --git a/library/port.c b/library/port.c index c63322a5933..01effca3dde 100644 --- a/library/port.c +++ b/library/port.c @@ -696,6 +696,94 @@ __ASM_GLOBAL_FUNC(interlocked_xchg_add, "lock; xaddl %eax,(%edx)\n\t" "ret"); +#elif defined(__powerpc__) +void* interlocked_cmpxchg_ptr( void **dest, void* xchg, void* compare) +{ + long ret; + long scratch; + __asm__ __volatile__( + "sync; " + "0: lwarx %0,0,%2 ;" + " xor. %1,%4,%0;" + " bne 1f;" + " stwcx. %3,0,%2;" + " bne- 0b;" + "1: " + "sync; " + : "=&r"(ret), "=&r"(scratch) + : "r"(dest), "r"(xchg), "r"(compare) + : "cr0", "memory"); + return (void*)ret; +} + +long interlocked_cmpxchg( long *dest, long xchg, long compare) +{ + long ret; + long scratch; + __asm__ __volatile__( + "sync; " + "0: lwarx %0,0,%2 ;" + " xor. %1,%4,%0;" + " bne 1f;" + " stwcx. %3,0,%2;" + " bne- 0b;" + "1: " + "sync; " + : "=&r"(ret), "=&r"(scratch) + : "r"(dest), "r"(xchg), "r"(compare) + : "cr0", "memory"); + return ret; +} + +long interlocked_xchg_add( long *dest, long incr ) +{ + void *ret __attribute__ ((aligned (4))) = &ret; + long inc = incr; + long zero = 0; + __asm__ __volatile__( + "sync; " + "0: lwarx %0, %3, %1;" + " add %0, %2, %0;" + " stwcx. %0, %3, %1;" + " bne- 0b;" + "sync; " + : "=&r"(ret) + : "r"(dest), "r"(inc), "r"(zero) + : "cr0", "memory" + ); + return (long)ret; +} + +long interlocked_xchg( long* dest, long val ) +{ + void *ret __attribute__ ((aligned (4))) = &ret; + __asm__ __volatile__( + "sync; " + "0: lwarx %0,0,%1 ;" + " stwcx. %2,0,%1;" + " bne- 0b;" + "sync; " + : "=&r"(ret) + : "r"(dest), "r"(val) + : "cr0", "memory"); + return (long)ret; +} + +void* interlocked_xchg_ptr( void** dest, void* val ) +{ + void *ret __attribute__ ((aligned (4))) = &ret; + __asm__ __volatile__( + "sync; " + "0: lwarx %0,0,%1 ;" + " stwcx. %2,0,%1;" + " bne- 0b;" + "sync; " + : "=&r"(ret) + : "r"(dest), "r"(val) + : "cr0", "memory"); + return (void*)ret; +} + #elif defined(__sparc__) && defined(__sun__) /* @@ -757,7 +845,6 @@ long interlocked_xchg_add( long *dest, long incr ) _lwp_mutex_unlock( &interlocked_mutex ); return retv; } - #else # error You must implement the interlocked* functions for your CPU #endif diff --git a/scheduler/sysdeps.c b/scheduler/sysdeps.c index b3320e739bd..06170dbb07a 100644 --- a/scheduler/sysdeps.c +++ b/scheduler/sysdeps.c @@ -85,6 +85,9 @@ void SYSDEPS_SetCurThread( TEB *teb ) #if defined(__i386__) /* On the i386, the current thread is in the %fs register */ wine_set_fs( teb->teb_sel ); +#elif defined(__powerpc__) + /* On PowerPC, the current TEB is in the gpr13 register */ + __asm__ __volatile__("mr 13, %0" : : "r" (teb)); #elif defined(HAVE__LWP_CREATE) /* On non-i386 Solaris, we use the LWP private pointer */ _lwp_setprivate( teb ); @@ -249,13 +252,13 @@ __declspec(naked) void SYSDEPS_CallOnStack( void (*func)(LPVOID), LPVOID arg ) __asm int 3; } #endif /* defined(__GNUC__) || defined(_MSC_VER) */ -#else /* defined(__i386__) */ +#else /* !defined(__i386__) */ void SYSDEPS_CallOnStack( void (*func)(LPVOID), LPVOID arg ) { func( arg ); while(1); /* avoid warning */ } -#endif /* defined(__i386__) */ +#endif /* !defined(__i386__) */ /*********************************************************************** @@ -335,6 +338,8 @@ struct _TEB * WINAPI NtCurrentTeb(void) extern void *_lwp_getprivate(void); return (struct _TEB *)_lwp_getprivate(); } +#elif defined(__powerpc__) +__ASM_GLOBAL_FUNC( NtCurrentTeb, "\n\tmr 3,13\n\tblr" ); #else # error NtCurrentTeb not defined for this architecture #endif /* __i386__ */