[PATCH 2/3] Initial port to PowerPC 64 Little Endian systems Verified

Timothy Pearson tpearson at raptorengineering.com
Tue Feb 26 04:04:28 CST 2019


 to start winecfg

Signed-off-by: Timothy Pearson <tpearson at raptorengineering.com>
---
 configure                       |   38 +
 configure.ac                    |    9 +
 dlls/dbghelp/Makefile.in        |    1 +
 dlls/dbghelp/cpu_ppc64.c        |  100 +++
 dlls/dbghelp/dbghelp.c          |    6 +-
 dlls/kernel32/cpu.c             |    3 +
 dlls/kernel32/module.c          |    1 +
 dlls/kernel32/process.c         |    8 +-
 dlls/kernel32/tests/file.c      |    2 +
 dlls/kernel32/tests/loader.c    |    2 +
 dlls/kernel32/tests/module.c    |    2 +
 dlls/ntdll/Makefile.in          |    1 +
 dlls/ntdll/loader.c             |   10 +-
 dlls/ntdll/nt.c                 |    8 +
 dlls/ntdll/ntdll.spec           |    2 +-
 dlls/ntdll/process.c            |    8 +-
 dlls/ntdll/server.c             |    6 +-
 dlls/ntdll/signal_powerpc.c     |    4 +-
 dlls/ntdll/signal_ppc64.c       | 1221 +++++++++++++++++++++++++++++++
 dlls/ntdll/virtual.c            |    2 +-
 dlls/setupapi/fakedll.c         |    2 +
 dlls/ucrtbase/ucrtbase.spec     |    2 +-
 include/basetsd.h               |   10 +
 include/msvcrt/crtdefs.h        |    6 +
 include/rpc.h                   |    4 +-
 include/windef.h                |    6 +
 include/wine/server_protocol.h  |    6 +-
 include/winnt.h                 |  138 +++-
 libs/port/interlocked.c         |    2 +-
 libs/wine/port.c                |   19 +
 programs/winedbg/Makefile.in    |    1 +
 programs/winedbg/be_ppc.c       |    2 +-
 programs/winedbg/be_ppc64.c     |  303 ++++++++
 programs/winedbg/gdbproxy.c     |    2 +
 programs/winedbg/tgt_active.c   |    2 +
 programs/winedbg/tgt_minidump.c |    3 +
 programs/winedbg/winedbg.c      |    4 +
 programs/winetest/main.c        |    2 +
 server/mapping.c                |    8 +-
 server/process.h                |    2 +-
 server/protocol.def             |    6 +-
 server/thread.c                 |    6 +
 server/trace.c                  |   21 +
 tools/widl/widl.c               |    7 +
 tools/widl/widl.h               |    2 +-
 tools/widl/write_msft.c         |    2 +-
 tools/winebuild/build.h         |    4 +-
 tools/winebuild/import.c        |  117 +++
 tools/winebuild/main.c          |    6 +
 tools/winebuild/parser.c        |    4 +-
 tools/winebuild/spec32.c        |   37 +-
 tools/winebuild/utils.c         |   12 +
 tools/winedump/minidump.c       |    3 +
 tools/winedump/pe.c             |    1 +
 tools/winegcc/utils.h           |    2 +-
 tools/winegcc/winegcc.c         |   41 +-
 tools/wrc/wrc.c                 |    3 +-
 57 files changed, 2168 insertions(+), 64 deletions(-)
 create mode 100644 dlls/dbghelp/cpu_ppc64.c
 create mode 100644 dlls/ntdll/signal_ppc64.c
 create mode 100644 programs/winedbg/be_ppc64.c

diff --git a/configure b/configure
index 793e2ffc5c..c0e210d429 100755
--- a/configure
+++ b/configure
@@ -5670,6 +5670,15 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
   i[3456789]86*)
     enable_win16=${enable_win16:-yes}
     ;;
+  powerpc64*)
+    CC="$CC -m64"
+    CXX="$CXX -m64"
+    host_cpu="powerpc64"
+    notice_platform="64-bit "
+    TARGETFLAGS="-m64"
+
+    enable_win64=${enable_win64:-yes}
+    ;;
 esac
 
 enable_win16=${enable_win16:-no}
@@ -9215,6 +9224,7 @@ fi
         *x86_64*)      exec_prefix='${prefix}/x86_64' ;;
         *arm*)         exec_prefix='${prefix}/armeabi-v7a' ;;
         *aarch64*)     exec_prefix='${prefix}/arm64-v8a' ;;
+        *powerpc64*)   exec_prefix='${prefix}/ppc64' ;;
       esac
     fi
     ;;
@@ -16279,6 +16289,34 @@ CFLAGS=$ac_wine_try_cflags_saved
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fno_omit_frame_pointer" >&5
 $as_echo "$ac_cv_cflags__fno_omit_frame_pointer" >&6; }
+if test "x$ac_cv_cflags__fno_omit_frame_pointer" = xyes; then :
+  EXTRACFLAGS="$EXTRACFLAGS -fno-omit-frame-pointer"
+fi ;;
+  esac
+
+    case $host_cpu in
+    *powerpc64*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fno-omit-frame-pointer" >&5
+$as_echo_n "checking whether the compiler supports -fno-omit-frame-pointer... " >&6; }
+if ${ac_cv_cflags__fno_omit_frame_pointer+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_wine_try_cflags_saved=$CFLAGS
+CFLAGS="$CFLAGS -fno-omit-frame-pointer"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int main(int argc, char **argv) { return 0; }
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_cflags__fno_omit_frame_pointer=yes
+else
+  ac_cv_cflags__fno_omit_frame_pointer=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+CFLAGS=$ac_wine_try_cflags_saved
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fno_omit_frame_pointer" >&5
+$as_echo "$ac_cv_cflags__fno_omit_frame_pointer" >&6; }
 if test "x$ac_cv_cflags__fno_omit_frame_pointer" = xyes; then :
   EXTRACFLAGS="$EXTRACFLAGS -fno-omit-frame-pointer"
 fi ;;
diff --git a/configure.ac b/configure.ac
index c978477a51..a615e4a5e6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -217,6 +217,14 @@ case $host in
   i[[3456789]]86*)
     enable_win16=${enable_win16:-yes}
     ;;
+  powerpc64*)
+    CC="$CC -m64"
+    CXX="$CXX -m64"
+    host_cpu="powerpc64"
+    notice_platform="64-bit "
+    AC_SUBST(TARGETFLAGS,"-m64")
+    enable_win64=${enable_win64:-yes}
+    ;;
 esac
 
 dnl enable_win16 defaults to yes on x86, to no on other CPUs
@@ -932,6 +940,7 @@ case $host_os in
         *x86_64*)      exec_prefix='${prefix}/x86_64' ;;
         *arm*)         exec_prefix='${prefix}/armeabi-v7a' ;;
         *aarch64*)     exec_prefix='${prefix}/arm64-v8a' ;;
+        *powerpc64*)   exec_prefix='${prefix}/ppc64' ;;
       esac
     fi
     ;;
diff --git a/dlls/dbghelp/Makefile.in b/dlls/dbghelp/Makefile.in
index 3e120e8afe..35b14ad6bd 100644
--- a/dlls/dbghelp/Makefile.in
+++ b/dlls/dbghelp/Makefile.in
@@ -10,6 +10,7 @@ C_SRCS = \
 	cpu_arm64.c \
 	cpu_i386.c \
 	cpu_ppc.c \
+	cpu_ppc64.c \
 	cpu_x86_64.c \
 	crc32.c \
 	dbghelp.c \
diff --git a/dlls/dbghelp/cpu_ppc64.c b/dlls/dbghelp/cpu_ppc64.c
new file mode 100644
index 0000000000..270da05f39
--- /dev/null
+++ b/dlls/dbghelp/cpu_ppc64.c
@@ -0,0 +1,100 @@
+/*
+ * File cpu_ppc64.c
+ *
+ * Copyright (C) 2009-2009, Eric Pouech.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <assert.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "dbghelp_private.h"
+#include "winternl.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
+
+static BOOL ppc64_get_addr(HANDLE hThread, const CONTEXT* ctx,
+                         enum cpu_addr ca, ADDRESS64* addr)
+{
+   switch (ca)
+    {
+#if defined(__powerpc64__)
+    case cpu_addr_pc:
+        addr->Mode    = AddrModeFlat;
+        addr->Segment = 0; /* don't need segment */
+        addr->Offset  = ctx->Iar;
+        return TRUE;
+#endif
+    default:
+    case cpu_addr_stack:
+    case cpu_addr_frame:
+        FIXME("not done\n");
+    }
+    return FALSE;
+}
+
+static BOOL ppc64_stack_walk(struct cpu_stack_walk* csw, STACKFRAME64 *frame,
+    union ctx *ctx)
+{
+    FIXME("not done\n");
+    return FALSE;
+}
+
+static unsigned ppc64_map_dwarf_register(unsigned regno, BOOL eh_frame)
+{
+    FIXME("not done\n");
+    return 0;
+}
+
+static void *ppc64_fetch_context_reg(union ctx *ctx, unsigned regno, unsigned *size)
+{
+    FIXME("NIY\n");
+    return NULL;
+}
+
+static const char* ppc64_fetch_regname(unsigned regno)
+{
+    FIXME("Unknown register %x\n", regno);
+    return NULL;
+}
+
+static BOOL ppc64_fetch_minidump_thread(struct dump_context* dc, unsigned index, unsigned flags, const CONTEXT* ctx)
+{
+    FIXME("NIY\n");
+    return FALSE;
+}
+
+static BOOL ppc64_fetch_minidump_module(struct dump_context* dc, unsigned index, unsigned flags)
+{
+    FIXME("NIY\n");
+    return FALSE;
+}
+
+DECLSPEC_HIDDEN struct cpu cpu_ppc64 = {
+    IMAGE_FILE_MACHINE_POWERPC64,
+    8,
+    CV_REG_NONE, /* FIXME */
+    ppc64_get_addr,
+    ppc64_stack_walk,
+    NULL,
+    ppc64_map_dwarf_register,
+    ppc64_fetch_context_reg,
+    ppc64_fetch_regname,
+    ppc64_fetch_minidump_thread,
+    ppc64_fetch_minidump_module,
+};
diff --git a/dlls/dbghelp/dbghelp.c b/dlls/dbghelp/dbghelp.c
index ed4d5f4321..e4a0a6d509 100644
--- a/dlls/dbghelp/dbghelp.c
+++ b/dlls/dbghelp/dbghelp.c
@@ -132,14 +132,16 @@ const char* wine_dbgstr_addr(const ADDRESS64* addr)
     }
 }
 
-extern struct cpu       cpu_i386, cpu_x86_64, cpu_ppc, cpu_arm, cpu_arm64;
+extern struct cpu       cpu_i386, cpu_x86_64, cpu_ppc, cpu_arm, cpu_arm64, cpu_ppc64;
 
-static struct cpu*      dbghelp_cpus[] = {&cpu_i386, &cpu_x86_64, &cpu_ppc, &cpu_arm, &cpu_arm64, NULL};
+static struct cpu*      dbghelp_cpus[] = {&cpu_i386, &cpu_x86_64, &cpu_ppc, &cpu_arm, &cpu_arm64, &cpu_ppc64, NULL};
 struct cpu*             dbghelp_current_cpu =
 #if defined(__i386__)
     &cpu_i386
 #elif defined(__x86_64__)
     &cpu_x86_64
+#elif defined(__powerpc64__)
+    &cpu_ppc64
 #elif defined(__powerpc__)
     &cpu_ppc
 #elif defined(__arm__)
diff --git a/dlls/kernel32/cpu.c b/dlls/kernel32/cpu.c
index 9445d0bc05..71032c4ae4 100644
--- a/dlls/kernel32/cpu.c
+++ b/dlls/kernel32/cpu.c
@@ -145,6 +145,9 @@ VOID WINAPI GetSystemInfo(
         default: si->dwProcessorType = 0;
         }
         break;
+    case PROCESSOR_ARCHITECTURE_PPC64:
+        si->dwProcessorType = PROCESSOR_PPC64_OP;
+        break;
     case PROCESSOR_ARCHITECTURE_AMD64:
         si->dwProcessorType = PROCESSOR_AMD_X8664;
         break;
diff --git a/dlls/kernel32/module.c b/dlls/kernel32/module.c
index eb0471cc8e..c70b9ace57 100644
--- a/dlls/kernel32/module.c
+++ b/dlls/kernel32/module.c
@@ -333,6 +333,7 @@ BOOL WINAPI GetBinaryTypeW( LPCWSTR name, LPDWORD type )
                 return TRUE;
             case IMAGE_FILE_MACHINE_AMD64:
             case IMAGE_FILE_MACHINE_ARM64:
+            case IMAGE_FILE_MACHINE_POWERPC64:
                 *type = SCS_64BIT_BINARY;
                 return TRUE;
             }
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c
index ad257a054e..61c18c77c5 100644
--- a/dlls/kernel32/process.c
+++ b/dlls/kernel32/process.c
@@ -111,7 +111,7 @@ static WCHAR winevdm[] = {'C',':','\\','w','i','n','d','o','w','s',
                           '\\','s','y','s','t','e','m','3','2',
                           '\\','w','i','n','e','v','d','m','.','e','x','e',0};
 
-static const char * const cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64" };
+static const char * const cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64","PowerPC 64" };
 
 static void exec_process( LPCWSTR name );
 
@@ -173,7 +173,7 @@ static inline unsigned int is_path_prefix( const WCHAR *prefix, const WCHAR *fil
  */
 static inline BOOL is_64bit_arch( cpu_type_t cpu )
 {
-    return (cpu == CPU_x86_64 || cpu == CPU_ARM64);
+    return (cpu == CPU_x86_64 || cpu == CPU_ARM64 || cpu == CPU_POWERPC64);
 }
 
 
@@ -286,6 +286,7 @@ static enum binary_type get_binary_info( HANDLE hfile, pe_image_info_t *info )
         {
         case 3:   info->cpu = CPU_x86; break;
         case 20:  info->cpu = CPU_POWERPC; break;
+        case 22:  info->cpu = CPU_POWERPC64; break;
         case 40:  info->cpu = CPU_ARM; break;
         case 62:  info->cpu = CPU_x86_64; break;
         case 183: info->cpu = CPU_ARM64; break;
@@ -338,6 +339,7 @@ static enum binary_type get_binary_info( HANDLE hfile, pe_image_info_t *info )
         case 0x0000000c: info->cpu = CPU_ARM; break;
         case 0x0100000c: info->cpu = CPU_ARM64; break;
         case 0x00000012: info->cpu = CPU_POWERPC; break;
+        case 0x00000014: info->cpu = CPU_POWERPC64; break;
         }
         switch(header.macho.filetype)
         {
@@ -2716,6 +2718,8 @@ BOOL WINAPI CreateProcessInternalW( HANDLE token, LPCWSTR app_name, LPWSTR cmd_l
         /* assume current arch */
 #if defined(__i386__) || defined(__x86_64__)
         pe_info.cpu = is_64bit ? CPU_x86_64 : CPU_x86;
+#elif defined(__powerpc64__)
+        pe_info.cpu = CPU_POWERPC64;
 #elif defined(__powerpc__)
         pe_info.cpu = CPU_POWERPC;
 #elif defined(__arm__)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c
index 33b17aa327..ef91548c9b 100644
--- a/dlls/kernel32/tests/file.c
+++ b/dlls/kernel32/tests/file.c
@@ -2278,6 +2278,8 @@ static BOOL create_fake_dll( LPCSTR filename )
     nt->FileHeader.Machine = IMAGE_FILE_MACHINE_I386;
 #elif defined __x86_64__
     nt->FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64;
+#elif defined __powerpc64__
+    nt->FileHeader.Machine = IMAGE_FILE_MACHINE_POWERPC64;
 #elif defined __powerpc__
     nt->FileHeader.Machine = IMAGE_FILE_MACHINE_POWERPC;
 #elif defined __arm__
diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c
index b8dc72bc7f..b2c65c4123 100644
--- a/dlls/kernel32/tests/loader.c
+++ b/dlls/kernel32/tests/loader.c
@@ -102,6 +102,8 @@ static const IMAGE_NT_HEADERS nt_header_template =
       IMAGE_FILE_MACHINE_I386, /* Machine */
 #elif defined __x86_64__
       IMAGE_FILE_MACHINE_AMD64, /* Machine */
+#elif defined __powerpc64__
+      IMAGE_FILE_MACHINE_POWERPC64, /* Machine */
 #elif defined __powerpc__
       IMAGE_FILE_MACHINE_POWERPC, /* Machine */
 #elif defined __arm__
diff --git a/dlls/kernel32/tests/module.c b/dlls/kernel32/tests/module.c
index 3e077f38a9..aba228ff05 100644
--- a/dlls/kernel32/tests/module.c
+++ b/dlls/kernel32/tests/module.c
@@ -60,6 +60,8 @@ static const struct
             IMAGE_FILE_MACHINE_I386, /* Machine */
 #elif defined __x86_64__
             IMAGE_FILE_MACHINE_AMD64, /* Machine */
+#elif defined __powerpc64__
+            IMAGE_FILE_MACHINE_POWERPC64, /* Machine */
 #elif defined __powerpc__
             IMAGE_FILE_MACHINE_POWERPC, /* Machine */
 #elif defined __arm__
diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index ed4bb94e4d..fac244546d 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -41,6 +41,7 @@ C_SRCS = \
 	signal_arm64.c \
 	signal_i386.c \
 	signal_powerpc.c \
+	signal_ppc64.c \
 	signal_x86_64.c \
 	string.c \
 	sync.c \
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index d7dbe573a4..6f5e4da929 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -211,7 +211,7 @@ static inline BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module,
 #endif /* __i386__ */
 
 
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__powerpc64__)
 /*************************************************************************
  *		stub_entry_point
  *
@@ -1964,11 +1964,15 @@ static BOOL is_valid_binary( HMODULE module, const pe_image_info_t *info )
     return info->machine == IMAGE_FILE_MACHINE_ARM ||
            info->machine == IMAGE_FILE_MACHINE_THUMB ||
            info->machine == IMAGE_FILE_MACHINE_ARMNT;
+#elif defined(__powerpc__) && !defined(__powerpc64__)
+    return info->machine == IMAGE_FILE_MACHINE_POWERPC;
 #elif defined(_WIN64)  /* support 32-bit IL-only images on 64-bit */
-#ifdef __x86_64__
+#if defined(__x86_64__)
     if (info->machine == IMAGE_FILE_MACHINE_AMD64) return TRUE;
-#else
+#elif defined(__aarch64__)
     if (info->machine == IMAGE_FILE_MACHINE_ARM64) return TRUE;
+#elif defined(__powerpc64__)
+    if (info->machine == IMAGE_FILE_MACHINE_POWERPC64) return TRUE;
 #endif
     if (!info->contains_code) return TRUE;
     if (!(info->image_flags & IMAGE_FLAGS_ComPlusNativeReady))
diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
index 0a599470c9..792c7f06e1 100644
--- a/dlls/ntdll/nt.c
+++ b/dlls/ntdll/nt.c
@@ -1136,6 +1136,14 @@ static inline void get_cpuinfo(SYSTEM_CPU_INFORMATION* info)
     }
 }
 
+#elif defined(__powerpc64__)
+
+static inline void get_cpuinfo(SYSTEM_CPU_INFORMATION* info)
+{
+    FIXME("CPU Feature detection not implemented.\n");
+    info->Architecture = PROCESSOR_ARCHITECTURE_PPC64;
+}
+
 #elif defined(__powerpc__) || defined(__ppc__)
 
 static inline void get_cpuinfo(SYSTEM_CPU_INFORMATION* info)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 649774f48a..750eb4e0cb 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -160,7 +160,7 @@
 @ stdcall NtCreateTimer(ptr long ptr long)
 @ stub NtCreateToken
 # @ stub NtCreateWaitablePort
-@ stdcall -arch=win32,arm64 NtCurrentTeb()
+@ stdcall -arch=win32,arm64,powerpc64 NtCurrentTeb()
 # @ stub NtDebugActiveProcess
 # @ stub NtDebugContinue
 @ stdcall NtDelayExecution(long ptr)
diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c
index 2ff8610cce..b1a48d0c1a 100644
--- a/dlls/ntdll/process.c
+++ b/dlls/ntdll/process.c
@@ -60,11 +60,11 @@ static ULONG execute_flags = MEM_EXECUTE_OPTION_DISABLE;
 
 static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
 
-static const char * const cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64" };
+static const char * const cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64", "PowerPC 64" };
 
 static inline BOOL is_64bit_arch( cpu_type_t cpu )
 {
-    return (cpu == CPU_x86_64 || cpu == CPU_ARM64);
+    return (cpu == CPU_x86_64 || cpu == CPU_ARM64 || cpu == CPU_POWERPC64);
 }
 
 /*
@@ -520,13 +520,13 @@ NTSTATUS WINAPI NtQueryInformationProcess(
             ULONG_PTR val = 0;
 
             if (ProcessHandle == GetCurrentProcess()) val = is_wow64;
-            else if (server_cpus & ((1 << CPU_x86_64) | (1 << CPU_ARM64)))
+            else if (server_cpus & ((1 << CPU_x86_64) | (1 << CPU_ARM64) | (1 << CPU_POWERPC64)))
             {
                 SERVER_START_REQ( get_process_info )
                 {
                     req->handle = wine_server_obj_handle( ProcessHandle );
                     if (!(ret = wine_server_call( req )))
-                        val = (reply->cpu != CPU_x86_64 && reply->cpu != CPU_ARM64);
+                        val = (reply->cpu != CPU_x86_64 && reply->cpu != CPU_ARM64 && reply->cpu != CPU_POWERPC64);
                 }
                 SERVER_END_REQ;
             }
diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c
index 094b530950..3039acb0e0 100644
--- a/dlls/ntdll/server.c
+++ b/dlls/ntdll/server.c
@@ -100,6 +100,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(server);
 static const enum cpu_type client_cpu = CPU_x86;
 #elif defined(__x86_64__)
 static const enum cpu_type client_cpu = CPU_x86_64;
+#elif defined(__powerpc64__)
+static const enum cpu_type client_cpu = CPU_POWERPC64;
 #elif defined(__powerpc__)
 static const enum cpu_type client_cpu = CPU_POWERPC;
 #elif defined(__arm__)
@@ -1475,7 +1477,7 @@ void server_init_process_done(void)
  */
 size_t server_init_thread( void *entry_point, BOOL *suspend )
 {
-    static const char *cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64" };
+    static const char *cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64", "PowerPC64" };
     static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
     const char *arch = getenv( "WINEARCH" );
     int ret;
@@ -1518,7 +1520,7 @@ size_t server_init_thread( void *entry_point, BOOL *suspend )
     }
     SERVER_END_REQ;
 
-    is_wow64 = !is_win64 && (server_cpus & ((1 << CPU_x86_64) | (1 << CPU_ARM64))) != 0;
+    is_wow64 = !is_win64 && (server_cpus & ((1 << CPU_x86_64) | (1 << CPU_ARM64) | (1 << CPU_POWERPC64))) != 0;
     ntdll_get_thread_data()->wow64_redir = is_wow64;
 
     switch (ret)
diff --git a/dlls/ntdll/signal_powerpc.c b/dlls/ntdll/signal_powerpc.c
index 86398d8f54..29114be0ff 100644
--- a/dlls/ntdll/signal_powerpc.c
+++ b/dlls/ntdll/signal_powerpc.c
@@ -18,7 +18,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#ifdef __powerpc__
+#if defined(__powerpc__) && !defined(__powerpc64__)
 
 #include "config.h"
 #include "wine/port.h"
@@ -1267,4 +1267,4 @@ TEB * WINAPI NtCurrentTeb(void)
     return pthread_getspecific( teb_key );
 }
 
-#endif  /* __powerpc__ */
+#endif  /* defined(__powerpc__) && !defined(__powerpc64__) */
diff --git a/dlls/ntdll/signal_ppc64.c b/dlls/ntdll/signal_ppc64.c
new file mode 100644
index 0000000000..345b15d83e
--- /dev/null
+++ b/dlls/ntdll/signal_ppc64.c
@@ -0,0 +1,1221 @@
+/*
+ * PowerPC signal handling routines
+ *
+ * Copyright 2002 Marcus Meissner, SuSE Linux AG
+ * Copyright 2019 Timothy Pearson <tpearson at raptorengineering.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef __powerpc64__
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <assert.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+#ifdef HAVE_SYSCALL_H
+# include <syscall.h>
+#else
+# ifdef HAVE_SYS_SYSCALL_H
+#  include <sys/syscall.h>
+# endif
+#endif
+#ifdef HAVE_SYS_SIGNAL_H
+# include <sys/signal.h>
+#endif
+#ifdef HAVE_SYS_UCONTEXT_H
+# include <sys/ucontext.h>
+#endif
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winternl.h"
+#include "wine/library.h"
+#include "wine/exception.h"
+#include "ntdll_misc.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(seh);
+WINE_DECLARE_DEBUG_CHANNEL(relay);
+
+static pthread_key_t teb_key;
+
+/***********************************************************************
+ * signal context platform-specific definitions
+ */
+#ifdef linux
+
+/* All Registers access - only for local access */
+# define REG_sig(reg_name, context)		((context)->uc_mcontext.regs->reg_name)
+
+
+/* Gpr Registers access  */
+# define GPR_sig(reg_num, context)		REG_sig(gpr[reg_num], context)
+
+# define IAR_sig(context)			REG_sig(nip, context)	/* Program counter */
+# define MSR_sig(context)			REG_sig(msr, context)   /* Machine State Register (Supervisor) */
+# define CTR_sig(context)			REG_sig(ctr, context)   /* Count register */
+
+# define XER_sig(context)			REG_sig(xer, context) /* User's integer exception register */
+# define LR_sig(context)			REG_sig(link, context) /* Link register */
+# define CR_sig(context)			REG_sig(ccr, context) /* Condition register */
+
+/* Float Registers access  */
+# define FLOAT_sig(reg_num, context)		(((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
+
+# define FPSCR_sig(context)			(*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
+
+/* Exception Registers access */
+# define DAR_sig(context)			REG_sig(dar, context)
+# define DSISR_sig(context)			REG_sig(dsisr, context)
+# define TRAP_sig(context)			REG_sig(trap, context)
+
+#endif /* linux */
+
+typedef int (*wine_signal_handler)(unsigned int sig);
+
+static wine_signal_handler handlers[256];
+
+/***********************************************************************
+ *           dispatch_signal
+ */
+static inline int dispatch_signal(unsigned int sig)
+{
+    if (handlers[sig] == NULL) return 0;
+    return handlers[sig](sig);
+}
+
+/***********************************************************************
+ *           save_context
+ *
+ * Set the register values from a sigcontext.
+ */
+static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
+{
+
+#define C(x) context->Gpr##x = GPR_sig(x,sigcontext)
+        /* Save Gpr registers */
+	C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
+	C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19); C(20);
+	C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30);
+	C(31);
+#undef C
+
+	context->Iar = IAR_sig(sigcontext);  /* Program Counter */
+	context->Msr = MSR_sig(sigcontext);  /* Machine State Register (Supervisor) */
+	context->Ctr = CTR_sig(sigcontext);
+        
+        context->Xer = XER_sig(sigcontext);
+	context->Lr  = LR_sig(sigcontext);
+	context->Cr  = CR_sig(sigcontext);
+        
+        /* Saving Exception regs */
+        context->Dar   = DAR_sig(sigcontext);
+        context->Dsisr = DSISR_sig(sigcontext);
+        context->Trap  = TRAP_sig(sigcontext);
+}
+
+
+/***********************************************************************
+ *           restore_context
+ *
+ * Build a sigcontext from the register values.
+ */
+static void restore_context( const CONTEXT *context, ucontext_t *sigcontext )
+{
+
+#define C(x)  GPR_sig(x,sigcontext) = context->Gpr##x
+	C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
+	C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19); C(20);
+	C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30);
+	C(31);
+#undef C
+
+        IAR_sig(sigcontext) = context->Iar;  /* Program Counter */
+        MSR_sig(sigcontext) = context->Msr;  /* Machine State Register (Supervisor) */
+        CTR_sig(sigcontext) = context->Ctr;
+        
+        XER_sig(sigcontext) = context->Xer;
+        LR_sig(sigcontext) = context->Lr;
+	CR_sig(sigcontext) = context->Cr;
+        
+        /* Setting Exception regs */
+        DAR_sig(sigcontext) = context->Dar;
+        DSISR_sig(sigcontext) = context->Dsisr;
+        TRAP_sig(sigcontext) = context->Trap;
+}
+
+
+/***********************************************************************
+ *           save_fpu
+ *
+ * Set the FPU context from a sigcontext.
+ */
+static inline void save_fpu( CONTEXT *context, const ucontext_t *sigcontext )
+{
+#define C(x)   context->Fpr##x = FLOAT_sig(x,sigcontext)
+        C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
+	C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19); C(20);
+	C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30);
+	C(31);
+#undef C
+        context->Fpscr = FPSCR_sig(sigcontext);
+}
+
+
+/***********************************************************************
+ *           restore_fpu
+ *
+ * Restore the FPU context to a sigcontext.
+ */
+static inline void restore_fpu( CONTEXT *context, const ucontext_t *sigcontext )
+{
+#define C(x)  FLOAT_sig(x,sigcontext) = context->Fpr##x
+        C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
+	C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19); C(20);
+	C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30);
+	C(31);
+#undef C
+        FPSCR_sig(sigcontext) = context->Fpscr;
+}
+
+
+/***********************************************************************
+ *		RtlCaptureContext (NTDLL.@)
+ */
+void WINAPI RtlCaptureContext( CONTEXT *context )
+{
+    FIXME("not implemented\n");
+    memset( context, 0, sizeof(*context) );
+}
+
+
+/***********************************************************************
+ *           set_cpu_context
+ *
+ * Set the new CPU context.
+ */
+static void set_cpu_context( const CONTEXT *context )
+{
+    FIXME("not implemented\n");
+}
+
+
+/***********************************************************************
+ *           get_server_context_flags
+ *
+ * Convert CPU-specific flags to generic server flags
+ */
+static unsigned int get_server_context_flags( DWORD flags )
+{
+    unsigned int ret = 0;
+
+    if (flags & CONTEXT_CONTROL) ret |= SERVER_CTX_CONTROL;
+    if (flags & CONTEXT_INTEGER) ret |= SERVER_CTX_INTEGER;
+    if (flags & CONTEXT_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
+    if (flags & CONTEXT_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
+    return ret;
+}
+
+
+/***********************************************************************
+ *           copy_context
+ *
+ * Copy a register context according to the flags.
+ */
+static void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
+{
+    if (flags & CONTEXT_CONTROL)
+    {
+        to->Msr   = from->Msr;
+        to->Ctr   = from->Ctr;
+        to->Iar   = from->Iar;
+        to->Lr    = from->Lr;
+        to->Dar   = from->Dar;
+        to->Dsisr = from->Dsisr;
+        to->Trap  = from->Trap;
+    }
+    if (flags & CONTEXT_INTEGER)
+    {
+        to->Gpr0  = from->Gpr0;
+        to->Gpr1  = from->Gpr1;
+        to->Gpr2  = from->Gpr2;
+        to->Gpr3  = from->Gpr3;
+        to->Gpr4  = from->Gpr4;
+        to->Gpr5  = from->Gpr5;
+        to->Gpr6  = from->Gpr6;
+        to->Gpr7  = from->Gpr7;
+        to->Gpr8  = from->Gpr8;
+        to->Gpr9  = from->Gpr9;
+        to->Gpr10 = from->Gpr10;
+        to->Gpr11 = from->Gpr11;
+        to->Gpr12 = from->Gpr12;
+        to->Gpr13 = from->Gpr13;
+        to->Gpr14 = from->Gpr14;
+        to->Gpr15 = from->Gpr15;
+        to->Gpr16 = from->Gpr16;
+        to->Gpr17 = from->Gpr17;
+        to->Gpr18 = from->Gpr18;
+        to->Gpr19 = from->Gpr19;
+        to->Gpr20 = from->Gpr20;
+        to->Gpr21 = from->Gpr21;
+        to->Gpr22 = from->Gpr22;
+        to->Gpr23 = from->Gpr23;
+        to->Gpr24 = from->Gpr24;
+        to->Gpr25 = from->Gpr25;
+        to->Gpr26 = from->Gpr26;
+        to->Gpr27 = from->Gpr27;
+        to->Gpr28 = from->Gpr28;
+        to->Gpr29 = from->Gpr29;
+        to->Gpr30 = from->Gpr30;
+        to->Gpr31 = from->Gpr31;
+        to->Xer   = from->Xer;
+        to->Cr    = from->Cr;
+    }
+    if (flags & CONTEXT_FLOATING_POINT)
+    {
+        to->Fpr0  = from->Fpr0;
+        to->Fpr1  = from->Fpr1;
+        to->Fpr2  = from->Fpr2;
+        to->Fpr3  = from->Fpr3;
+        to->Fpr4  = from->Fpr4;
+        to->Fpr5  = from->Fpr5;
+        to->Fpr6  = from->Fpr6;
+        to->Fpr7  = from->Fpr7;
+        to->Fpr8  = from->Fpr8;
+        to->Fpr9  = from->Fpr9;
+        to->Fpr10 = from->Fpr10;
+        to->Fpr11 = from->Fpr11;
+        to->Fpr12 = from->Fpr12;
+        to->Fpr13 = from->Fpr13;
+        to->Fpr14 = from->Fpr14;
+        to->Fpr15 = from->Fpr15;
+        to->Fpr16 = from->Fpr16;
+        to->Fpr17 = from->Fpr17;
+        to->Fpr18 = from->Fpr18;
+        to->Fpr19 = from->Fpr19;
+        to->Fpr20 = from->Fpr20;
+        to->Fpr21 = from->Fpr21;
+        to->Fpr22 = from->Fpr22;
+        to->Fpr23 = from->Fpr23;
+        to->Fpr24 = from->Fpr24;
+        to->Fpr25 = from->Fpr25;
+        to->Fpr26 = from->Fpr26;
+        to->Fpr27 = from->Fpr27;
+        to->Fpr28 = from->Fpr28;
+        to->Fpr29 = from->Fpr29;
+        to->Fpr30 = from->Fpr30;
+        to->Fpr31 = from->Fpr31;
+        to->Fpscr = from->Fpscr;
+    }
+}
+
+
+/***********************************************************************
+ *           context_to_server
+ *
+ * Convert a register context to the server format.
+ */
+NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
+{
+    DWORD flags = from->ContextFlags;  /* no CPU id? */
+
+    memset( to, 0, sizeof(*to) );
+    to->cpu = CPU_POWERPC64;
+
+    if (flags & CONTEXT_CONTROL)
+    {
+        to->flags |= SERVER_CTX_CONTROL;
+        to->ctl.powerpc64_regs.iar   = from->Iar;
+        to->ctl.powerpc64_regs.msr   = from->Msr;
+        to->ctl.powerpc64_regs.ctr   = from->Ctr;
+        to->ctl.powerpc64_regs.lr    = from->Lr;
+        to->ctl.powerpc64_regs.dar   = from->Dar;
+        to->ctl.powerpc64_regs.dsisr = from->Dsisr;
+        to->ctl.powerpc64_regs.trap  = from->Trap;
+    }
+    if (flags & CONTEXT_INTEGER)
+    {
+        to->flags |= SERVER_CTX_INTEGER;
+        to->integer.powerpc64_regs.gpr[0]  = from->Gpr0;
+        to->integer.powerpc64_regs.gpr[1]  = from->Gpr1;
+        to->integer.powerpc64_regs.gpr[2]  = from->Gpr2;
+        to->integer.powerpc64_regs.gpr[3]  = from->Gpr3;
+        to->integer.powerpc64_regs.gpr[4]  = from->Gpr4;
+        to->integer.powerpc64_regs.gpr[5]  = from->Gpr5;
+        to->integer.powerpc64_regs.gpr[6]  = from->Gpr6;
+        to->integer.powerpc64_regs.gpr[7]  = from->Gpr7;
+        to->integer.powerpc64_regs.gpr[8]  = from->Gpr8;
+        to->integer.powerpc64_regs.gpr[9]  = from->Gpr9;
+        to->integer.powerpc64_regs.gpr[10] = from->Gpr10;
+        to->integer.powerpc64_regs.gpr[11] = from->Gpr11;
+        to->integer.powerpc64_regs.gpr[12] = from->Gpr12;
+        to->integer.powerpc64_regs.gpr[13] = from->Gpr13;
+        to->integer.powerpc64_regs.gpr[14] = from->Gpr14;
+        to->integer.powerpc64_regs.gpr[15] = from->Gpr15;
+        to->integer.powerpc64_regs.gpr[16] = from->Gpr16;
+        to->integer.powerpc64_regs.gpr[17] = from->Gpr17;
+        to->integer.powerpc64_regs.gpr[18] = from->Gpr18;
+        to->integer.powerpc64_regs.gpr[19] = from->Gpr19;
+        to->integer.powerpc64_regs.gpr[20] = from->Gpr20;
+        to->integer.powerpc64_regs.gpr[21] = from->Gpr21;
+        to->integer.powerpc64_regs.gpr[22] = from->Gpr22;
+        to->integer.powerpc64_regs.gpr[23] = from->Gpr23;
+        to->integer.powerpc64_regs.gpr[24] = from->Gpr24;
+        to->integer.powerpc64_regs.gpr[25] = from->Gpr25;
+        to->integer.powerpc64_regs.gpr[26] = from->Gpr26;
+        to->integer.powerpc64_regs.gpr[27] = from->Gpr27;
+        to->integer.powerpc64_regs.gpr[28] = from->Gpr28;
+        to->integer.powerpc64_regs.gpr[29] = from->Gpr29;
+        to->integer.powerpc64_regs.gpr[30] = from->Gpr30;
+        to->integer.powerpc64_regs.gpr[31] = from->Gpr31;
+        to->integer.powerpc64_regs.xer     = from->Xer;
+        to->integer.powerpc64_regs.cr      = from->Cr;
+    }
+    if (flags & CONTEXT_FLOATING_POINT)
+    {
+        to->flags |= SERVER_CTX_FLOATING_POINT;
+        to->fp.powerpc64_regs.fpr[0]  = from->Fpr0;
+        to->fp.powerpc64_regs.fpr[1]  = from->Fpr1;
+        to->fp.powerpc64_regs.fpr[2]  = from->Fpr2;
+        to->fp.powerpc64_regs.fpr[3]  = from->Fpr3;
+        to->fp.powerpc64_regs.fpr[4]  = from->Fpr4;
+        to->fp.powerpc64_regs.fpr[5]  = from->Fpr5;
+        to->fp.powerpc64_regs.fpr[6]  = from->Fpr6;
+        to->fp.powerpc64_regs.fpr[7]  = from->Fpr7;
+        to->fp.powerpc64_regs.fpr[8]  = from->Fpr8;
+        to->fp.powerpc64_regs.fpr[9]  = from->Fpr9;
+        to->fp.powerpc64_regs.fpr[10] = from->Fpr10;
+        to->fp.powerpc64_regs.fpr[11] = from->Fpr11;
+        to->fp.powerpc64_regs.fpr[12] = from->Fpr12;
+        to->fp.powerpc64_regs.fpr[13] = from->Fpr13;
+        to->fp.powerpc64_regs.fpr[14] = from->Fpr14;
+        to->fp.powerpc64_regs.fpr[15] = from->Fpr15;
+        to->fp.powerpc64_regs.fpr[16] = from->Fpr16;
+        to->fp.powerpc64_regs.fpr[17] = from->Fpr17;
+        to->fp.powerpc64_regs.fpr[18] = from->Fpr18;
+        to->fp.powerpc64_regs.fpr[19] = from->Fpr19;
+        to->fp.powerpc64_regs.fpr[20] = from->Fpr20;
+        to->fp.powerpc64_regs.fpr[21] = from->Fpr21;
+        to->fp.powerpc64_regs.fpr[22] = from->Fpr22;
+        to->fp.powerpc64_regs.fpr[23] = from->Fpr23;
+        to->fp.powerpc64_regs.fpr[24] = from->Fpr24;
+        to->fp.powerpc64_regs.fpr[25] = from->Fpr25;
+        to->fp.powerpc64_regs.fpr[26] = from->Fpr26;
+        to->fp.powerpc64_regs.fpr[27] = from->Fpr27;
+        to->fp.powerpc64_regs.fpr[28] = from->Fpr28;
+        to->fp.powerpc64_regs.fpr[29] = from->Fpr29;
+        to->fp.powerpc64_regs.fpr[30] = from->Fpr30;
+        to->fp.powerpc64_regs.fpr[31] = from->Fpr31;
+        to->fp.powerpc64_regs.fpscr   = from->Fpscr;
+    }
+    return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
+ *           context_from_server
+ *
+ * Convert a register context from the server format.
+ */
+NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
+{
+    if (from->cpu != CPU_POWERPC64) return STATUS_INVALID_PARAMETER;
+
+    to->ContextFlags = 0;  /* no CPU id? */
+    if (from->flags & SERVER_CTX_CONTROL)
+    {
+        to->ContextFlags |= CONTEXT_CONTROL;
+        to->Msr   = from->ctl.powerpc64_regs.msr;
+        to->Ctr   = from->ctl.powerpc64_regs.ctr;
+        to->Iar   = from->ctl.powerpc64_regs.iar;
+        to->Lr    = from->ctl.powerpc64_regs.lr;
+        to->Dar   = from->ctl.powerpc64_regs.dar;
+        to->Dsisr = from->ctl.powerpc64_regs.dsisr;
+        to->Trap  = from->ctl.powerpc64_regs.trap;
+    }
+    if (from->flags & SERVER_CTX_INTEGER)
+    {
+        to->ContextFlags |= CONTEXT_INTEGER;
+        to->Gpr0  = from->integer.powerpc64_regs.gpr[0];
+        to->Gpr1  = from->integer.powerpc64_regs.gpr[1];
+        to->Gpr2  = from->integer.powerpc64_regs.gpr[2];
+        to->Gpr3  = from->integer.powerpc64_regs.gpr[3];
+        to->Gpr4  = from->integer.powerpc64_regs.gpr[4];
+        to->Gpr5  = from->integer.powerpc64_regs.gpr[5];
+        to->Gpr6  = from->integer.powerpc64_regs.gpr[6];
+        to->Gpr7  = from->integer.powerpc64_regs.gpr[7];
+        to->Gpr8  = from->integer.powerpc64_regs.gpr[8];
+        to->Gpr9  = from->integer.powerpc64_regs.gpr[9];
+        to->Gpr10 = from->integer.powerpc64_regs.gpr[10];
+        to->Gpr11 = from->integer.powerpc64_regs.gpr[11];
+        to->Gpr12 = from->integer.powerpc64_regs.gpr[12];
+        to->Gpr13 = from->integer.powerpc64_regs.gpr[13];
+        to->Gpr14 = from->integer.powerpc64_regs.gpr[14];
+        to->Gpr15 = from->integer.powerpc64_regs.gpr[15];
+        to->Gpr16 = from->integer.powerpc64_regs.gpr[16];
+        to->Gpr17 = from->integer.powerpc64_regs.gpr[17];
+        to->Gpr18 = from->integer.powerpc64_regs.gpr[18];
+        to->Gpr19 = from->integer.powerpc64_regs.gpr[19];
+        to->Gpr20 = from->integer.powerpc64_regs.gpr[20];
+        to->Gpr21 = from->integer.powerpc64_regs.gpr[21];
+        to->Gpr22 = from->integer.powerpc64_regs.gpr[22];
+        to->Gpr23 = from->integer.powerpc64_regs.gpr[23];
+        to->Gpr24 = from->integer.powerpc64_regs.gpr[24];
+        to->Gpr25 = from->integer.powerpc64_regs.gpr[25];
+        to->Gpr26 = from->integer.powerpc64_regs.gpr[26];
+        to->Gpr27 = from->integer.powerpc64_regs.gpr[27];
+        to->Gpr28 = from->integer.powerpc64_regs.gpr[28];
+        to->Gpr29 = from->integer.powerpc64_regs.gpr[29];
+        to->Gpr30 = from->integer.powerpc64_regs.gpr[30];
+        to->Gpr31 = from->integer.powerpc64_regs.gpr[31];
+        to->Xer   = from->integer.powerpc64_regs.xer;
+        to->Cr    = from->integer.powerpc64_regs.cr;
+    }
+    if (from->flags & SERVER_CTX_FLOATING_POINT)
+    {
+        to->ContextFlags |= CONTEXT_FLOATING_POINT;
+        to->Fpr0  = from->fp.powerpc64_regs.fpr[0];
+        to->Fpr1  = from->fp.powerpc64_regs.fpr[1];
+        to->Fpr2  = from->fp.powerpc64_regs.fpr[2];
+        to->Fpr3  = from->fp.powerpc64_regs.fpr[3];
+        to->Fpr4  = from->fp.powerpc64_regs.fpr[4];
+        to->Fpr5  = from->fp.powerpc64_regs.fpr[5];
+        to->Fpr6  = from->fp.powerpc64_regs.fpr[6];
+        to->Fpr7  = from->fp.powerpc64_regs.fpr[7];
+        to->Fpr8  = from->fp.powerpc64_regs.fpr[8];
+        to->Fpr9  = from->fp.powerpc64_regs.fpr[9];
+        to->Fpr10 = from->fp.powerpc64_regs.fpr[10];
+        to->Fpr11 = from->fp.powerpc64_regs.fpr[11];
+        to->Fpr12 = from->fp.powerpc64_regs.fpr[12];
+        to->Fpr13 = from->fp.powerpc64_regs.fpr[13];
+        to->Fpr14 = from->fp.powerpc64_regs.fpr[14];
+        to->Fpr15 = from->fp.powerpc64_regs.fpr[15];
+        to->Fpr16 = from->fp.powerpc64_regs.fpr[16];
+        to->Fpr17 = from->fp.powerpc64_regs.fpr[17];
+        to->Fpr18 = from->fp.powerpc64_regs.fpr[18];
+        to->Fpr19 = from->fp.powerpc64_regs.fpr[19];
+        to->Fpr20 = from->fp.powerpc64_regs.fpr[20];
+        to->Fpr21 = from->fp.powerpc64_regs.fpr[21];
+        to->Fpr22 = from->fp.powerpc64_regs.fpr[22];
+        to->Fpr23 = from->fp.powerpc64_regs.fpr[23];
+        to->Fpr24 = from->fp.powerpc64_regs.fpr[24];
+        to->Fpr25 = from->fp.powerpc64_regs.fpr[25];
+        to->Fpr26 = from->fp.powerpc64_regs.fpr[26];
+        to->Fpr27 = from->fp.powerpc64_regs.fpr[27];
+        to->Fpr28 = from->fp.powerpc64_regs.fpr[28];
+        to->Fpr29 = from->fp.powerpc64_regs.fpr[29];
+        to->Fpr30 = from->fp.powerpc64_regs.fpr[30];
+        to->Fpr31 = from->fp.powerpc64_regs.fpr[31];
+        to->Fpscr = from->fp.powerpc64_regs.fpscr;
+    }
+    return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
+ *              NtSetContextThread  (NTDLL.@)
+ *              ZwSetContextThread  (NTDLL.@)
+ */
+NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
+{
+    NTSTATUS ret;
+    BOOL self;
+    context_t server_context;
+
+    context_to_server( &server_context, context );
+    ret = set_thread_context( handle, &server_context, &self );
+    if (self && ret == STATUS_SUCCESS) set_cpu_context( context );
+    return ret;
+}
+
+
+/***********************************************************************
+ *              NtGetContextThread  (NTDLL.@)
+ *              ZwGetContextThread  (NTDLL.@)
+ */
+NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
+{
+    NTSTATUS ret;
+    DWORD needed_flags = context->ContextFlags;
+    BOOL self = (handle == GetCurrentThread());
+
+    if (!self)
+    {
+        context_t server_context;
+        unsigned int server_flags = get_server_context_flags( context->ContextFlags );
+
+        if ((ret = get_thread_context( handle, &server_context, server_flags, &self ))) return ret;
+        if ((ret = context_from_server( context, &server_context ))) return ret;
+        needed_flags &= ~context->ContextFlags;
+    }
+
+    if (self && needed_flags)
+    {
+        CONTEXT ctx;
+        RtlCaptureContext( &ctx );
+        copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
+        context->ContextFlags |= ctx.ContextFlags & needed_flags;
+    }
+    return STATUS_SUCCESS;
+}
+
+
+/**********************************************************************
+ *           call_stack_handlers
+ *
+ * Call the stack handlers chain.
+ */
+static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
+{
+    EXCEPTION_POINTERS ptrs;
+
+    FIXME( "not implemented on PowerPC 64\n" );
+
+    /* hack: call unhandled exception filter directly */
+    ptrs.ExceptionRecord = rec;
+    ptrs.ContextRecord = context;
+    call_unhandled_exception_filter( &ptrs );
+    return STATUS_UNHANDLED_EXCEPTION;
+}
+
+
+/*******************************************************************
+ *		raise_exception
+ *
+ * Implementation of NtRaiseException.
+ */
+static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
+{
+    NTSTATUS status;
+
+    if (first_chance)
+    {
+        DWORD c;
+
+        TRACE( "code=%x flags=%x addr=%p ip=%llx tid=%04x\n",
+               rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
+               context->Iar, GetCurrentThreadId() );
+        for (c = 0; c < rec->NumberParameters; c++)
+            TRACE( " info[%d]=%08llx\n", c, rec->ExceptionInformation[c] );
+        if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
+        {
+            if (rec->ExceptionInformation[1] >> 16)
+                MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
+                         rec->ExceptionAddress,
+                         (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
+            else
+                MESSAGE( "wine: Call from %p to unimplemented function %s.%lld, aborting\n",
+                         rec->ExceptionAddress,
+                         (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
+        }
+        else
+        {
+            /* FIXME: dump context */
+        }
+
+        status = send_debug_event( rec, TRUE, context );
+        if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
+            return STATUS_SUCCESS;
+
+        if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
+            return STATUS_SUCCESS;
+
+        if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
+            return status;
+    }
+
+    /* last chance exception */
+
+    status = send_debug_event( rec, FALSE, context );
+    if (status != DBG_CONTINUE)
+    {
+        if (rec->ExceptionFlags & EH_STACK_INVALID)
+            ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
+        else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
+            ERR("Process attempted to continue execution after noncontinuable exception.\n");
+        else
+            ERR("Unhandled exception code %x flags %x addr %p\n",
+                rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
+        NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
+    }
+    return STATUS_SUCCESS;
+}
+
+
+/**********************************************************************
+ *		segv_handler
+ *
+ * Handler for SIGSEGV and related errors.
+ */
+static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
+{
+    EXCEPTION_RECORD rec;
+    CONTEXT context;
+    NTSTATUS status;
+
+    save_context( &context, sigcontext );
+
+    rec.ExceptionRecord  = NULL;
+    rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
+    rec.ExceptionAddress = (LPVOID)context.Iar;
+    rec.NumberParameters = 0;
+
+    switch (signal)
+    {
+    case SIGSEGV:
+    	switch (siginfo->si_code & 0xffff)
+        {
+	case SEGV_MAPERR:
+	case SEGV_ACCERR:
+            rec.NumberParameters = 2;
+            rec.ExceptionInformation[0] = 0; /* FIXME ? */
+            rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr;
+            if (!(rec.ExceptionCode = virtual_handle_fault(siginfo->si_addr, rec.ExceptionInformation[0], FALSE)))
+                goto done;
+            break;
+	default:
+            FIXME("Unhandled SIGSEGV/%x\n",siginfo->si_code);
+            break;
+	}
+    	break;
+    case SIGBUS:
+    	switch (siginfo->si_code & 0xffff)
+        {
+	case BUS_ADRALN:
+            rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
+            break;
+#ifdef BUS_ADRERR
+	case BUS_ADRERR:
+#endif
+#ifdef BUS_OBJERR
+	case BUS_OBJERR:
+            /* FIXME: correct for all cases ? */
+            rec.NumberParameters = 2;
+            rec.ExceptionInformation[0] = 0; /* FIXME ? */
+            rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr;
+            if (!(rec.ExceptionCode = virtual_handle_fault(siginfo->si_addr, rec.ExceptionInformation[0], FALSE)))
+                goto done;
+            break;
+#endif
+	default:
+            FIXME("Unhandled SIGBUS/%x\n",siginfo->si_code);
+            break;
+	}
+    	break;
+    case SIGILL:
+    	switch (siginfo->si_code & 0xffff)
+        {
+	case ILL_ILLOPC: /* illegal opcode */
+#ifdef ILL_ILLOPN
+	case ILL_ILLOPN: /* illegal operand */
+#endif
+#ifdef ILL_ILLADR
+	case ILL_ILLADR: /* illegal addressing mode */
+#endif
+#ifdef ILL_ILLTRP
+	case ILL_ILLTRP: /* illegal trap */
+#endif
+#ifdef ILL_COPROC
+	case ILL_COPROC: /* coprocessor error */
+#endif
+            rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
+            break;
+	case ILL_PRVOPC: /* privileged opcode */
+#ifdef ILL_PRVREG
+	case ILL_PRVREG: /* privileged register */
+#endif
+            rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
+            break;
+#ifdef ILL_BADSTK
+	case ILL_BADSTK: /* internal stack error */
+            rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
+            break;
+#endif
+	default:
+            FIXME("Unhandled SIGILL/%x\n", siginfo->si_code);
+            break;
+	}
+    	break;
+    }
+    status = raise_exception( &rec, &context, TRUE );
+    if (status) raise_status( status, &rec );
+done:
+    restore_context( &context, sigcontext );
+}
+
+/**********************************************************************
+ *		trap_handler
+ *
+ * Handler for SIGTRAP.
+ */
+static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
+{
+    EXCEPTION_RECORD rec;
+    CONTEXT context;
+    NTSTATUS status;
+
+    save_context( &context, sigcontext );
+
+    rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
+    rec.ExceptionRecord  = NULL;
+    rec.ExceptionAddress = (LPVOID)context.Iar;
+    rec.NumberParameters = 0;
+
+    /* FIXME: check if we might need to modify PC */
+    switch (siginfo->si_code & 0xffff)
+    {
+#ifdef TRAP_BRKPT
+    case TRAP_BRKPT:
+        rec.ExceptionCode = EXCEPTION_BREAKPOINT;
+    	break;
+#endif
+#ifdef TRAP_TRACE
+    case TRAP_TRACE:
+        rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
+    	break;
+#endif
+    default:
+        FIXME("Unhandled SIGTRAP/%x\n", siginfo->si_code);
+        break;
+    }
+    status = raise_exception( &rec, &context, TRUE );
+    if (status) raise_status( status, &rec );
+    restore_context( &context, sigcontext );
+}
+
+/**********************************************************************
+ *		fpe_handler
+ *
+ * Handler for SIGFPE.
+ */
+static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
+{
+    EXCEPTION_RECORD rec;
+    CONTEXT context;
+    NTSTATUS status;
+
+    save_fpu( &context, sigcontext );
+    save_context( &context, sigcontext );
+
+    switch (siginfo->si_code & 0xffff )
+    {
+#ifdef FPE_FLTSUB
+    case FPE_FLTSUB:
+        rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
+        break;
+#endif
+#ifdef FPE_INTDIV
+    case FPE_INTDIV:
+        rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
+        break;
+#endif
+#ifdef FPE_INTOVF
+    case FPE_INTOVF:
+        rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
+        break;
+#endif
+#ifdef FPE_FLTDIV
+    case FPE_FLTDIV:
+        rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
+        break;
+#endif
+#ifdef FPE_FLTOVF
+    case FPE_FLTOVF:
+        rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
+        break;
+#endif
+#ifdef FPE_FLTUND
+    case FPE_FLTUND:
+        rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
+        break;
+#endif
+#ifdef FPE_FLTRES
+    case FPE_FLTRES:
+        rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
+        break;
+#endif
+#ifdef FPE_FLTINV
+    case FPE_FLTINV:
+#endif
+    default:
+        rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
+        break;
+    }
+    rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
+    rec.ExceptionRecord  = NULL;
+    rec.ExceptionAddress = (LPVOID)context.Iar;
+    rec.NumberParameters = 0;
+    status = raise_exception( &rec, &context, TRUE );
+    if (status) raise_status( status, &rec );
+
+    restore_context( &context, sigcontext );
+    restore_fpu( &context, sigcontext );
+}
+
+/**********************************************************************
+ *		int_handler
+ *
+ * Handler for SIGINT.
+ */
+static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
+{
+    if (!dispatch_signal(SIGINT))
+    {
+        EXCEPTION_RECORD rec;
+        CONTEXT context;
+        NTSTATUS status;
+
+        save_context( &context, sigcontext );
+        rec.ExceptionCode    = CONTROL_C_EXIT;
+        rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
+        rec.ExceptionRecord  = NULL;
+        rec.ExceptionAddress = (LPVOID)context.Iar;
+        rec.NumberParameters = 0;
+        status = raise_exception( &rec, &context, TRUE );
+        if (status) raise_status( status, &rec );
+        restore_context( &context, sigcontext );
+    }
+}
+
+
+/**********************************************************************
+ *		abrt_handler
+ *
+ * Handler for SIGABRT.
+ */
+static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
+{
+    EXCEPTION_RECORD rec;
+    CONTEXT context;
+    NTSTATUS status;
+
+    save_context( &context, sigcontext );
+    rec.ExceptionCode    = EXCEPTION_WINE_ASSERTION;
+    rec.ExceptionFlags   = EH_NONCONTINUABLE;
+    rec.ExceptionRecord  = NULL;
+    rec.ExceptionAddress = (LPVOID)context.Iar;
+    rec.NumberParameters = 0;
+    status = raise_exception( &rec, &context, TRUE );
+    if (status) raise_status( status, &rec );
+    restore_context( &context, sigcontext );
+}
+
+
+/**********************************************************************
+ *		quit_handler
+ *
+ * Handler for SIGQUIT.
+ */
+static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
+{
+    abort_thread(0);
+}
+
+
+/**********************************************************************
+ *		usr1_handler
+ *
+ * Handler for SIGUSR1, used to signal a thread that it got suspended.
+ */
+static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
+{
+    CONTEXT context;
+
+    save_context( &context, sigcontext );
+    wait_suspend( &context );
+    restore_context( &context, sigcontext );
+}
+
+
+/***********************************************************************
+ *           __wine_set_signal_handler   (NTDLL.@)
+ */
+int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
+{
+    if (sig >= ARRAY_SIZE(handlers)) return -1;
+    if (handlers[sig] != NULL) return -2;
+    handlers[sig] = wsh;
+    return 0;
+}
+
+
+/**********************************************************************
+ *		signal_alloc_thread
+ */
+NTSTATUS signal_alloc_thread( TEB **teb )
+{
+    static size_t sigstack_zero_bits;
+    SIZE_T size;
+    NTSTATUS status;
+
+    if (!sigstack_zero_bits)
+    {
+        size_t min_size = page_size;  /* this is just for the TEB, we don't use a signal stack yet */
+        /* find the first power of two not smaller than min_size */
+        while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++;
+        assert( sizeof(TEB) <= min_size );
+    }
+
+    size = 1 << sigstack_zero_bits;
+    *teb = NULL;
+    if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
+                                            &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
+    {
+        (*teb)->Tib.Self = &(*teb)->Tib;
+        (*teb)->Tib.ExceptionList = (void *)~0UL;
+    }
+    return status;
+}
+
+
+/**********************************************************************
+ *		signal_free_thread
+ */
+void signal_free_thread( TEB *teb )
+{
+    SIZE_T size = 0;
+
+    NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE );
+}
+
+
+/**********************************************************************
+ *		signal_init_thread
+ */
+void signal_init_thread( TEB *teb )
+{
+    static BOOL init_done;
+
+    if (!init_done)
+    {
+        pthread_key_create( &teb_key, NULL );
+        init_done = TRUE;
+    }
+    pthread_setspecific( teb_key, teb );
+}
+
+
+/**********************************************************************
+ *		signal_init_process
+ */
+void signal_init_process(void)
+{
+    struct sigaction sig_act;
+
+    sig_act.sa_mask = server_block_set;
+    sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
+
+    sig_act.sa_sigaction = int_handler;
+    if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
+    sig_act.sa_sigaction = fpe_handler;
+    if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
+    sig_act.sa_sigaction = abrt_handler;
+    if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
+    sig_act.sa_sigaction = quit_handler;
+    if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
+    sig_act.sa_sigaction = usr1_handler;
+    if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
+
+    sig_act.sa_sigaction = segv_handler;
+   if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
+   if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
+#ifdef SIGBUS
+    if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
+#endif
+
+#ifdef SIGTRAP
+    sig_act.sa_sigaction = trap_handler;
+    if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
+#endif
+    return;
+
+ error:
+    perror("sigaction");
+    exit(1);
+}
+
+
+/***********************************************************************
+ *            RtlUnwind  (NTDLL.@)
+ */
+void WINAPI RtlUnwind( PVOID pEndFrame, PVOID targetIp, PEXCEPTION_RECORD pRecord, PVOID retval )
+{
+    FIXME( "Not implemented on PowerPC 64\n" );
+}
+
+/*******************************************************************
+ *		NtRaiseException (NTDLL.@)
+ */
+NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
+{
+    NTSTATUS status = raise_exception( rec, context, first_chance );
+    if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
+    return status;
+}
+
+/***********************************************************************
+ *		RtlRaiseException (NTDLL.@)
+ */
+void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
+{
+    CONTEXT context;
+    NTSTATUS status;
+
+    RtlCaptureContext( &context );
+    rec->ExceptionAddress = (void *)context.Iar;
+    status = raise_exception( rec, &context, TRUE );
+    if (status) raise_status( status, rec );
+}
+
+/*************************************************************************
+ *		RtlCaptureStackBackTrace (NTDLL.@)
+ */
+USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
+{
+    FIXME( "(%d, %d, %p, %p) stub!\n", skip, count, buffer, hash );
+    return 0;
+}
+
+/***********************************************************************
+ *           call_thread_entry_point
+ */
+static void WINAPI call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
+{
+    __TRY
+    {
+        TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );
+        RtlExitUserThread( entry( arg ));
+    }
+    __EXCEPT(call_unhandled_exception_filter)
+    {
+        NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
+    }
+    __ENDTRY
+    abort();  /* should not be reached */
+}
+
+typedef void (WINAPI *thread_start_func)(LPTHREAD_START_ROUTINE,void *);
+
+struct startup_info
+{
+    thread_start_func      start;
+    LPTHREAD_START_ROUTINE entry;
+    void                  *arg;
+    BOOL                   suspend;
+};
+
+/***********************************************************************
+ *           thread_startup
+ */
+static void thread_startup( void *param )
+{
+    CONTEXT context = { 0 };
+    struct startup_info *info = param;
+
+    /* build the initial context */
+    context.ContextFlags = CONTEXT_FULL;
+    context.Gpr1 = (DWORD64)NtCurrentTeb()->Tib.StackBase;
+    context.Gpr3 = (DWORD64)info->entry;
+    context.Gpr4 = (DWORD64)info->arg;
+    context.Iar  = (DWORD64)info->start;
+
+    if (info->suspend) wait_suspend( &context );
+    LdrInitializeThunk( &context, (void **)&context.Gpr3, 0, 0 );
+
+    ((thread_start_func)context.Iar)( (LPTHREAD_START_ROUTINE)context.Gpr3, (void *)context.Gpr4 );
+}
+
+/***********************************************************************
+ *           signal_start_thread
+ *
+ * Thread startup sequence:
+ * signal_start_thread()
+ *   -> thread_startup()
+ *     -> call_thread_entry_point()
+ */
+void signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend )
+{
+    struct startup_info info = { call_thread_entry_point, entry, arg, suspend };
+    wine_switch_to_stack( thread_startup, &info, NtCurrentTeb()->Tib.StackBase );
+}
+
+/**********************************************************************
+ *		signal_start_process
+ *
+ * Process startup sequence:
+ * signal_start_process()
+ *   -> thread_startup()
+ *     -> kernel32_start_process()
+ */
+void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend )
+{
+    struct startup_info info = { kernel32_start_process, entry, NtCurrentTeb()->Peb, suspend };
+    wine_switch_to_stack( thread_startup, &info, NtCurrentTeb()->Tib.StackBase );
+}
+
+/***********************************************************************
+ *           signal_exit_thread
+ */
+void signal_exit_thread( int status )
+{
+    exit_thread( status );
+}
+
+/***********************************************************************
+ *           signal_exit_process
+ */
+void signal_exit_process( int status )
+{
+    exit( status );
+}
+
+/**********************************************************************
+ *              DbgBreakPoint   (NTDLL.@)
+ */
+void WINAPI DbgBreakPoint(void)
+{
+     kill(getpid(), SIGTRAP);
+}
+
+/**********************************************************************
+ *              DbgUserBreakPoint   (NTDLL.@)
+ */
+void WINAPI DbgUserBreakPoint(void)
+{
+     kill(getpid(), SIGTRAP);
+}
+
+/**********************************************************************
+ *           NtCurrentTeb   (NTDLL.@)
+ */
+TEB * WINAPI NtCurrentTeb(void)
+{
+    return pthread_getspecific( teb_key );
+}
+
+#endif  /* __powerpc64__ */
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 76dc6c284d..6788bb137f 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -3208,7 +3208,7 @@ void virtual_fill_image_information( const pe_image_info_t *pe_info, SECTION_IMA
     info->ImageFileSize        = pe_info->file_size;
     info->CheckSum             = pe_info->checksum;
 #ifndef _WIN64 /* don't return 64-bit values to 32-bit processes */
-    if (pe_info->machine == IMAGE_FILE_MACHINE_AMD64 || pe_info->machine == IMAGE_FILE_MACHINE_ARM64)
+    if (pe_info->machine == IMAGE_FILE_MACHINE_AMD64 || pe_info->machine == IMAGE_FILE_MACHINE_ARM64 || pe_info->machine == IMAGE_FILE_MACHINE_POWERPC64)
     {
         info->TransferAddress = (void *)0x81231234;  /* sic */
         info->MaximumStackSize = 0x100000;
diff --git a/dlls/setupapi/fakedll.c b/dlls/setupapi/fakedll.c
index e0d012a034..8c68a50346 100644
--- a/dlls/setupapi/fakedll.c
+++ b/dlls/setupapi/fakedll.c
@@ -280,6 +280,8 @@ static BOOL build_fake_dll( HANDLE file, const WCHAR *name )
     nt->FileHeader.Machine = IMAGE_FILE_MACHINE_ARM64;
 #elif defined __arm__
     nt->FileHeader.Machine = IMAGE_FILE_MACHINE_ARMNT;
+#elif defined __powerpc64__
+    nt->FileHeader.Machine = IMAGE_FILE_MACHINE_POWERPC64;
 #elif defined __powerpc__
     nt->FileHeader.Machine = IMAGE_FILE_MACHINE_POWERPC;
 #else
diff --git a/dlls/ucrtbase/ucrtbase.spec b/dlls/ucrtbase/ucrtbase.spec
index 00c806483e..6219ef265e 100644
--- a/dlls/ucrtbase/ucrtbase.spec
+++ b/dlls/ucrtbase/ucrtbase.spec
@@ -1324,7 +1324,7 @@
 @ stub _o__scalbf
 @ stub _o__searchenv
 @ stub _o__searchenv_s
-@ cdecl _o__seh_filter_dll(long ptr) __CppXcptFilter
+@ cdecl -arch=i386,x86_64,arm,arm64 _o__seh_filter_dll(long ptr) __CppXcptFilter
 @ cdecl _o__seh_filter_exe(long ptr) _XcptFilter
 @ stub _o__set_abort_behavior
 @ cdecl _o__set_app_type(long) MSVCRT___set_app_type
diff --git a/include/basetsd.h b/include/basetsd.h
index 96ea3f01bc..4972f549b5 100644
--- a/include/basetsd.h
+++ b/include/basetsd.h
@@ -277,6 +277,16 @@ typedef ULONG_PTR KAFFINITY, *PKAFFINITY;
 # undef  WORDS_BIGENDIAN
 # undef  BITFIELDS_BIGENDIAN
 # define ALLOW_UNALIGNED_ACCESS
+#elif defined(__powerpc64__)
+# if defined(__BIG_ENDIAN__)
+#  define WORDS_BIGENDIAN
+#  define BITFIELDS_BIGENDIAN
+#  undef  ALLOW_UNALIGNED_ACCESS
+# else
+#  undef  WORDS_BIGENDIAN
+#  undef  BITFIELDS_BIGENDIAN
+#  undef  ALLOW_UNALIGNED_ACCESS
+#endif
 #elif defined(__powerpc__)
 # define WORDS_BIGENDIAN
 # define BITFIELDS_BIGENDIAN
diff --git a/include/msvcrt/crtdefs.h b/include/msvcrt/crtdefs.h
index 0c0b08748e..cfc0122719 100644
--- a/include/msvcrt/crtdefs.h
+++ b/include/msvcrt/crtdefs.h
@@ -64,6 +64,9 @@
 #   define __stdcall __attribute__((pcs("aapcs-vfp")))
 # elif defined(__aarch64__) && defined (__GNUC__)
 #  define __stdcall __attribute__((ms_abi))
+# elif defined(__powerpc64__) && defined (__GNUC__)
+   /* ppc64 relies on long calls being generated for thunks (r2 save / restore) */
+#  define __stdcall __attribute__((__longcall__))
 # else  /* __i386__ */
 #  define __stdcall
 # endif  /* __i386__ */
@@ -86,6 +89,9 @@
 #   define __cdecl __attribute__((pcs("aapcs-vfp")))
 # elif defined(__aarch64__) && defined (__GNUC__)
 #  define __cdecl __attribute__((ms_abi))
+# elif defined(__powerpc64__) && defined (__GNUC__)
+   /* ppc64 relies on long calls being generated for thunks (r2 save / restore) */
+#  define __cdecl __attribute__((__longcall__))
 # elif !defined(_MSC_VER)
 #  define __cdecl
 # endif
diff --git a/include/rpc.h b/include/rpc.h
index eb7d0417bd..56b1112418 100644
--- a/include/rpc.h
+++ b/include/rpc.h
@@ -25,7 +25,9 @@
 #ifndef __WINE_RPC_H
 #define __WINE_RPC_H
 
-#if defined(__powerpc__) || defined(_MAC) /* ? */
+#if defined(__powerpc64__)
+# define __RPC_WIN64__
+#elif defined(__powerpc__) || defined(_MAC) /* ? */
 # define __RPC_MAC__
  /* Also define __RPC_WIN32__ to ensure compatibility */
 # define __RPC_WIN32__
diff --git a/include/windef.h b/include/windef.h
index ea9f32b5a0..82e9ab968c 100644
--- a/include/windef.h
+++ b/include/windef.h
@@ -80,6 +80,9 @@ extern "C" {
 #   define __stdcall __attribute__((pcs("aapcs-vfp")))
 # elif defined(__aarch64__) && defined (__GNUC__)
 #  define __stdcall __attribute__((ms_abi))
+# elif defined(__powerpc64__) && defined (__GNUC__)
+   /* ppc64 relies on long calls being generated for thunks (r2 save / restore) */
+#  define __stdcall __attribute__((__longcall__))
 # else  /* __i386__ */
 #  define __stdcall
 # endif  /* __i386__ */
@@ -102,6 +105,9 @@ extern "C" {
 #   define __cdecl __attribute__((pcs("aapcs-vfp")))
 # elif defined(__aarch64__) && defined (__GNUC__)
 #  define __cdecl __attribute__((ms_abi))
+# elif defined(__powerpc64__) && defined (__GNUC__)
+   /* ppc64 relies on long calls being generated for thunks (r2 save / restore) */
+#  define __cdecl __attribute__((__longcall__))
 # elif !defined(_MSC_VER)
 #  define __cdecl
 # endif
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 63f65cd00f..450ec9b39c 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -117,7 +117,7 @@ typedef union
 
 enum cpu_type
 {
-    CPU_x86, CPU_x86_64, CPU_POWERPC, CPU_ARM, CPU_ARM64
+    CPU_x86, CPU_x86_64, CPU_POWERPC, CPU_ARM, CPU_ARM64, CPU_POWERPC64
 };
 typedef int cpu_type_t;
 
@@ -132,6 +132,7 @@ typedef struct
         struct { unsigned __int64 rip, rbp, rsp;
                  unsigned int cs, ss, flags, __pad; } x86_64_regs;
         struct { unsigned int iar, msr, ctr, lr, dar, dsisr, trap, __pad; } powerpc_regs;
+        struct { unsigned __int64 iar, msr, ctr, lr, dar, dsisr, trap, __pad; } powerpc64_regs;
         struct { unsigned int sp, lr, pc, cpsr; } arm_regs;
         struct { unsigned __int64 sp, pc, pstate; } arm64_regs;
     } ctl;
@@ -141,6 +142,7 @@ typedef struct
         struct { unsigned __int64 rax,rbx, rcx, rdx, rsi, rdi,
                                   r8, r9, r10, r11, r12, r13, r14, r15; } x86_64_regs;
         struct { unsigned int gpr[32], cr, xer; } powerpc_regs;
+        struct { unsigned __int64 gpr[32], cr, xer; } powerpc64_regs;
         struct { unsigned int r[13]; } arm_regs;
         struct { unsigned __int64 x[31]; } arm64_regs;
     } integer;
@@ -155,6 +157,7 @@ typedef struct
                  unsigned char regs[80]; } i386_regs;
         struct { struct { unsigned __int64 low, high; } fpregs[32]; } x86_64_regs;
         struct { double fpr[32], fpscr; } powerpc_regs;
+        struct { double fpr[32], fpscr; } powerpc64_regs;
         struct { unsigned __int64 d[32]; unsigned int fpscr; } arm_regs;
         struct { unsigned __int64 d[64]; unsigned int fpcr, fpsr; } arm64_regs;
     } fp;
@@ -163,6 +166,7 @@ typedef struct
         struct { unsigned int dr0, dr1, dr2, dr3, dr6, dr7; } i386_regs;
         struct { unsigned __int64 dr0, dr1, dr2, dr3, dr6, dr7; } x86_64_regs;
         struct { unsigned int dr[8]; } powerpc_regs;
+        struct { unsigned __int64 dr[8]; } powerpc64_regs;
         struct { unsigned int bvr[8], bcr[8], wvr[1], wcr[1]; } arm_regs;
         struct { unsigned __int64 bvr[8], wvr[2]; unsigned int bcr[8], wcr[2]; } arm64_regs;
     } debug;
diff --git a/include/winnt.h b/include/winnt.h
index 5694ad7c01..74a55cb5b5 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -2,6 +2,7 @@
  * Win32 definitions for Windows NT
  *
  * Copyright 1996 Alexandre Julliard
+ * Copyright 2019 Timothy Pearson <tpearson at raptorengineering.com> (PowerPC 64)
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -655,6 +656,7 @@ typedef DWORD FLONG;
 #define PROCESSOR_ARCHITECTURE_ARM64            12
 #define PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64   13
 #define PROCESSOR_ARCHITECTURE_IA32_ON_ARM64    14
+#define PROCESSOR_ARCHITECTURE_PPC64		15
 #define PROCESSOR_ARCHITECTURE_UNKNOWN	0xFFFF
 
 /* dwProcessorType */
@@ -672,6 +674,7 @@ typedef DWORD FLONG;
 #define PROCESSOR_PPC_603        603
 #define PROCESSOR_PPC_604        604
 #define PROCESSOR_PPC_620        620
+#define PROCESSOR_PPC64_OP       690
 #define PROCESSOR_HITACHI_SH3    10003
 #define PROCESSOR_HITACHI_SH3E   10004
 #define PROCESSOR_HITACHI_SH4    10005
@@ -1985,8 +1988,138 @@ typedef struct _CONTEXT
 
 #endif  /* _MIPS_ */
 
-/* PowerPC context definitions */
-#ifdef __powerpc__
+/* PowerPC 64-bit context definitions */
+#if defined(__powerpc64__)
+
+#define CONTEXT_CONTROL         0x0001
+#define CONTEXT_FLOATING_POINT  0x0002
+#define CONTEXT_INTEGER         0x0004
+#define CONTEXT_DEBUG_REGISTERS 0x0008
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER)
+#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | \
+        CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS)
+
+#define EXCEPTION_READ_FAULT    0
+#define EXCEPTION_WRITE_FAULT   1
+#define EXCEPTION_EXECUTE_FAULT 8
+
+typedef struct
+{
+    /* These are selected by CONTEXT_FLOATING_POINT */
+    double Fpr0;
+    double Fpr1;
+    double Fpr2;
+    double Fpr3;
+    double Fpr4;
+    double Fpr5;
+    double Fpr6;
+    double Fpr7;
+    double Fpr8;
+    double Fpr9;
+    double Fpr10;
+    double Fpr11;
+    double Fpr12;
+    double Fpr13;
+    double Fpr14;
+    double Fpr15;
+    double Fpr16;
+    double Fpr17;
+    double Fpr18;
+    double Fpr19;
+    double Fpr20;
+    double Fpr21;
+    double Fpr22;
+    double Fpr23;
+    double Fpr24;
+    double Fpr25;
+    double Fpr26;
+    double Fpr27;
+    double Fpr28;
+    double Fpr29;
+    double Fpr30;
+    double Fpr31;
+    double Fpscr;
+
+    /* These are selected by CONTEXT_INTEGER */
+    DWORD64 Gpr0;
+    DWORD64 Gpr1;
+    DWORD64 Gpr2;
+    DWORD64 Gpr3;
+    DWORD64 Gpr4;
+    DWORD64 Gpr5;
+    DWORD64 Gpr6;
+    DWORD64 Gpr7;
+    DWORD64 Gpr8;
+    DWORD64 Gpr9;
+    DWORD64 Gpr10;
+    DWORD64 Gpr11;
+    DWORD64 Gpr12;
+    DWORD64 Gpr13;
+    DWORD64 Gpr14;
+    DWORD64 Gpr15;
+    DWORD64 Gpr16;
+    DWORD64 Gpr17;
+    DWORD64 Gpr18;
+    DWORD64 Gpr19;
+    DWORD64 Gpr20;
+    DWORD64 Gpr21;
+    DWORD64 Gpr22;
+    DWORD64 Gpr23;
+    DWORD64 Gpr24;
+    DWORD64 Gpr25;
+    DWORD64 Gpr26;
+    DWORD64 Gpr27;
+    DWORD64 Gpr28;
+    DWORD64 Gpr29;
+    DWORD64 Gpr30;
+    DWORD64 Gpr31;
+
+    DWORD64 Cr;
+    DWORD64 Xer;
+
+    /* These are selected by CONTEXT_CONTROL */
+    DWORD64 Msr;
+    DWORD64 Iar; /* Instruction Address Register , aka PC ... */
+    DWORD64 Lr;
+    DWORD64 Ctr;
+
+    DWORD64 ContextFlags;
+
+    DWORD64 Dar;   /* Fault registers for coredump */
+    DWORD64 Dsisr;
+    DWORD64 Trap;  /* number of powerpc exception taken */
+
+    /* These are selected by CONTEXT_DEBUG_REGISTERS */
+    DWORD64 Dr0;
+    DWORD64 Dr1;
+    DWORD64 Dr2;
+    DWORD64 Dr3;
+    DWORD64 Dr4;
+    DWORD64 Dr5;
+    DWORD64 Dr6;
+    DWORD64 Dr7;
+} CONTEXT;
+
+typedef struct _STACK_FRAME_HEADER
+{
+    DWORD BackChain;
+    DWORD GlueSaved1;
+    DWORD GlueSaved2;
+    DWORD Reserved1;
+    DWORD Spare1;
+    DWORD Spare2;
+
+    DWORD Parameter0;
+    DWORD Parameter1;
+    DWORD Parameter2;
+    DWORD Parameter3;
+    DWORD Parameter4;
+    DWORD Parameter5;
+    DWORD Parameter6;
+    DWORD Parameter7;
+} STACK_FRAME_HEADER,*PSTACK_FRAME_HEADER;
+
+#elif defined(__powerpc__)
 
 #define CONTEXT_CONTROL         0x0001
 #define CONTEXT_FLOATING_POINT  0x0002
@@ -2729,6 +2862,7 @@ typedef struct _IMAGE_VXD_HEADER {
 #define	IMAGE_FILE_MACHINE_AM33		0x01d3
 #define	IMAGE_FILE_MACHINE_POWERPC	0x01f0
 #define	IMAGE_FILE_MACHINE_POWERPCFP	0x01f1
+#define	IMAGE_FILE_MACHINE_POWERPC64	0x01f2
 #define	IMAGE_FILE_MACHINE_IA64		0x0200
 #define	IMAGE_FILE_MACHINE_MIPS16	0x0266
 #define	IMAGE_FILE_MACHINE_ALPHA64	0x0284
diff --git a/libs/port/interlocked.c b/libs/port/interlocked.c
index efdfd2af19..6cb1b56bd5 100644
--- a/libs/port/interlocked.c
+++ b/libs/port/interlocked.c
@@ -180,7 +180,7 @@ __ASM_GLOBAL_FUNC(interlocked_cmpxchg128,
                   __ASM_CFI(".cfi_same_value %rbx\n\t")
                   "ret")
 
-#elif defined(__powerpc__)
+#elif defined(__powerpc__) && !defined(__powerpc64__)
 
 #if !(defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) && __SIZEOF_POINTER__ == 4) \
  && !(defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) && __SIZEOF_POINTER__ == 8)
diff --git a/libs/wine/port.c b/libs/wine/port.c
index 29e9091789..702225b110 100644
--- a/libs/wine/port.c
+++ b/libs/wine/port.c
@@ -2,6 +2,7 @@
  * Wine portability routines
  *
  * Copyright 2000 Alexandre Julliard
+ * Copyright 2019 Timothy Pearson <tpearson at raptorengineering.com> (PowerPC 64)
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -147,6 +148,24 @@ __ASM_GLOBAL_FUNC( wine_call_on_stack,
                    __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
                    __ASM_CFI(".cfi_same_value %rbp\n\t")
                    "ret")
+#elif defined(__powerpc64__) && defined(__GNUC__)
+__ASM_GLOBAL_FUNC( wine_call_on_stack,
+                   "mflr 0\n\t"           /* get return address */
+                   "std 0, 16(1)\n\t"     /* save return address on stack */
+                   "subi 5, 5, 112\n\t"   /* reserve space on new stack */
+                   "std 1, 48(5)\n\t"     /* store old sp */
+                   "mr 12, 3\n\t"         /* func -> r12: ppc64 v2 requires r12 == ctr before bctr for TOC setup */
+                   "mtctr 12\n\t"         /* func -> ctr */
+                   "mr 3, 4\n\t"          /* args -> function param 1 (r3) */
+                   "mr 1, 5\n\t"          /* stack */
+                   "li 0, 0\n\t"          /* zero */
+                   "std 0, 0(1)\n\t"      /* bottom of stack */
+                   "stdu 1, -112(1)\n\t"  /* create a frame for this function */
+                   "bctrl\n\t"            /* call ctr */
+                   "ld 1, 160(1)\n\t"     /* fetch old sp */
+                   "ld 0, 16(1)\n\t"      /* fetch return address */
+                   "mtlr 0\n\t"           /* return address -> lr */
+                   "blr")                 /* return */
 #elif defined(__powerpc__) && defined(__GNUC__)
 __ASM_GLOBAL_FUNC( wine_call_on_stack,
                    "mflr 0\n\t"         /* get return address */
diff --git a/programs/winedbg/Makefile.in b/programs/winedbg/Makefile.in
index 22c4cd23e8..6bd4a2c2a6 100644
--- a/programs/winedbg/Makefile.in
+++ b/programs/winedbg/Makefile.in
@@ -9,6 +9,7 @@ C_SRCS = \
 	be_arm64.c \
 	be_i386.c \
 	be_ppc.c \
+	be_ppc64.c \
 	be_x86_64.c \
 	break.c \
 	crashdlg.c \
diff --git a/programs/winedbg/be_ppc.c b/programs/winedbg/be_ppc.c
index ff6ece6df3..ff264ed83e 100644
--- a/programs/winedbg/be_ppc.c
+++ b/programs/winedbg/be_ppc.c
@@ -21,7 +21,7 @@
 
 #include "debugger.h"
 
-#if defined(__powerpc__)
+#if defined(__powerpc__) && !defined(__powerpc64__)
 
 static BOOL be_ppc_get_addr(HANDLE hThread, const dbg_ctx_t *ctx,
                             enum be_cpu_addr bca, ADDRESS64* addr)
diff --git a/programs/winedbg/be_ppc64.c b/programs/winedbg/be_ppc64.c
new file mode 100644
index 0000000000..c342df9f78
--- /dev/null
+++ b/programs/winedbg/be_ppc64.c
@@ -0,0 +1,303 @@
+/*
+ * Debugger Power PC specific functions
+ *
+ * Copyright 2000-2003 Marcus Meissner
+ *                2004 Eric Pouech
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "debugger.h"
+
+#if defined(__powerpc64__)
+
+static BOOL be_ppc_get_addr(HANDLE hThread, const dbg_ctx_t *ctx,
+                            enum be_cpu_addr bca, ADDRESS64* addr)
+{
+    switch (bca)
+    {
+    case be_cpu_addr_pc:
+        return be_cpu_build_addr(hThread, ctx, addr, 0, ctx->ctx.Iar);
+    default:
+    case be_cpu_addr_stack:
+    case be_cpu_addr_frame:
+        dbg_printf("not done\n");
+    }
+    return FALSE;
+}
+
+static BOOL be_ppc_get_register_info(int regno, enum be_cpu_addr* kind)
+{
+    dbg_printf("not done\n");
+    return FALSE;
+}
+
+static void be_ppc_single_step(dbg_ctx_t *ctx, BOOL enable)
+{
+#ifndef MSR_SE
+# define MSR_SE (1<<10)
+#endif 
+    if (enable) ctx->ctx.Msr |= MSR_SE;
+    else ctx->ctx.Msr &= ~MSR_SE;
+}
+
+static void be_ppc_print_context(HANDLE hThread, const dbg_ctx_t *ctx, int all_regs)
+{
+    dbg_printf("Context printing for PPC not done yet\n");
+}
+
+static void be_ppc_print_segment_info(HANDLE hThread, const dbg_ctx_t *ctx)
+{
+}
+
+static struct dbg_internal_var be_ppc_ctx[] =
+{
+    {0,                 NULL,           0,                                      dbg_itype_none}
+};
+
+static BOOL be_ppc_is_step_over_insn(const void* insn)
+{
+    dbg_printf("not done\n");
+    return FALSE;
+}
+
+static BOOL be_ppc_is_function_return(const void* insn)
+{
+    dbg_printf("not done\n");
+    return FALSE;
+}
+
+static BOOL be_ppc_is_break_insn(const void* insn)
+{
+    dbg_printf("not done\n");
+    return FALSE;
+}
+
+static BOOL be_ppc_is_func_call(const void* insn, ADDRESS64* callee)
+{
+    return FALSE;
+}
+
+static BOOL be_ppc_is_jump(const void* insn, ADDRESS64* jumpee)
+{
+    return FALSE;
+}
+
+static void be_ppc_disasm_one_insn(ADDRESS64* addr, int display)
+
+{
+    dbg_printf("Disasm NIY\n");
+}
+
+static BOOL be_ppc_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
+                                 dbg_ctx_t *ctx, enum be_xpoint_type type,
+                                 void* addr, unsigned long* val, unsigned size)
+{
+    unsigned long       xbp;
+    SIZE_T              sz;
+
+    switch (type)
+    {
+    case be_xpoint_break:
+        if (!size) return FALSE;
+        if (!pio->read(hProcess, addr, val, 4, &sz) || sz != 4) return FALSE;
+        xbp = 0x7d821008; /* 7d 82 10 08 ... in big endian */
+        if (!pio->write(hProcess, addr, &xbp, 4, &sz) || sz != 4) return FALSE;
+        break;
+    default:
+        dbg_printf("Unknown/unsupported bp type %c\n", type);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static BOOL be_ppc_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
+                                 dbg_ctx_t *ctx, enum be_xpoint_type type,
+                                 void* addr, unsigned long val, unsigned size)
+{
+    SIZE_T              sz;
+
+    switch (type)
+    {
+    case be_xpoint_break:
+        if (!size) return FALSE;
+        if (!pio->write(hProcess, addr, &val, 4, &sz) || sz == 4) return FALSE;
+        break;
+    default:
+        dbg_printf("Unknown/unsupported bp type %c\n", type);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static BOOL be_ppc_is_watchpoint_set(const dbg_ctx_t *ctx, unsigned idx)
+{
+    dbg_printf("not done\n");
+    return FALSE;
+}
+
+static void be_ppc_clear_watchpoint(dbg_ctx_t *ctx, unsigned idx)
+{
+    dbg_printf("not done\n");
+}
+
+static int be_ppc_adjust_pc_for_break(dbg_ctx_t *ctx, BOOL way)
+{
+    dbg_printf("not done\n");
+    return 0;
+}
+
+static BOOL be_ppc_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
+                                 BOOL is_signed, LONGLONG* ret)
+{
+    dbg_printf("not done\n");
+    return FALSE;
+}
+
+static BOOL be_ppc_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
+                               long double* ret)
+{
+    dbg_printf("not done\n");
+    return FALSE;
+}
+
+static BOOL be_ppc_store_integer(const struct dbg_lvalue* lvalue, unsigned size,
+                                 BOOL is_signed, LONGLONG val)
+{
+    dbg_printf("be_ppc_store_integer: not done\n");
+    return FALSE;
+}
+
+static BOOL be_ppc_get_context(HANDLE thread, dbg_ctx_t *ctx)
+{
+    ctx->ctx.ContextFlags = CONTEXT_ALL;
+    return GetThreadContext(thread, &ctx->ctx);
+}
+
+static BOOL be_ppc_set_context(HANDLE thread, const dbg_ctx_t *ctx)
+{
+    return SetThreadContext(thread, &ctx->ctx);
+}
+
+#define REG(r,gs)  {FIELD_OFFSET(CONTEXT, r), sizeof(((CONTEXT*)NULL)->r), gs}
+
+static struct gdb_register be_ppc_gdb_register_map[] = {
+    REG(Gpr0,  4),
+    REG(Gpr1,  4),
+    REG(Gpr2,  4),
+    REG(Gpr3,  4),
+    REG(Gpr4,  4),
+    REG(Gpr5,  4),
+    REG(Gpr6,  4),
+    REG(Gpr7,  4),
+    REG(Gpr8,  4),
+    REG(Gpr9,  4),
+    REG(Gpr10, 4),
+    REG(Gpr11, 4),
+    REG(Gpr12, 4),
+    REG(Gpr13, 4),
+    REG(Gpr14, 4),
+    REG(Gpr15, 4),
+    REG(Gpr16, 4),
+    REG(Gpr17, 4),
+    REG(Gpr18, 4),
+    REG(Gpr19, 4),
+    REG(Gpr20, 4),
+    REG(Gpr21, 4),
+    REG(Gpr22, 4),
+    REG(Gpr23, 4),
+    REG(Gpr24, 4),
+    REG(Gpr25, 4),
+    REG(Gpr26, 4),
+    REG(Gpr27, 4),
+    REG(Gpr28, 4),
+    REG(Gpr29, 4),
+    REG(Gpr30, 4),
+    REG(Gpr31, 4),
+    REG(Fpr0,  4),
+    REG(Fpr1,  4),
+    REG(Fpr2,  4),
+    REG(Fpr3,  4),
+    REG(Fpr4,  4),
+    REG(Fpr5,  4),
+    REG(Fpr6,  4),
+    REG(Fpr7,  4),
+    REG(Fpr8,  4),
+    REG(Fpr9,  4),
+    REG(Fpr10, 4),
+    REG(Fpr11, 4),
+    REG(Fpr12, 4),
+    REG(Fpr13, 4),
+    REG(Fpr14, 4),
+    REG(Fpr15, 4),
+    REG(Fpr16, 4),
+    REG(Fpr17, 4),
+    REG(Fpr18, 4),
+    REG(Fpr19, 4),
+    REG(Fpr20, 4),
+    REG(Fpr21, 4),
+    REG(Fpr22, 4),
+    REG(Fpr23, 4),
+    REG(Fpr24, 4),
+    REG(Fpr25, 4),
+    REG(Fpr26, 4),
+    REG(Fpr27, 4),
+    REG(Fpr28, 4),
+    REG(Fpr29, 4),
+    REG(Fpr30, 4),
+    REG(Fpr31, 4),
+
+    REG(Iar, 4),
+    REG(Msr, 4),
+    REG(Cr, 4),
+    REG(Lr, 4),
+    REG(Ctr, 4),
+    REG(Xer, 4),
+    /* FIXME: MQ is missing? FIELD_OFFSET(CONTEXT, Mq), */
+    /* see gdb/nlm/ppc.c */
+};
+
+struct backend_cpu be_ppc64 =
+{
+    IMAGE_FILE_MACHINE_POWERPC64,
+    8,
+    be_cpu_linearize,
+    be_cpu_build_addr,
+    be_ppc_get_addr,
+    be_ppc_get_register_info,
+    be_ppc_single_step,
+    be_ppc_print_context,
+    be_ppc_print_segment_info,
+    be_ppc_ctx,
+    be_ppc_is_step_over_insn,
+    be_ppc_is_function_return,
+    be_ppc_is_break_insn,
+    be_ppc_is_func_call,
+    be_ppc_is_jump,
+    be_ppc_disasm_one_insn,
+    be_ppc_insert_Xpoint,
+    be_ppc_remove_Xpoint,
+    be_ppc_is_watchpoint_set,
+    be_ppc_clear_watchpoint,
+    be_ppc_adjust_pc_for_break,
+    be_ppc_fetch_integer,
+    be_ppc_fetch_float,
+    be_ppc_store_integer,
+    be_ppc_get_context,
+    be_ppc_set_context,
+    be_ppc_gdb_register_map,
+    ARRAY_SIZE(be_ppc_gdb_register_map),
+};
+#endif
diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c
index b7f59ee05b..8baa35b0a4 100644
--- a/programs/winedbg/gdbproxy.c
+++ b/programs/winedbg/gdbproxy.c
@@ -179,6 +179,8 @@ static unsigned char checksum(const char* ptr, int len)
 
 #ifdef __i386__
 static const char target_xml[] = "";
+#elif defined(__powerpc64__)
+static const char target_xml[] = "";
 #elif defined(__powerpc__)
 static const char target_xml[] = "";
 #elif defined(__x86_64__)
diff --git a/programs/winedbg/tgt_active.c b/programs/winedbg/tgt_active.c
index 5385d0effa..5e010a1c1c 100644
--- a/programs/winedbg/tgt_active.c
+++ b/programs/winedbg/tgt_active.c
@@ -732,6 +732,8 @@ static void output_system_info(void)
     static const char platform[] = "i386";
 #elif defined(__x86_64__)
     static const char platform[] = "x86_64";
+#elif defined(__powerpc64__)
+    static const char platform[] = "powerpc64";
 #elif defined(__powerpc__)
     static const char platform[] = "powerpc";
 #elif defined(__arm__)
diff --git a/programs/winedbg/tgt_minidump.c b/programs/winedbg/tgt_minidump.c
index 95af7a601e..295e3e2b4d 100644
--- a/programs/winedbg/tgt_minidump.c
+++ b/programs/winedbg/tgt_minidump.c
@@ -291,6 +291,9 @@ static enum dbg_start minidump_do_reload(struct tgt_process_minidump_data* data)
         case PROCESSOR_ARCHITECTURE_PPC:
             str = "PowerPC";
             break;
+        case PROCESSOR_ARCHITECTURE_PPC64:
+            str = "PowerPC 64";
+            break;
         case PROCESSOR_ARCHITECTURE_AMD64:
             str = "X86_64";
             break;
diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c
index 8634c0f73f..c4d7ccdac1 100644
--- a/programs/winedbg/winedbg.c
+++ b/programs/winedbg/winedbg.c
@@ -281,6 +281,8 @@ struct dbg_process*     dbg_get_process_h(HANDLE h)
 
 #ifdef __i386__
 extern struct backend_cpu be_i386;
+#elif defined(__powerpc64__)
+extern struct backend_cpu be_ppc64;
 #elif defined(__powerpc__)
 extern struct backend_cpu be_ppc;
 #elif defined(__x86_64__)
@@ -330,6 +332,8 @@ struct dbg_process*	dbg_add_process(const struct be_process_io* pio, DWORD pid,
 
 #ifdef __i386__
     p->be_cpu = &be_i386;
+#elif defined(__powerpc64__)
+    p->be_cpu = &be_ppc64;
 #elif defined(__powerpc__)
     p->be_cpu = &be_ppc;
 #elif defined(__x86_64__)
diff --git a/programs/winetest/main.c b/programs/winetest/main.c
index 3d6cc660ec..44a9963d17 100644
--- a/programs/winetest/main.c
+++ b/programs/winetest/main.c
@@ -343,6 +343,8 @@ static void print_version (void)
     static const char platform[] = "i386";
 #elif defined(__x86_64__)
     static const char platform[] = "x86_64";
+#elif defined(__powerpc64__)
+    static const char platform[] = "powerpc64";
 #elif defined(__powerpc__)
     static const char platform[] = "powerpc";
 #elif defined(__arm__)
diff --git a/server/mapping.c b/server/mapping.c
index 085d7aaa30..7c2d5316fe 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -2,6 +2,7 @@
  * Server-side file mapping management
  *
  * Copyright (C) 1999 Alexandre Julliard
+ * Copyright 2019 Timothy Pearson <tpearson at raptorengineering.com> (PowerPC 64)
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -619,7 +620,7 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
             return STATUS_INVALID_IMAGE_FORMAT;
         case IMAGE_FILE_MACHINE_POWERPC:
             mapping->image.cpu = CPU_POWERPC;
-            if (cpu_mask & CPU_FLAG(CPU_POWERPC)) break;
+            if (cpu_mask & (CPU_FLAG(CPU_POWERPC) | CPU_FLAG(CPU_POWERPC64))) break;
             return STATUS_INVALID_IMAGE_FORMAT;
         default:
             return STATUS_INVALID_IMAGE_FORMAT;
@@ -661,6 +662,10 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
             mapping->image.cpu = CPU_ARM64;
             if (cpu_mask & (CPU_FLAG(CPU_ARM) | CPU_FLAG(CPU_ARM64))) break;
             return STATUS_INVALID_IMAGE_FORMAT;
+        case IMAGE_FILE_MACHINE_POWERPC64:
+            mapping->image.cpu = CPU_POWERPC64;
+            if (cpu_mask & (CPU_FLAG(CPU_POWERPC) | CPU_FLAG(CPU_POWERPC64))) break;
+            return STATUS_INVALID_IMAGE_FORMAT;
         default:
             return STATUS_INVALID_IMAGE_FORMAT;
         }
@@ -726,6 +731,7 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
             mapping->image.image_flags |= IMAGE_FLAGS_ComPlusNativeReady;
             if (cpu_mask & CPU_FLAG(CPU_x86_64)) mapping->image.cpu = CPU_x86_64;
             else if (cpu_mask & CPU_FLAG(CPU_ARM64)) mapping->image.cpu = CPU_ARM64;
+            else if (cpu_mask & CPU_FLAG(CPU_POWERPC64)) mapping->image.cpu = CPU_POWERPC64;
         }
     }
 
diff --git a/server/process.h b/server/process.h
index 4566a04b48..b65c36d0e8 100644
--- a/server/process.h
+++ b/server/process.h
@@ -108,7 +108,7 @@ struct process_snapshot
 };
 
 #define CPU_FLAG(cpu) (1 << (cpu))
-#define CPU_64BIT_MASK (CPU_FLAG(CPU_x86_64) | CPU_FLAG(CPU_ARM64))
+#define CPU_64BIT_MASK (CPU_FLAG(CPU_x86_64) | CPU_FLAG(CPU_ARM64) | CPU_FLAG(CPU_POWERPC64))
 
 /* process functions */
 
diff --git a/server/protocol.def b/server/protocol.def
index e65b984a44..0fa5513285 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -133,7 +133,7 @@ typedef union
 /* supported CPU types */
 enum cpu_type
 {
-    CPU_x86, CPU_x86_64, CPU_POWERPC, CPU_ARM, CPU_ARM64
+    CPU_x86, CPU_x86_64, CPU_POWERPC, CPU_ARM, CPU_ARM64, CPU_POWERPC64
 };
 typedef int cpu_type_t;
 
@@ -148,6 +148,7 @@ typedef struct
         struct { unsigned __int64 rip, rbp, rsp;
                  unsigned int cs, ss, flags, __pad; } x86_64_regs;
         struct { unsigned int iar, msr, ctr, lr, dar, dsisr, trap, __pad; } powerpc_regs;
+        struct { unsigned __int64 iar, msr, ctr, lr, dar, dsisr, trap, __pad; } powerpc64_regs;
         struct { unsigned int sp, lr, pc, cpsr; } arm_regs;
         struct { unsigned __int64 sp, pc, pstate; } arm64_regs;
     } ctl;  /* selected by SERVER_CTX_CONTROL */
@@ -157,6 +158,7 @@ typedef struct
         struct { unsigned __int64 rax,rbx, rcx, rdx, rsi, rdi,
                                   r8, r9, r10, r11, r12, r13, r14, r15; } x86_64_regs;
         struct { unsigned int gpr[32], cr, xer; } powerpc_regs;
+        struct { unsigned __int64 gpr[32], cr, xer; } powerpc64_regs;
         struct { unsigned int r[13]; } arm_regs;
         struct { unsigned __int64 x[31]; } arm64_regs;
     } integer;  /* selected by SERVER_CTX_INTEGER */
@@ -171,6 +173,7 @@ typedef struct
                  unsigned char regs[80]; } i386_regs;
         struct { struct { unsigned __int64 low, high; } fpregs[32]; } x86_64_regs;
         struct { double fpr[32], fpscr; } powerpc_regs;
+        struct { double fpr[32], fpscr; } powerpc64_regs;
         struct { unsigned __int64 d[32]; unsigned int fpscr; } arm_regs;
         struct { unsigned __int64 d[64]; unsigned int fpcr, fpsr; } arm64_regs;
     } fp;  /* selected by SERVER_CTX_FLOATING_POINT */
@@ -179,6 +182,7 @@ typedef struct
         struct { unsigned int dr0, dr1, dr2, dr3, dr6, dr7; } i386_regs;
         struct { unsigned __int64 dr0, dr1, dr2, dr3, dr6, dr7; } x86_64_regs;
         struct { unsigned int dr[8]; } powerpc_regs;
+        struct { unsigned __int64 dr[8]; } powerpc64_regs;
         struct { unsigned int bvr[8], bcr[8], wvr[1], wcr[1]; } arm_regs;
         struct { unsigned __int64 bvr[8], wvr[2]; unsigned int bcr[8], wcr[2]; } arm64_regs;
     } debug;  /* selected by SERVER_CTX_DEBUG_REGISTERS */
diff --git a/server/thread.c b/server/thread.c
index 4c3d9c3d16..5571036077 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -57,6 +57,8 @@
 static const unsigned int supported_cpus = CPU_FLAG(CPU_x86);
 #elif defined(__x86_64__)
 static const unsigned int supported_cpus = CPU_FLAG(CPU_x86_64) | CPU_FLAG(CPU_x86);
+#elif defined(__powerpc64__)
+static const unsigned int supported_cpus = CPU_FLAG(CPU_POWERPC64);
 #elif defined(__powerpc__)
 static const unsigned int supported_cpus = CPU_FLAG(CPU_POWERPC);
 #elif defined(__arm__)
@@ -1182,6 +1184,7 @@ static unsigned int get_context_system_regs( enum cpu_type cpu )
     case CPU_x86:     return SERVER_CTX_DEBUG_REGISTERS;
     case CPU_x86_64:  return SERVER_CTX_DEBUG_REGISTERS;
     case CPU_POWERPC: return 0;
+    case CPU_POWERPC64: return 0;
     case CPU_ARM:     return SERVER_CTX_DEBUG_REGISTERS;
     case CPU_ARM64:   return SERVER_CTX_DEBUG_REGISTERS;
     }
@@ -1210,6 +1213,9 @@ void break_thread( struct thread *thread )
     case CPU_POWERPC:
         data.exception.address = thread->context->ctl.powerpc_regs.iar;
         break;
+    case CPU_POWERPC64:
+        data.exception.address = thread->context->ctl.powerpc64_regs.iar;
+        break;
     case CPU_ARM:
         data.exception.address = thread->context->ctl.arm_regs.pc;
         break;
diff --git a/server/trace.c b/server/trace.c
index 41bbe4a516..5a9e25656d 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -137,6 +137,7 @@ static void dump_cpu_type( const char *prefix, const cpu_type_t *code )
         CASE(x86);
         CASE(x86_64);
         CASE(POWERPC);
+        CASE(POWERPC64);
         CASE(ARM);
         CASE(ARM64);
         default: fprintf( stderr, "%s%u", prefix, *code ); break;
@@ -657,6 +658,26 @@ static void dump_varargs_context( const char *prefix, data_size_t size )
             fprintf( stderr, ",fpscr=%g", ctx.fp.powerpc_regs.fpscr );
         }
         break;
+    case CPU_POWERPC64:
+        if (ctx.flags & SERVER_CTX_CONTROL)
+            fprintf( stderr, ",iar=%016x,msr=%016x,ctr=%016x,lr=%016x,dar=%016x,dsisr=%016x,trap=%016x",
+                     ctx.ctl.powerpc64_regs.iar, ctx.ctl.powerpc64_regs.msr, ctx.ctl.powerpc64_regs.ctr,
+                     ctx.ctl.powerpc64_regs.lr, ctx.ctl.powerpc64_regs.dar, ctx.ctl.powerpc64_regs.dsisr,
+                     ctx.ctl.powerpc64_regs.trap );
+        if (ctx.flags & SERVER_CTX_INTEGER)
+        {
+            for (i = 0; i < 32; i++) fprintf( stderr, ",gpr%u=%016x", i, ctx.integer.powerpc64_regs.gpr[i] );
+            fprintf( stderr, ",cr=%08x,xer=%08x",
+                     ctx.integer.powerpc64_regs.cr, ctx.integer.powerpc64_regs.xer );
+        }
+        if (ctx.flags & SERVER_CTX_DEBUG_REGISTERS)
+            for (i = 0; i < 8; i++) fprintf( stderr, ",dr%u=%016x", i, ctx.debug.powerpc64_regs.dr[i] );
+        if (ctx.flags & SERVER_CTX_FLOATING_POINT)
+        {
+            for (i = 0; i < 32; i++) fprintf( stderr, ",fpr%u=%g", i, ctx.fp.powerpc64_regs.fpr[i] );
+            fprintf( stderr, ",fpscr=%g", ctx.fp.powerpc64_regs.fpscr );
+        }
+        break;
     case CPU_ARM:
         if (ctx.flags & SERVER_CTX_CONTROL)
             fprintf( stderr, ",sp=%08x,lr=%08x,pc=%08x,cpsr=%08x",
diff --git a/tools/widl/widl.c b/tools/widl/widl.c
index 0bcf67ba73..8b44d5a70f 100644
--- a/tools/widl/widl.c
+++ b/tools/widl/widl.c
@@ -95,6 +95,8 @@ static const char version_string[] = "Wine IDL Compiler version " PACKAGE_VERSIO
 enum target_cpu target_cpu = CPU_x86;
 #elif defined(__x86_64__)
 enum target_cpu target_cpu = CPU_x86_64;
+#elif defined(__powerpc64__)
+enum target_cpu target_cpu = CPU_POWERPC64;
 #elif defined(__powerpc__)
 enum target_cpu target_cpu = CPU_POWERPC;
 #elif defined(__arm__)
@@ -286,6 +288,7 @@ static void set_target( const char *target )
         { "amd64",   CPU_x86_64 },
         { "x86_64",  CPU_x86_64 },
         { "powerpc", CPU_POWERPC },
+        { "powerpc64", CPU_POWERPC64 },
         { "arm",     CPU_ARM },
         { "armv5",   CPU_ARM },
         { "armv6",   CPU_ARM },
@@ -751,6 +754,10 @@ int main(int argc,char *argv[])
       if (pointer_size == 4) error( "Cannot build 32-bit code for this CPU\n" );
       pointer_size = 8;
       break;
+  case CPU_POWERPC64:
+      if (pointer_size == 4) error( "Cannot build 32-bit code for this CPU\n" );
+      pointer_size = 8;
+      break;
   default:
       if (pointer_size == 8) error( "Cannot build 64-bit code for this CPU\n" );
       pointer_size = 4;
diff --git a/tools/widl/widl.h b/tools/widl/widl.h
index 4f4252e3ea..bc6226c54f 100644
--- a/tools/widl/widl.h
+++ b/tools/widl/widl.h
@@ -76,7 +76,7 @@ extern int char_number;
 
 enum target_cpu
 {
-    CPU_x86, CPU_x86_64, CPU_POWERPC, CPU_ARM, CPU_ARM64, CPU_LAST = CPU_ARM64
+    CPU_x86, CPU_x86_64, CPU_POWERPC, CPU_ARM, CPU_ARM64, CPU_POWERPC64, CPU_LAST = CPU_POWERPC64
 };
 
 extern enum target_cpu target_cpu;
diff --git a/tools/widl/write_msft.c b/tools/widl/write_msft.c
index cb4f0f38dd..95c65ce2f6 100644
--- a/tools/widl/write_msft.c
+++ b/tools/widl/write_msft.c
@@ -2159,7 +2159,7 @@ static void add_union_typeinfo(msft_typelib_t *typelib, type_t *tunion)
     var_t *cur;
     msft_typeinfo_t *msft_typeinfo;
 
-    if (-1 < tunion->typelib_idx)
+    if (-1 <= tunion->typelib_idx)
         return;
 
     tunion->typelib_idx = typelib->typelib_header.nrtypeinfos;
diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h
index fbc2cd9a00..61a5b05d2f 100644
--- a/tools/winebuild/build.h
+++ b/tools/winebuild/build.h
@@ -142,7 +142,7 @@ typedef struct
 
 enum target_cpu
 {
-    CPU_x86, CPU_x86_64, CPU_POWERPC, CPU_ARM, CPU_ARM64, CPU_LAST = CPU_ARM64
+    CPU_x86, CPU_x86_64, CPU_POWERPC, CPU_ARM, CPU_ARM64, CPU_POWERPC64, CPU_LAST = CPU_POWERPC64
 };
 
 enum target_platform
@@ -180,7 +180,7 @@ struct strarray
 
 #define FLAG_CPU(cpu)  (0x01000 << (cpu))
 #define FLAG_CPU_MASK  (FLAG_CPU(CPU_LAST + 1) - FLAG_CPU(0))
-#define FLAG_CPU_WIN64 (FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM64))
+#define FLAG_CPU_WIN64 (FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM64) | FLAG_CPU(CPU_POWERPC64))
 #define FLAG_CPU_WIN32 (FLAG_CPU_MASK & ~FLAG_CPU_WIN64)
 
 #define MAX_ORDINALS  65535
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c
index 5e5866c80f..b700e8e8e0 100644
--- a/tools/winebuild/import.c
+++ b/tools/winebuild/import.c
@@ -3,6 +3,7 @@
  *
  * Copyright 2000, 2004 Alexandre Julliard
  * Copyright 2000 Eric Pouech
+ * Copyright 2019 Timothy Pearson <tpearson at raptorengineering.com> (PowerPC 64)
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -694,6 +695,20 @@ static void output_import_thunk( const char *name, const char *table, int pos )
         output( "\tmr    %s, %s\n", ppc_reg(31), ppc_reg(0) );
         output( "\tbctr\n" );
         break;
+    case CPU_POWERPC64:
+	/*
+         * The ppc64 ABI v2 expects r12 to be set to ctr before bctr for PLT-like calls.
+         * ABIv2-compatible functions attempt to rebuild the TOC pointer (r2) from r12 under this assumption.
+         */
+        output( "\tlis %s, (%s+%d)@highest\n", ppc_reg(12), table, pos );
+        output( "\tori %s, %s, (%s+%d)@higher\n", ppc_reg(12), ppc_reg(12), table, pos );
+        output( "\trldicr %s, %s, 32, 31\n", ppc_reg(12), ppc_reg(12) );
+        output( "\toris %s, %s, (%s+%d)@high\n", ppc_reg(12), ppc_reg(12), table, pos );
+        output( "\tori %s, %s, (%s+%d)@l\n", ppc_reg(12), ppc_reg(12), table, pos );
+        output( "\tld %s, 0(%s)\n", ppc_reg(12), ppc_reg(12) );
+        output( "\tmtctr %s\n", ppc_reg(12) );
+        output( "\tbctr\n" );
+        break;
     }
     output_cfi( ".cfi_endproc" );
     output_function_size( name );
@@ -1042,6 +1057,62 @@ static void output_delayed_import_thunks( const DLLSPEC *spec )
         output( "\tmtlr %s\n", ppc_reg(0));
         output( "\taddi %s, %s, %d\n", ppc_reg(1), ppc_reg(1),  48+extra_stack_storage);
 
+        /* branch to ctr register. */
+        output( "\tbctr\n");
+        break;
+    case CPU_POWERPC64:
+        /* Save all callee saved registers into a stackframe. */
+        output( "\tstdu %s, -%d(%s)\n",ppc_reg(1), 168+extra_stack_storage, ppc_reg(1));
+        output( "\tstd  %s, %d(%s)\n", ppc_reg(3),  48+extra_stack_storage, ppc_reg(1));
+        output( "\tstd  %s, %d(%s)\n", ppc_reg(4),  56+extra_stack_storage, ppc_reg(1));
+        output( "\tstd  %s, %d(%s)\n", ppc_reg(5),  64+extra_stack_storage, ppc_reg(1));
+        output( "\tstd  %s, %d(%s)\n", ppc_reg(6),  72+extra_stack_storage, ppc_reg(1));
+        output( "\tstd  %s, %d(%s)\n", ppc_reg(7),  80+extra_stack_storage, ppc_reg(1));
+        output( "\tstd  %s, %d(%s)\n", ppc_reg(8),  88+extra_stack_storage, ppc_reg(1));
+        output( "\tstd  %s, %d(%s)\n", ppc_reg(9),  96+extra_stack_storage, ppc_reg(1));
+        output( "\tstd  %s, %d(%s)\n", ppc_reg(10),104+extra_stack_storage, ppc_reg(1));
+        output( "\tstd  %s, %d(%s)\n", ppc_reg(11),112+extra_stack_storage, ppc_reg(1));
+        output( "\tstd  %s, %d(%s)\n", ppc_reg(12),120+extra_stack_storage, ppc_reg(1));
+
+        /* r0 -> r3 (arg1) */
+        output( "\tmr %s, %s\n", ppc_reg(3), ppc_reg(0));
+
+        /* save return address */
+        output( "\tmflr %s\n", ppc_reg(0));
+        output( "\tstd  %s, %d(%s)\n", ppc_reg(0), 168+16+extra_stack_storage, ppc_reg(1));
+
+        /* Call the __wine_delay_load function, arg1 is arg1. */
+        output( "\tlis %s, %s at highest\n", ppc_reg(12), asm_name("__wine_spec_delay_load") );
+        output( "\tori %s, %s, %s at higher\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_spec_delay_load") );
+        output( "\trldicr %s, %s, 32, 31\n", ppc_reg(12), ppc_reg(12) );
+        output( "\toris %s, %s, %s at high\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_spec_delay_load") );
+        output( "\tori %s, %s, %s at l\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_spec_delay_load") );
+        output( "\tmtctr %s\n", ppc_reg(12) );
+        output( "\tbctrl\n" );
+
+        /* r3 (return value) -> r12 (branch / ctr) */
+        output( "\tmr %s, %s\n", ppc_reg(12), ppc_reg(3));
+
+        /* Load return value from call into ctr register */
+        output( "\tmtctr %s\n", ppc_reg(12));
+
+        /* restore all saved registers and drop stackframe. */
+        output( "\tld  %s, %d(%s)\n", ppc_reg(3),  48+extra_stack_storage, ppc_reg(1));
+        output( "\tld  %s, %d(%s)\n", ppc_reg(4),  56+extra_stack_storage, ppc_reg(1));
+        output( "\tld  %s, %d(%s)\n", ppc_reg(5),  64+extra_stack_storage, ppc_reg(1));
+        output( "\tld  %s, %d(%s)\n", ppc_reg(6),  72+extra_stack_storage, ppc_reg(1));
+        output( "\tld  %s, %d(%s)\n", ppc_reg(7),  80+extra_stack_storage, ppc_reg(1));
+        output( "\tld  %s, %d(%s)\n", ppc_reg(8),  88+extra_stack_storage, ppc_reg(1));
+        output( "\tld  %s, %d(%s)\n", ppc_reg(9),  96+extra_stack_storage, ppc_reg(1));
+        output( "\tld  %s, %d(%s)\n", ppc_reg(10),104+extra_stack_storage, ppc_reg(1));
+        output( "\tld  %s, %d(%s)\n", ppc_reg(11),112+extra_stack_storage, ppc_reg(1));
+        /* don't restore r12!  restoring r12 here would corrupt the computed TOC post-bctr. */
+
+        /* Load return value from call into return register */
+        output( "\tld  %s,  %d(%s)\n", ppc_reg(0), 168+16+extra_stack_storage, ppc_reg(1));
+        output( "\tmtlr %s\n", ppc_reg(0));
+        output( "\tld %s, 0(%s)\n", ppc_reg(1), ppc_reg(1));
+
         /* branch to ctr register. */
         output( "\tbctr\n");
         break;
@@ -1123,6 +1194,26 @@ static void output_delayed_import_thunks( const DLLSPEC *spec )
                     break;
                 }
                 break;
+            case CPU_POWERPC64:
+                /* Set up arg1 (r0)
+                 * Clobbers r12 since ppc64 ABI v2 expects r12 == ctr at branch to ctr,
+                 * i.e. we set up r12 right after this.
+                 */
+                output( "\tlis %s, %d at highest\n", ppc_reg(12), (idx << 16) | j );
+                output( "\tori %s, %s, %d at higher\n", ppc_reg(12), ppc_reg(12), (idx << 16) | j );
+                output( "\trldicr %s, %s, 32, 31\n", ppc_reg(12), ppc_reg(12) );
+                output( "\toris %s, %s, %d at high\n", ppc_reg(12), ppc_reg(12), (idx << 16) | j );
+                output( "\tori %s, %s, %d at l\n", ppc_reg(12), ppc_reg(12), (idx << 16) | j );
+                output( "\tmr %s, %s\n", ppc_reg(0), ppc_reg(12) );
+
+                output( "\tlis %s, %s at highest\n", ppc_reg(12), asm_name("__wine_delay_load_asm") );
+                output( "\tori %s, %s, %s at higher\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_delay_load_asm") );
+                output( "\trldicr %s, %s, 32, 31\n", ppc_reg(12), ppc_reg(12) );
+                output( "\toris %s, %s, %s at high\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_delay_load_asm") );
+                output( "\tori %s, %s, %s at l\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_delay_load_asm") );
+                output( "\tmtctr %s\n", ppc_reg(12) );
+                output( "\tbctr\n" );
+                break;
             }
             output_cfi( ".cfi_endproc" );
         }
@@ -1297,6 +1388,32 @@ void output_stubs( DLLSPEC *spec )
             output( "\tadd x2, x2, #:lo12:%s\n", asm_name("__wine_spec_unimplemented_stub") );
             output( "\tblr x2\n" );
             break;
+        case CPU_POWERPC64:
+            /* Clobbers r3, r4, and r12 */
+            output( "\tlis %s, %s at highest\n", ppc_reg(3), asm_name("__wine_spec_file_name") );
+            output( "\tori %s, %s, %s at higher\n", ppc_reg(3), ppc_reg(3), asm_name("__wine_spec_file_name") );
+            output( "\trldicr %s, %s, 32, 31\n", ppc_reg(3), ppc_reg(3) );
+            output( "\toris %s, %s, %s at high\n", ppc_reg(3), ppc_reg(3), asm_name("__wine_spec_file_name") );
+            output( "\tori %s, %s, %s at l\n", ppc_reg(3), ppc_reg(3), asm_name("__wine_spec_file_name") );
+            if (exp_name)
+            {
+                output( "\tlis %s, .L%s_string at highest\n", ppc_reg(4), name );
+                output( "\tori %s, %s, .L%s_string at higher\n", ppc_reg(4), ppc_reg(4), name );
+                output( "\trldicr %s, %s, 32, 31\n", ppc_reg(4), ppc_reg(4) );
+                output( "\toris %s, %s, .L%s_string at high\n", ppc_reg(4), ppc_reg(4), name );
+                output( "\tori %s, %s, .L%s_string at l\n", ppc_reg(4), ppc_reg(4), name );
+                count++;
+            }
+            else
+            {
+                output( "\tlis %s, %u at highest\n", ppc_reg(4), odp->ordinal );
+                output( "\tori %s, %s, %u at higher\n", ppc_reg(4), ppc_reg(4), odp->ordinal );
+                output( "\trldicr %s, %s, 32, 31\n", ppc_reg(4), ppc_reg(4) );
+                output( "\toris %s, %s, %u at high\n", ppc_reg(4), ppc_reg(4), odp->ordinal );
+                output( "\tori %s, %s, %u at l\n", ppc_reg(4), ppc_reg(4), odp->ordinal );
+            }
+            output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
+            break;
         default:
             assert(0);
         }
diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c
index b2f5c959c4..406679f2c8 100644
--- a/tools/winebuild/main.c
+++ b/tools/winebuild/main.c
@@ -51,6 +51,8 @@ int unwind_tables = 0;
 enum target_cpu target_cpu = CPU_x86;
 #elif defined(__x86_64__)
 enum target_cpu target_cpu = CPU_x86_64;
+#elif defined(__powerpc64__)
+enum target_cpu target_cpu = CPU_POWERPC64;
 #elif defined(__powerpc__)
 enum target_cpu target_cpu = CPU_POWERPC;
 #elif defined(__arm__)
@@ -552,6 +554,10 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec )
     case CPU_x86_64:
         if (force_pointer_size == 4) target_cpu = CPU_x86;
         break;
+    case CPU_POWERPC64:
+        if (force_pointer_size == 4)
+            fatal_error( "Cannot build 32-bit code for this CPU\n" );
+        break;
     default:
         if (force_pointer_size == 8)
             fatal_error( "Cannot build 64-bit code for this CPU\n" );
diff --git a/tools/winebuild/parser.c b/tools/winebuild/parser.c
index ad996547a5..f59ac7302a 100644
--- a/tools/winebuild/parser.c
+++ b/tools/winebuild/parser.c
@@ -403,9 +403,9 @@ static int parse_spec_stub( ORDDEF *odp, DLLSPEC *spec )
     odp->link_name = xstrdup("");
     /* don't bother generating stubs for Winelib */
     if (odp->flags & FLAG_CPU_MASK)
-        odp->flags &= FLAG_CPU(CPU_x86) | FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM) | FLAG_CPU(CPU_ARM64);
+        odp->flags &= FLAG_CPU(CPU_x86) | FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM) | FLAG_CPU(CPU_ARM64) | FLAG_CPU(CPU_POWERPC64);
     else
-        odp->flags |= FLAG_CPU(CPU_x86) | FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM) | FLAG_CPU(CPU_ARM64);
+        odp->flags |= FLAG_CPU(CPU_x86) | FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM) | FLAG_CPU(CPU_ARM64) | FLAG_CPU(CPU_POWERPC64);
 
     return parse_spec_arguments( odp, spec, 1 );
 }
diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c
index 3552eca74f..e57552552b 100644
--- a/tools/winebuild/spec32.c
+++ b/tools/winebuild/spec32.c
@@ -32,12 +32,13 @@
 
 #include "build.h"
 
-#define IMAGE_FILE_MACHINE_UNKNOWN 0
-#define IMAGE_FILE_MACHINE_I386    0x014c
-#define IMAGE_FILE_MACHINE_POWERPC 0x01f0
-#define IMAGE_FILE_MACHINE_AMD64   0x8664
-#define IMAGE_FILE_MACHINE_ARMNT   0x01C4
-#define IMAGE_FILE_MACHINE_ARM64   0xaa64
+#define IMAGE_FILE_MACHINE_UNKNOWN   0
+#define IMAGE_FILE_MACHINE_I386      0x014c
+#define IMAGE_FILE_MACHINE_POWERPC   0x01f0
+#define IMAGE_FILE_MACHINE_POWERPC64 0x01f2
+#define IMAGE_FILE_MACHINE_AMD64     0x8664
+#define IMAGE_FILE_MACHINE_ARMNT     0x01C4
+#define IMAGE_FILE_MACHINE_ARM64     0xaa64
 
 #define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224
 #define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240
@@ -515,6 +516,7 @@ static void output_asm_constructor( const char *constructor )
             break;
         case CPU_ARM64:
         case CPU_POWERPC:
+        case CPU_POWERPC64:
             output( "\n\t.section \".init\",\"ax\"\n" );
             output( "\tbl %s\n", asm_name(constructor) );
             break;
@@ -562,6 +564,7 @@ void output_module( DLLSPEC *spec )
             break;
         case CPU_ARM64:
         case CPU_POWERPC:
+        case CPU_POWERPC64:
             output( "\n\t.section \".init\",\"ax\"\n" );
             output( "\tb 1f\n" );
             break;
@@ -582,11 +585,12 @@ void output_module( DLLSPEC *spec )
     output( "\t.long 0x4550\n" );         /* Signature */
     switch(target_cpu)
     {
-    case CPU_x86:     machine = IMAGE_FILE_MACHINE_I386; break;
-    case CPU_x86_64:  machine = IMAGE_FILE_MACHINE_AMD64; break;
-    case CPU_POWERPC: machine = IMAGE_FILE_MACHINE_POWERPC; break;
-    case CPU_ARM:     machine = IMAGE_FILE_MACHINE_ARMNT; break;
-    case CPU_ARM64:   machine = IMAGE_FILE_MACHINE_ARM64; break;
+    case CPU_x86:       machine = IMAGE_FILE_MACHINE_I386; break;
+    case CPU_x86_64:    machine = IMAGE_FILE_MACHINE_AMD64; break;
+    case CPU_POWERPC:   machine = IMAGE_FILE_MACHINE_POWERPC; break;
+    case CPU_POWERPC64: machine = IMAGE_FILE_MACHINE_POWERPC64; break;
+    case CPU_ARM:       machine = IMAGE_FILE_MACHINE_ARMNT; break;
+    case CPU_ARM64:     machine = IMAGE_FILE_MACHINE_ARM64; break;
     }
     output( "\t.short 0x%04x\n",          /* Machine */
              machine );
@@ -765,11 +769,12 @@ void output_fake_module( DLLSPEC *spec )
     put_dword( 0x4550 );                             /* Signature */
     switch(target_cpu)
     {
-    case CPU_x86:     put_word( IMAGE_FILE_MACHINE_I386 ); break;
-    case CPU_x86_64:  put_word( IMAGE_FILE_MACHINE_AMD64 ); break;
-    case CPU_POWERPC: put_word( IMAGE_FILE_MACHINE_POWERPC ); break;
-    case CPU_ARM:     put_word( IMAGE_FILE_MACHINE_ARMNT ); break;
-    case CPU_ARM64:   put_word( IMAGE_FILE_MACHINE_ARM64 ); break;
+    case CPU_x86:       put_word( IMAGE_FILE_MACHINE_I386 ); break;
+    case CPU_x86_64:    put_word( IMAGE_FILE_MACHINE_AMD64 ); break;
+    case CPU_POWERPC:   put_word( IMAGE_FILE_MACHINE_POWERPC ); break;
+    case CPU_POWERPC64: put_word( IMAGE_FILE_MACHINE_POWERPC64 ); break;
+    case CPU_ARM:       put_word( IMAGE_FILE_MACHINE_ARMNT ); break;
+    case CPU_ARM64:     put_word( IMAGE_FILE_MACHINE_ARM64 ); break;
     }
     put_word( nb_sections );                         /* NumberOfSections */
     put_dword( 0 );                                  /* TimeDateStamp */
diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c
index 78e9645411..7b068d32b0 100644
--- a/tools/winebuild/utils.c
+++ b/tools/winebuild/utils.c
@@ -62,6 +62,7 @@ static const struct
     { "amd64",   CPU_x86_64 },
     { "x86_64",  CPU_x86_64 },
     { "powerpc", CPU_POWERPC },
+    { "powerpc64", CPU_POWERPC64 },
     { "arm",     CPU_ARM },
     { "armv5",   CPU_ARM },
     { "armv6",   CPU_ARM },
@@ -410,6 +411,7 @@ struct strarray get_as_command(void)
         default:
             switch(target_cpu)
             {
+            case CPU_POWERPC64:
             case CPU_POWERPC:
                 strarray_add_one( &args, (force_pointer_size == 8) ? "-a64" : "-a32" );
                 break;
@@ -451,6 +453,13 @@ struct strarray get_ld_command(void)
         default:
             switch(target_cpu)
             {
+            case CPU_POWERPC64:
+#if defined(__BIG_ENDIAN__)
+                strarray_add( &args, "-m", (force_pointer_size == 8) ? "elf64ppc" : "elf32ppc", NULL );
+#else
+                strarray_add( &args, "-m", (force_pointer_size == 8) ? "elf64lppc" : "elf32lppc", NULL );
+#endif
+                break;
             case CPU_POWERPC:
                 strarray_add( &args, "-m", (force_pointer_size == 8) ? "elf64ppc" : "elf32ppc", NULL );
                 break;
@@ -897,6 +906,7 @@ unsigned int get_alignment(unsigned int align)
         if (target_platform != PLATFORM_APPLE) return align;
         /* fall through */
     case CPU_POWERPC:
+    case CPU_POWERPC64:
     case CPU_ARM:
     case CPU_ARM64:
         n = 0;
@@ -918,6 +928,7 @@ unsigned int get_page_size(void)
     case CPU_POWERPC:
     case CPU_ARM:
         return 0x1000;
+    case CPU_POWERPC64:
     case CPU_ARM64:
         return 0x10000;
     }
@@ -937,6 +948,7 @@ unsigned int get_ptr_size(void)
         return 4;
     case CPU_x86_64:
     case CPU_ARM64:
+    case CPU_POWERPC64:
         return 8;
     }
     /* unreached */
diff --git a/tools/winedump/minidump.c b/tools/winedump/minidump.c
index da1369cbf8..c2767033c7 100644
--- a/tools/winedump/minidump.c
+++ b/tools/winedump/minidump.c
@@ -284,6 +284,9 @@ void mdmp_dump(void)
             case PROCESSOR_ARCHITECTURE_PPC:
                 str = "PowerPC";
                 break;
+            case PROCESSOR_ARCHITECTURE_PPC64:
+                str = "PowerPC 64";
+                break;
             case PROCESSOR_ARCHITECTURE_ARM:
                 str = "ARM";
                 break;
diff --git a/tools/winedump/pe.c b/tools/winedump/pe.c
index f8689f7f33..3721db67a7 100644
--- a/tools/winedump/pe.c
+++ b/tools/winedump/pe.c
@@ -59,6 +59,7 @@ const char *get_machine_str(int mach)
     case IMAGE_FILE_MACHINE_R10000:	return "R10000";
     case IMAGE_FILE_MACHINE_ALPHA:	return "Alpha";
     case IMAGE_FILE_MACHINE_POWERPC:	return "PowerPC";
+    case IMAGE_FILE_MACHINE_POWERPC64:	return "PowerPC64";
     case IMAGE_FILE_MACHINE_AMD64:      return "AMD64";
     case IMAGE_FILE_MACHINE_IA64:       return "IA64";
     case IMAGE_FILE_MACHINE_ARM64:      return "ARM64";
diff --git a/tools/winegcc/utils.h b/tools/winegcc/utils.h
index 536fb2d2f9..e83b6b743d 100644
--- a/tools/winegcc/utils.h
+++ b/tools/winegcc/utils.h
@@ -37,7 +37,7 @@
 
 enum target_cpu
 {
-    CPU_x86, CPU_x86_64, CPU_POWERPC, CPU_ARM, CPU_ARM64
+    CPU_x86, CPU_x86_64, CPU_POWERPC, CPU_ARM, CPU_ARM64, CPU_POWERPC64
 };
 
 enum target_platform
diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c
index 54d43685df..cc5738c370 100644
--- a/tools/winegcc/winegcc.c
+++ b/tools/winegcc/winegcc.c
@@ -160,6 +160,7 @@ static const struct
     { "amd64",   CPU_x86_64 },
     { "x86_64",  CPU_x86_64 },
     { "powerpc", CPU_POWERPC },
+    { "powerpc64", CPU_POWERPC64 },
     { "arm",     CPU_ARM },
     { "armv5",   CPU_ARM },
     { "armv6",   CPU_ARM },
@@ -225,6 +226,8 @@ struct options
 static const enum target_cpu build_cpu = CPU_x86;
 #elif defined(__x86_64__)
 static const enum target_cpu build_cpu = CPU_x86_64;
+#elif defined(__powerpc64__)
+static const enum target_cpu build_cpu = CPU_POWERPC64;
 #elif defined(__powerpc__)
 static const enum target_cpu build_cpu = CPU_POWERPC;
 #elif defined(__arm__)
@@ -436,9 +439,9 @@ static int check_platform( struct options *opts, const char *file )
             if (!memcmp( header, "\177ELF", 4 ))
             {
                 if (header[4] == 2)  /* 64-bit */
-                    ret = (opts->target_cpu == CPU_x86_64 || opts->target_cpu == CPU_ARM64);
+                    ret = (opts->target_cpu == CPU_x86_64 || opts->target_cpu == CPU_ARM64 || opts->target_cpu == CPU_POWERPC64);
                 else
-                    ret = (opts->target_cpu != CPU_x86_64 && opts->target_cpu != CPU_ARM64);
+                    ret = (opts->target_cpu != CPU_x86_64 && opts->target_cpu != CPU_ARM64 && opts->target_cpu != CPU_POWERPC64);
             }
         }
         close( fd );
@@ -450,11 +453,12 @@ static const char *get_multiarch_dir( enum target_cpu cpu )
 {
    switch(cpu)
    {
-   case CPU_x86:     return "/i386-linux-gnu";
-   case CPU_x86_64:  return "/x86_64-linux-gnu";
-   case CPU_ARM:     return "/arm-linux-gnueabi";
-   case CPU_ARM64:   return "/aarch64-linux-gnu";
-   case CPU_POWERPC: return "/powerpc-linux-gnu";
+   case CPU_x86:       return "/i386-linux-gnu";
+   case CPU_x86_64:    return "/x86_64-linux-gnu";
+   case CPU_ARM:       return "/arm-linux-gnueabi";
+   case CPU_ARM64:     return "/aarch64-linux-gnu";
+   case CPU_POWERPC:   return "/powerpc-linux-gnu";
+   case CPU_POWERPC64: return "/powerpc64le-linux-gnu";
    default:
        assert(0);
        return NULL;
@@ -469,8 +473,8 @@ static char *get_lib_dir( struct options *opts )
     unsigned int i;
     size_t build_len, target_len;
 
-    bit_suffix = opts->target_cpu == CPU_x86_64 || opts->target_cpu == CPU_ARM64 ? "64" : "32";
-    other_bit_suffix = opts->target_cpu == CPU_x86_64 || opts->target_cpu == CPU_ARM64 ? "32" : "64";
+    bit_suffix = opts->target_cpu == CPU_x86_64 || opts->target_cpu == CPU_ARM64 || opts->target_cpu == CPU_POWERPC64 ? "64" : "32";
+    other_bit_suffix = opts->target_cpu == CPU_x86_64 || opts->target_cpu == CPU_ARM64 || opts->target_cpu == CPU_POWERPC64 ? "32" : "64";
     build_multiarch = get_multiarch_dir( build_cpu );
     target_multiarch = get_multiarch_dir( opts->target_cpu );
     build_len = strlen( build_multiarch );
@@ -595,7 +599,7 @@ static void compile(struct options* opts, const char* lang)
         strarray_add(comp_args, "-fPIC");
     }
 
-    if (opts->target_cpu == CPU_x86_64 || opts->target_cpu == CPU_ARM64)
+    if (opts->target_cpu == CPU_x86_64 || opts->target_cpu == CPU_ARM64 || opts->target_cpu == CPU_POWERPC64)
     {
         strarray_add(comp_args, "-DWIN64");
         strarray_add(comp_args, "-D_WIN64");
@@ -633,6 +637,7 @@ static void compile(struct options* opts, const char* lang)
         case CPU_ARM:
         case CPU_ARM64:
         case CPU_POWERPC:
+        case CPU_POWERPC64:
             strarray_add(comp_args, "-D__stdcall=");
             strarray_add(comp_args, "-D__cdecl=");
             strarray_add(comp_args, "-D_stdcall=");
@@ -659,7 +664,7 @@ static void compile(struct options* opts, const char* lang)
     strarray_add(comp_args, "-D__int8=char");
     strarray_add(comp_args, "-D__int16=short");
     strarray_add(comp_args, "-D__int32=int");
-    if (opts->target_cpu == CPU_x86_64 || opts->target_cpu == CPU_ARM64)
+    if (opts->target_cpu == CPU_x86_64 || opts->target_cpu == CPU_ARM64 || opts->target_cpu == CPU_POWERPC64)
         strarray_add(comp_args, "-D__int64=long");
     else
         strarray_add(comp_args, "-D__int64=long long");
@@ -1216,8 +1221,14 @@ static void build(struct options* opts)
             else
                 prelink = PRELINK;
         }
-        if (!try_link(opts->prefix, link_args, "-Wl,-z,max-page-size=0x1000"))
-            strarray_add(link_args, "-Wl,-z,max-page-size=0x1000");
+        if (opts->target_cpu == CPU_POWERPC64) {
+            if (!try_link(opts->prefix, link_args, "-Wl,-z,max-page-size=0x10000"))
+                strarray_add(link_args, "-Wl,-z,max-page-size=0x10000");
+        }
+        else {
+            if (!try_link(opts->prefix, link_args, "-Wl,-z,max-page-size=0x1000"))
+                strarray_add(link_args, "-Wl,-z,max-page-size=0x1000");
+        }
         break;
     }
 
@@ -1588,6 +1599,8 @@ int main(int argc, char **argv)
                             opts.target_cpu = CPU_x86;
                         else if (opts.target_cpu == CPU_ARM64)
                             opts.target_cpu = CPU_ARM;
+                        else if (opts.target_cpu == CPU_POWERPC64)
+                            opts.target_cpu = CPU_POWERPC;
                         opts.force_pointer_size = 4;
 			raw_linker_arg = 1;
                     }
@@ -1597,6 +1610,8 @@ int main(int argc, char **argv)
                             opts.target_cpu = CPU_x86_64;
                         else if (opts.target_cpu == CPU_ARM)
                             opts.target_cpu = CPU_ARM64;
+                        else if (opts.target_cpu == CPU_POWERPC)
+                            opts.target_cpu = CPU_POWERPC64;
                         opts.force_pointer_size = 8;
 			raw_linker_arg = 1;
                     }
diff --git a/tools/wrc/wrc.c b/tools/wrc/wrc.c
index ea8bfe07a7..f05d687eb0 100644
--- a/tools/wrc/wrc.c
+++ b/tools/wrc/wrc.c
@@ -317,7 +317,8 @@ static void set_target( const char *target )
     if (!(p = strchr( cpu, '-' ))) error( "Invalid target specification '%s'\n", target );
     *p = 0;
     if (!strcmp( cpu, "amd64" ) || !strcmp( cpu, "x86_64" ) ||
-        !strcmp( cpu, "ia64" ) || !strcmp( cpu, "aarch64" ))
+        !strcmp( cpu, "ia64" ) || !strcmp( cpu, "aarch64" ) ||
+        !strcmp( cpu, "ppc64" ) || strcmp( cpu, "ppc64el" )  || strcmp( cpu, "ppc64le" ))
         pointer_size = 8;
     else
         pointer_size = 4;
-- 
2.20.1




More information about the wine-devel mailing list