Wine Emulation: Swapping functions

Pierre d'Herbemont stegefin at free.fr
Tue Aug 24 11:06:50 CDT 2004


Hi Alexandre,

This patch allows to load a PE exe to memory. You may notice that there 
is no "mass" byte swapping. The technics used here is a bit developer 
here:
http://stegefin.free.fr/wine/
You might prefer a more conventional way of doing the byte swapping, in 
this case tell me. We might still need this approach since it could 
efficient for sharing data accross the LE exe and the BE winelib.

Pierre.

ChangeLog:
- Add swapping functions and support for loading an Little Endian x86 
Exe on a Big Endian Host.
-------------- next part --------------
Index: Make.rules.in
===================================================================
RCS file: /home/wine/wine/Make.rules.in,v
retrieving revision 1.174
diff -u -r1.174 Make.rules.in
--- Make.rules.in	22 Aug 2004 22:33:57 -0000	1.174
+++ Make.rules.in	24 Aug 2004 15:57:37 -0000
@@ -78,6 +78,7 @@
 LDPATH       = @LDPATH@
 DLLDIR       = $(TOPOBJDIR)/dlls
 LIBDIR       = $(TOPOBJDIR)/libs
+LIBEMU       = -L$(TOPOBJDIR)/libs/emu -lwine_emu
 LIBPORT      = -L$(TOPOBJDIR)/libs/port -lwine_port
 LIBUNICODE   = -L$(TOPOBJDIR)/libs/unicode -lwine_unicode
 LIBWINE      = -L$(TOPOBJDIR)/libs/wine -lwine
Index: configure.ac
===================================================================
RCS file: /home/wine/wine/configure.ac,v
retrieving revision 1.302
diff -u -r1.302 configure.ac
--- configure.ac	19 Aug 2004 19:31:20 -0000	1.302
+++ configure.ac	24 Aug 2004 15:57:39 -0000
@@ -1704,6 +1704,7 @@
 fonts/Makefile
 include/Makefile
 libs/Makefile
+libs/emu/Makefile
 libs/port/Makefile
 libs/unicode/Makefile
 libs/wine/Makefile
Index: dlls/kernel/module.c
===================================================================
RCS file: /home/wine/wine/dlls/kernel/module.c,v
retrieving revision 1.9
diff -u -r1.9 module.c
--- dlls/kernel/module.c	3 Jun 2004 00:25:08 -0000	1.9
+++ dlls/kernel/module.c	24 Aug 2004 15:57:39 -0000
@@ -44,6 +44,8 @@
 #include "wine/unicode.h"
 #include "wine/server.h"
 
+#include "wine/emu.h"
+
 WINE_DEFAULT_DEBUG_CHANNEL(module);
 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
 
@@ -181,7 +183,7 @@
 
     /* Not ELF, try DOS */
 
-    if (header.mz.e_magic == IMAGE_DOS_SIGNATURE)
+    if (header.mz.e_magic == swap_word_from_le(IMAGE_DOS_SIGNATURE))
     {
         union
         {
@@ -196,7 +198,7 @@
          * This will tell us if there is more header information
          * to read or not.
          */
-        if (SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) == -1)
+        if (SetFilePointer( hfile, swap_dword_from_le(header.mz.e_lfanew), NULL, SEEK_SET ) == -1)
             return BINARY_DOS;
         if (!ReadFile( hfile, &ext_header, sizeof(ext_header), &len, NULL ) || len < 4)
             return BINARY_DOS;
@@ -210,10 +212,10 @@
             {
                 if (len < sizeof(ext_header.nt))  /* clear remaining part of header if missing */
                     memset( (char *)&ext_header.nt + len, 0, sizeof(ext_header.nt) - len );
-                if (res_start) *res_start = (void *)ext_header.nt.OptionalHeader.ImageBase;
-                if (res_end) *res_end = (void *)(ext_header.nt.OptionalHeader.ImageBase +
-                                                 ext_header.nt.OptionalHeader.SizeOfImage);
-                if (ext_header.nt.FileHeader.Characteristics & IMAGE_FILE_DLL) return BINARY_PE_DLL;
+                if (res_start) *res_start = (void *)swap_dword_from_le(ext_header.nt.OptionalHeader.ImageBase);
+                if (res_end) *res_end = (void *)(swap_dword_from_le(ext_header.nt.OptionalHeader.ImageBase) +
+                                                 swap_dword_from_le(ext_header.nt.OptionalHeader.SizeOfImage));
+                if (swap_word_from_le(ext_header.nt.FileHeader.Characteristics) & IMAGE_FILE_DLL) return BINARY_PE_DLL;
                 return BINARY_PE_EXE;
             }
             return BINARY_DOS;
Index: dlls/kernel/process.c
===================================================================
RCS file: /home/wine/wine/dlls/kernel/process.c,v
retrieving revision 1.71
diff -u -r1.71 process.c
--- dlls/kernel/process.c	18 Aug 2004 21:03:32 -0000	1.71
+++ dlls/kernel/process.c	24 Aug 2004 15:57:41 -0000
@@ -43,6 +43,7 @@
 #include "wine/server.h"
 #include "wine/unicode.h"
 #include "wine/debug.h"
+#include "wine/emu.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(process);
 WINE_DECLARE_DEBUG_CHANNEL(file);
@@ -1011,6 +1012,15 @@
 
         SetLastError( 0 );  /* clear error code */
         if (peb->BeingDebugged) DbgBreakPoint();
+
+#ifdef WINE_EMU
+        if(nt->FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
+        {
+            ExitProcess(wine_emu_start(peb));
+            /* shouldn't happen but in case */
+            return;
+        }
+#endif
         ExitProcess( entry( peb ) );
     }
     __EXCEPT(UnhandledExceptionFilter)
Index: dlls/ntdll/loader.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/loader.c,v
retrieving revision 1.76
diff -u -r1.76 loader.c
--- dlls/ntdll/loader.c	2 Aug 2004 22:25:01 -0000	1.76
+++ dlls/ntdll/loader.c	24 Aug 2004 15:57:43 -0000
@@ -37,6 +37,7 @@
 #include "wine/unicode.h"
 #include "wine/debug.h"
 #include "wine/server.h"
+#include "wine/emu.h"
 #include "ntdll_misc.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(module);
@@ -1141,6 +1142,10 @@
     wm->ldr.Flags |= LDR_WINE_INTERNAL;
     NtAllocateVirtualMemory( GetCurrentProcess(), &addr, module, &nt->OptionalHeader.SizeOfImage,
                              MEM_SYSTEM | MEM_IMAGE, PAGE_EXECUTE_WRITECOPY );
+#ifdef WINE_EMU
+    if(nt->FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
+        wine_emu_auto_swap_mem(addr, nt->OptionalHeader.SizeOfImage, WINE_EMU_DEFAULT_PROT );
+#endif
 
     /* fixup imports */
 
@@ -1859,6 +1864,11 @@
     }
     wm->ldr.LoadCount = -1;  /* can't unload main exe */
 
+#ifdef WINE_EMU
+    if(nt->FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
+        wine_emu_auto_swap_mem(wm->ldr.BaseAddress, wm->ldr.SizeOfImage, WINE_EMU_DEFAULT_PROT );
+#endif
+
     /* the main exe needs to be the first in the load order list */
     RemoveEntryList( &wm->ldr.InLoadOrderModuleList );
     InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderModuleList );
@@ -2054,5 +2064,11 @@
         MESSAGE( "wine: could not find __wine_kernel_init in kernel32.dll, status %lx\n", status );
         exit(1);
     }
+    
+#ifdef WINE_EMU
+    /* Call emulation init, set up byte swapping signal handler */
+    wine_emu_init();
+#endif
+
     init_func();
 }
Index: dlls/ntdll/signal_powerpc.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/signal_powerpc.c,v
retrieving revision 1.24
diff -u -r1.24 signal_powerpc.c
--- dlls/ntdll/signal_powerpc.c	8 Dec 2003 21:58:55 -0000	1.24
+++ dlls/ntdll/signal_powerpc.c	24 Aug 2004 15:57:44 -0000
@@ -58,6 +58,7 @@
 #include "wine/exception.h"
 #include "ntdll_misc.h"
 #include "wine/debug.h"
+#include "wine/emu.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(seh);
 
@@ -484,6 +485,14 @@
 static HANDLER_DEF(segv_handler)
 {
     CONTEXT context;
+	
+#ifdef WINE_EMU
+	/* Go to the emulator as soon as we can to swap the bytes */
+	if( __siginfo->si_signo == SIGBUS && ( wine_emu_swap_access(HANDLER_CONTEXT) == 1 ) )
+		return; /* in this case it was only for the emulator, we don't
+		           want to catch the signal */
+#endif
+
     save_context( &context, HANDLER_CONTEXT );
     do_segv( &context, __siginfo->si_signo, __siginfo->si_errno, __siginfo->si_code, __siginfo->si_addr );
     restore_context( &context, HANDLER_CONTEXT );
Index: dlls/ntdll/virtual.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/virtual.c,v
retrieving revision 1.38
diff -u -r1.38 virtual.c
--- dlls/ntdll/virtual.c	18 Aug 2004 00:04:58 -0000	1.38
+++ dlls/ntdll/virtual.c	24 Aug 2004 15:57:45 -0000
@@ -48,6 +48,7 @@
 #include "wine/server.h"
 #include "wine/list.h"
 #include "wine/debug.h"
+#include "wine/emu.h"
 #include "ntdll_misc.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(virtual);
@@ -545,6 +546,11 @@
     memset( view->prot + (((char *)base - (char *)view->base) >> page_shift),
             vprot, size >> page_shift );
     VIRTUAL_DEBUG_DUMP_VIEW( view );
+
+#ifdef WINE_EMU
+	/* Just in case of emu, we need our region manager to be updated */
+	wine_emu_update_auto_swap(base, size, vprot);
+#endif
     return TRUE;
 }
 
@@ -852,6 +858,12 @@
     status = STATUS_INVALID_IMAGE_FORMAT;  /* generic error */
     if (map_file_into_view( view, fd, 0, header_size, 0, VPROT_COMMITTED | VPROT_READ,
                             removable ) != STATUS_SUCCESS) goto error;
+
+#ifdef WINE_EMU
+    /* The maped region is in fact a little-endian region, tell our endian region manager */
+    wine_emu_auto_swap_mem( ptr, header_size, PROT_READ );
+#endif
+
     dos = (IMAGE_DOS_HEADER *)ptr;
     nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew);
     if ((char *)(nt + 1) > ptr + header_size) goto error;
Index: libs/Makefile.in
===================================================================
RCS file: /home/wine/wine/libs/Makefile.in,v
retrieving revision 1.8
diff -u -r1.8 Makefile.in
--- libs/Makefile.in	1 May 2004 02:41:01 -0000	1.8
+++ libs/Makefile.in	24 Aug 2004 15:57:45 -0000
@@ -5,6 +5,7 @@
 MODULE    = none
 
 SUBDIRS = \
+	emu \
 	port \
 	unicode \
 	wine \
@@ -16,6 +17,7 @@
 
 SYMLINKS = \
 	libwine.$(LIBEXT) \
+	libwine_emu.a \
 	libwine_port.a \
 	libwine_unicode.$(LIBEXT) \
 	libwpp.a
@@ -40,6 +42,9 @@
 libwine_unicode.so libwine_unicode.so.1 libwine_unicode.dll libwine_unicode.dylib libwine_unicode.1.dylib libwine_unicode.a: unicode/libwine_unicode.$(LIBEXT)
 	$(RM) $@ && $(LN_S) unicode/$@ $@
 
+libwine_emu.a: emu/libwine_emu.a
+	$(RM) $@ && $(LN_S) port/$@ $@
+
 libwine_port.a: port/libwine_port.a
 	$(RM) $@ && $(LN_S) port/$@ $@
 
@@ -49,10 +54,11 @@
 # Directory dependencies
 
 wine/libwine.$(LIBEXT): wine
+wine/libwine_emu.a: emu
 unicode/libwine_unicode.$(LIBEXT): unicode
 port/libwine_port.a: port
 wpp/libwpp.a: wpp
 
-wine wine/__install__ wine/__install-lib__: libwine_port.a
+wine wine/__install__ wine/__install-lib__: libwine_port.a libwine_emu.a
 
 ### Dependencies:
Index: server/mapping.c
===================================================================
RCS file: /home/wine/wine/server/mapping.c,v
retrieving revision 1.47
diff -u -r1.47 mapping.c
--- server/mapping.c	1 May 2004 02:50:06 -0000	1.47
+++ server/mapping.c	24 Aug 2004 15:57:46 -0000
@@ -36,6 +36,8 @@
 #include "thread.h"
 #include "request.h"
 
+#include "wine/emu.h"
+
 struct mapping
 {
     struct object   obj;             /* object header */
@@ -202,28 +204,113 @@
     if (!(fd = mapping_get_fd( &mapping->obj ))) return 0;
     unix_fd = get_unix_fd( fd );
     if (pread( unix_fd, &dos, sizeof(dos), 0 ) != sizeof(dos)) goto error;
+	
+	/* Swap the dos header (only effective on big endian host ) */
+	self_swap_word_from_le(dos.e_magic);
+	self_swap_word_from_le(dos.e_cblp);
+	self_swap_word_from_le(dos.e_cp);
+	self_swap_word_from_le(dos.e_cparhdr);
+	self_swap_word_from_le(dos.e_minalloc);
+	self_swap_word_from_le(dos.e_maxalloc);
+	self_swap_word_from_le(dos.e_ss);
+	self_swap_word_from_le(dos.e_sp);
+	self_swap_word_from_le(dos.e_csum);
+	self_swap_word_from_le(dos.e_ip);
+	self_swap_word_from_le(dos.e_cs);
+	self_swap_word_from_le(dos.e_lfarlc);
+	self_swap_word_from_le(dos.e_ovno);
+	self_swap_word_from_le(dos.e_oemid);
+	self_swap_word_from_le(dos.e_oeminfo);
+	self_swap_dword_from_le(dos.e_lfanew);
+
+
     if (dos.e_magic != IMAGE_DOS_SIGNATURE) goto error;
     pos = dos.e_lfanew;
 
     if (pread( unix_fd, &nt.Signature, sizeof(nt.Signature), pos ) != sizeof(nt.Signature))
         goto error;
     pos += sizeof(nt.Signature);
+	
+	/* Swap the nt Signature */
+	self_swap_dword_from_le(nt.Signature);
+	
     if (nt.Signature != IMAGE_NT_SIGNATURE) goto error;
     if (pread( unix_fd, &nt.FileHeader, sizeof(nt.FileHeader), pos ) != sizeof(nt.FileHeader))
         goto error;
     pos += sizeof(nt.FileHeader);
+	
+	/* Swap the nt FileHeader */
+	self_swap_word_from_le(nt.FileHeader.Machine);
+	self_swap_word_from_le(nt.FileHeader.NumberOfSections);
+	self_swap_dword_from_le(nt.FileHeader.TimeDateStamp);
+	self_swap_dword_from_le(nt.FileHeader.PointerToSymbolTable);
+	self_swap_dword_from_le(nt.FileHeader.NumberOfSymbols);
+	self_swap_word_from_le(nt.FileHeader.SizeOfOptionalHeader);
+	self_swap_word_from_le(nt.FileHeader.Characteristics);
+	
     /* zero out Optional header in the case it's not present or partial */
     memset(&nt.OptionalHeader, 0, sizeof(nt.OptionalHeader));
     if (pread( unix_fd, &nt.OptionalHeader, nt.FileHeader.SizeOfOptionalHeader,
                pos ) != nt.FileHeader.SizeOfOptionalHeader) goto error;
     pos += nt.FileHeader.SizeOfOptionalHeader;
 
+	/* Swap the nt Optional header */
+	self_swap_word_from_le(nt.OptionalHeader.Magic);
+	self_swap_dword_from_le(nt.OptionalHeader.SizeOfCode);
+	self_swap_dword_from_le(nt.OptionalHeader.SizeOfInitializedData);
+	self_swap_dword_from_le(nt.OptionalHeader.SizeOfUninitializedData);
+	self_swap_dword_from_le(nt.OptionalHeader.AddressOfEntryPoint);
+	self_swap_dword_from_le(nt.OptionalHeader.BaseOfCode);
+	self_swap_dword_from_le(nt.OptionalHeader.BaseOfData);
+	self_swap_dword_from_le(nt.OptionalHeader.ImageBase);
+	self_swap_dword_from_le(nt.OptionalHeader.SectionAlignment);
+	self_swap_dword_from_le(nt.OptionalHeader.FileAlignment);
+	self_swap_word_from_le(nt.OptionalHeader.MajorOperatingSystemVersion);
+	self_swap_word_from_le(nt.OptionalHeader.MinorOperatingSystemVersion);
+	self_swap_word_from_le(nt.OptionalHeader.MajorImageVersion);
+	self_swap_word_from_le(nt.OptionalHeader.MinorImageVersion);
+	self_swap_word_from_le(nt.OptionalHeader.MajorSubsystemVersion);
+	self_swap_word_from_le(nt.OptionalHeader.MinorSubsystemVersion);
+	self_swap_dword_from_le(nt.OptionalHeader.Win32VersionValue);
+	self_swap_dword_from_le(nt.OptionalHeader.SizeOfImage);
+	self_swap_dword_from_le(nt.OptionalHeader.SizeOfHeaders);
+	self_swap_dword_from_le(nt.OptionalHeader.CheckSum);
+	self_swap_word_from_le(nt.OptionalHeader.Subsystem);
+	self_swap_word_from_le(nt.OptionalHeader.DllCharacteristics);
+	self_swap_dword_from_le(nt.OptionalHeader.SizeOfStackReserve);
+	self_swap_dword_from_le(nt.OptionalHeader.SizeOfStackCommit);
+	self_swap_dword_from_le(nt.OptionalHeader.SizeOfHeapReserve);
+	self_swap_dword_from_le(nt.OptionalHeader.SizeOfHeapCommit);
+	self_swap_dword_from_le(nt.OptionalHeader.LoaderFlags);
+	self_swap_dword_from_le(nt.OptionalHeader.NumberOfRvaAndSizes);
+	int i;
+	for(i = 0; i < nt.OptionalHeader.NumberOfRvaAndSizes; i++)
+	{
+		self_swap_dword_from_le(nt.OptionalHeader.DataDirectory[i].VirtualAddress);
+		self_swap_dword_from_le(nt.OptionalHeader.DataDirectory[i].Size);
+	}
+	
     /* load the section headers */
 
     size = sizeof(*sec) * nt.FileHeader.NumberOfSections;
     if (!(sec = malloc( size ))) goto error;
     if (pread( unix_fd, sec, size, pos ) != size) goto error;
 
+	/* Swap the section headers */
+	for(i = 0; i < nt.FileHeader.NumberOfSections; i++)
+	{
+		self_swap_dword_from_le(sec[i].Misc.PhysicalAddress);
+		self_swap_dword_from_le(sec[i].Misc.VirtualSize);
+		self_swap_dword_from_le(sec[i].VirtualAddress);
+		self_swap_dword_from_le(sec[i].SizeOfRawData);
+		self_swap_dword_from_le(sec[i].PointerToRawData);
+		self_swap_dword_from_le(sec[i].PointerToRelocations);
+		self_swap_dword_from_le(sec[i].PointerToLinenumbers);
+		self_swap_dword_from_le(sec[i].NumberOfRelocations);
+		self_swap_dword_from_le(sec[i].NumberOfLinenumbers);
+		self_swap_dword_from_le(sec[i].Characteristics);
+	}
+	
     if (!build_shared_mapping( mapping, unix_fd, sec, nt.FileHeader.NumberOfSections )) goto error;
 
     if (mapping->shared_file)  /* link it in the list */
--- /dev/null	Tue Aug 24 17:58:24 2004
+++ include/wine/emu.h	Tue Aug 24 17:53:11 2004
@@ -0,0 +1,78 @@
+/*
+ * Wine emulation handling
+ *
+ * Copyright (c) 1999 Alexandre Julliard
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __WINE_WINE_EMU_H
+#define __WINE_WINE_EMU_H
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include "basetsd.h"
+#include "wine/winbase16.h"
+#include "wine/winuser16.h"
+#include "ntstatus.h"
+#include "thread.h"
+#include "module.h"
+#include "wine/exception.h"
+#include "wine/server.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+/* Switch to enable/disable emulation */
+/* #define WINE_EMU */
+
+#define WINE_EMU_DEFAULT_PROT (PROT_READ|PROT_WRITE|PROT_EXEC)
+
+#ifdef WORDS_BIGENDIAN
+# ifdef __APPLE__
+#  include <machine/byte_order.h>
+#  define bswap_16		NXSwapShort
+#  define bswap_32		NXSwapLong
+#  define bswap_64		NXSwapLongLong
+# else
+#  include <byteswap.h>
+# endif
+# define WINE_EMU_BIGENDIAN 1
+# define swap_word_from_le			bswap_16
+# define swap_dword_from_le			bswap_32
+# define self_swap_word_from_le(x)  x = swap_word_from_le(x)
+# define self_swap_dword_from_le(x)	x = swap_dword_from_le(x)
+#else
+# define WINE_EMU_LITLLEENDIAN 1
+# define swap_word_from_le(x)   x
+# define swap_dword_from_le(x)  x
+# define self_swap_word_from_le(x)
+# define self_swap_dword_from_le(x)
+#endif
+
+/* init emulation functions. Need to be called before using the bswap.c's functions */
+void wine_emu_init();
+
+/* Swapping functions for memory area (implemented in bswap.c) */
+void wine_emu_init_bswap();
+int wine_emu_auto_swap_mem( void * mem_start, unsigned long mem_size, int prot );
+void wine_emu_update_auto_swap( void * mem_start, unsigned long mem_size, int prot );
+void wine_emu_enable_auto_swap();
+void wine_emu_disable_auto_swap();
+
+/* Emulation function (implemented in emu.c) */
+DWORD wine_emu_start( PEB *peb );
+
+#endif  /* __WINE_WINE_EMU_H */
--- /dev/null	Tue Aug 24 17:58:24 2004
+++ libs/emu/bswap.c	Tue Aug 24 15:32:22 2004
@@ -0,0 +1,395 @@
+/*
+ * Bytes Swapping on-the-fly using signal handling
+ *
+ * Copyright 2003 Pierre d'Herbemont
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <signal.h>
+
+#include "wine/emu.h"
+
+/* FIXME : Avoid code duplication would be good with dlls/ntdll/signal_powerpc.c */
+#ifdef __powerpc__
+#ifdef linux
+typedef struct ucontext SIGCONTEXT;
+# define HANDLER_DEF(name) void name( int __signal, struct siginfo *__siginfo, SIGCONTEXT *__context )
+# define HANDLER_CONTEXT (__context)
+# define REG_sig(reg_name, context)		((context)->uc_mcontext.regs->reg_name)
+# define GPR_sig(reg_num, context)		REG_sig(gpr[reg_num], context)
+# define IAR_sig(context)				REG_sig(nip, context)	/* Program counter */
+# define XER_sig(context)				REG_sig(xer, context) /* User's integer exception register */
+# define DAR_sig(context)				REG_sig(dar, context)
+#endif /* linux */
+#ifdef __APPLE__
+# include <sys/ucontext.h>
+# include <sys/types.h>
+# include <signal.h>
+typedef struct ucontext SIGCONTEXT;
+# define HANDLER_DEF(name) void name( int __signal, struct __siginfo *__siginfo, SIGCONTEXT *__context )
+# define HANDLER_CONTEXT (__context)
+
+# define REG_sig(reg_name, context)		((context)->uc_mcontext->ss.reg_name)
+# define reg_access(reg, context)			((unsigned int*)(&(context)->uc_mcontext->ss))[reg+2]
+# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
+# define GPR_sig(reg_num, context)		REG_sig(r##reg_num, context)
+# define IAR_sig(context)				REG_sig(srr0, context)	/* Program counter */
+# define XER_sig(context)				REG_sig(xer, context) /* Link register */
+# define DAR_sig(context)				EXCEPREG_sig(dar, context)     /* Fault registers for coredump */
+#endif /* __APPLE__ */
+#endif /* __powerpc__ */
+
+#define DTRACEFEMU if(0) printf
+
+/* FIXME: this could be optimized using directly the PPC instruction for it */
+#define swap_dword_ptr_from_le(x)   swap_dword_from_le(*((uint32_t*)x))
+#define swap_word_ptr_from_le(x)	swap_word_from_le(*((uint16_t*)x))
+
+typedef struct mem_reg
+{
+	void *		start;
+	void *		end;
+	int			prot;
+	struct mem_reg *   next;
+} mem_reg ;
+
+mem_reg * mem_reg_list = (mem_reg *)-1;
+
+static inline mem_reg * mem_reg_with_address(void * address)
+{
+	mem_reg *reg;
+	for( reg = mem_reg_list ; reg != (mem_reg *)-1 ; reg = reg->next)
+	{
+		if( reg->start <= address && reg->end > address )
+			return reg;
+	}
+	return 0;
+}
+
+
+
+/***********************************************************************
+ *		wine_emu_disable_auto_swap
+ *		Make all the auto swapped region unlocked
+ */
+void wine_emu_disable_auto_swap()
+{
+#ifdef WINE_EMU_BIGENDIAN
+	mem_reg *reg;
+	DTRACEFEMU("wine_emu_disable_auto_swap\n");
+	for( reg = mem_reg_list ; reg != (mem_reg *)-1 ; reg = reg->next)
+		mprotect(reg->start, (int)reg->end - (int)reg->start, reg->prot);
+#endif
+}
+
+/***********************************************************************
+ *		wine_emu_enable_auto_swap
+ *		Enable (lock) all the auto swapped region
+ */
+void wine_emu_enable_auto_swap()
+{
+#ifdef WINE_EMU_BIGENDIAN
+	mem_reg *reg;
+	DTRACEFEMU("wine_emu_enable_auto_swap\n");
+	for( reg = mem_reg_list ; reg != (mem_reg *)-1 ; reg = reg->next)
+		mprotect(reg->start, (int)reg->end - (int)reg->start, 0);
+#endif
+}
+
+/***********************************************************************
+ *		update all access
+ *		Update (lock) all theauto swapped region
+ */
+void wine_emu_update_auto_swap( void * mem_start, unsigned long mem_size, int prot)
+{
+	wine_emu_enable_auto_swap();
+}
+
+/***********************************************************************
+ *		wine_emu_swap_access
+ *
+ *		Called by the sigbus handler, when an instruction try to access
+ *		a memory region which is protected because its endianness is
+ *		different than the host endianness. emu_swap_access performs all
+ *		the necessary swapping.
+ *		
+ *		Return 1 if it has done its job well, 0 if the SIGBUS occured
+ *		for an other reason not related to byte swapping
+ */
+int wine_emu_swap_access( struct ucontext *uc )
+{
+#if defined(WINE_EMU_BIGENDIAN) && defined(__powerpc__)
+    unsigned int insn;
+    unsigned int target_reg, reg_A, reg_B;
+	void		*target_mem;
+	mem_reg *   region;
+	
+	DTRACEFEMU("signal job: ");
+	
+	
+	/* init mem destination */
+	target_mem = (void *)DAR_sig(uc);
+	
+	region = mem_reg_with_address(target_mem);
+	
+	/* Test if it is a memory access which cause the signal */
+	if(!region)
+	{
+        /* Not likely to happen */
+        
+		DTRACEFEMU("testing the IAR (PC) to see if we want to emulate instruction\n");
+		
+		/* Test if it is a instruction jump which cause the signal */
+		region = mem_reg_with_address((void *)IAR_sig(uc));
+		if(!region)
+		{
+			DTRACEFEMU("exception not for us\n");
+			return 0; /* not for us */
+		}
+		
+		/* Unlock the region */
+		if(mprotect(region->start, (int)region->end - (int)region->start, region->prot))
+			printf("error: cant mprotect\n");
+		
+		/* We want to emulate instruction */
+		//emu_instruction(IAR_sig(uc));
+		
+		/* Lock the region */
+		if(mprotect(region->start, (int)region->end - (int)region->start, 0))
+			printf("error: cant mprotect\n");
+			
+		return 0; /* was ours */
+	}
+	
+	/* Unlock the region */
+	if(mprotect(region->start, (int)region->end - (int)region->start, region->prot))
+		printf("error: cant mprotect");
+
+	/* init instruction */
+    insn = *(unsigned int*)IAR_sig(uc);
+    target_reg = (insn >> 21) & 0x1f;
+	reg_A = (insn >> 16) & 0x1f;
+	reg_B = (insn >> 11) & 0x1f;
+
+    switch (insn >> 26) /* Parse the PowerPC instruction */
+    {
+	case 0x1f :
+		{
+			u_int32_t reg = target_reg-1;
+			u_int16_t *mem = target_mem;
+			int i,n;
+		switch((insn>>1)&0x3ff)
+		{
+		case 23: /* LWZX */
+			DTRACEFEMU("lwzx");
+			reg_access( target_reg, uc ) = swap_dword_ptr_from_le(target_mem);
+			break;
+		case 87: /* LBZX */
+			DTRACEFEMU("lbzx");
+			reg_access( target_reg, uc ) = (*(u_int8_t*)target_mem);
+			DTRACEFEMU("\t 0x%x/0x%x", *(u_int8_t*)target_mem, reg_access( target_reg, uc ));
+			break;
+		case 597:
+			DTRACEFEMU("lswi NOT HANDLED"); 
+			return 0; /* throw an exception, since we don't know how to handle this one */
+		case 533: /* LSWX */
+			DTRACEFEMU("LSWX 0x%x", XER_sig(uc));
+			for(n=XER_sig(uc), i=24 ; n > 0 ; n--, mem++)
+			{
+				if(i==24)
+				{
+					reg = (reg + 1) % 32; reg_access( reg, uc ) = 0;
+				}
+				reg_access( reg, uc ) = *mem << i | reg_access( reg, uc );
+				if(i == 0)
+					i = 24;
+				else
+					i -= 8;
+			}
+			break;
+		case 279: /* LHZX */
+			DTRACEFEMU("lhzx");
+			reg_access( target_reg, uc ) = swap_word_ptr_from_le(target_mem);
+			DTRACEFEMU("\t 0x%x/0x%x", *(u_int16_t*)target_mem, reg_access( target_reg, uc ));
+			break;
+		default:
+			printf("unknow(31-%d) NOT HANDLED",(insn>>1)&0x3ff);
+			return 0; /* throw an exception, since we don't know how to handle this one */
+		}
+		}
+	    break;
+	case 0x20 :		/* LWZ */
+	    DTRACEFEMU("lwz");
+		reg_access( target_reg, uc ) = swap_dword_ptr_from_le(target_mem);
+		DTRACEFEMU("\t 0x%x/0x%x", *(u_int32_t*)target_mem, reg_access( target_reg, uc ));
+	    break;
+	case 0x21 :		/* LWZU */
+	    DTRACEFEMU("lwzu");
+		reg_access( target_reg, uc ) = swap_dword_ptr_from_le(target_mem);
+		reg_access( reg_A, uc ) = (int)target_mem; /* With Update */
+		DTRACEFEMU("\t 0x%x/0x%x", *(u_int32_t*)target_mem, reg_access( target_reg, uc ));
+	    break;
+	case 0x22 :		/* LBZ */
+		DTRACEFEMU("lbz");
+		reg_access( target_reg, uc ) = (*(u_int8_t*)target_mem);
+		DTRACEFEMU("\t 0x%x/0x%x", *(u_int8_t*)target_mem, reg_access( target_reg, uc ));
+	    break;
+	case 0x28 :		/* LHZ */
+		DTRACEFEMU("lhz");
+		reg_access( target_reg, uc ) = swap_word_ptr_from_le(target_mem);
+		DTRACEFEMU("\t 0x%x/0x%x", *(u_int16_t*)target_mem, reg_access( target_reg, uc ));
+	    break;
+	case 0x24 :		/* STW */
+	    DTRACEFEMU("stw");
+		*(u_int32_t*)target_mem = swap_dword_ptr_from_le(&reg_access( target_reg, uc ));
+		break;
+	case 0x0c :		/* LDWU */
+	    DTRACEFEMU("ldwu");
+	case 0x26 :		/* STS */
+	     DTRACEFEMU("sts"); 
+	case 0x2c :		/* STL */
+	     DTRACEFEMU("stl"); 
+	default :
+        fprintf(stderr, "wine_emu: uncaught (0x%x)\n", insn >> 26);
+        /* throw an exception, since we don't know how to handle this one */
+		return 0; 
+    }
+	
+	/* Lock the region */
+	if(mprotect(region->start, (int)region->end - (int)region->start, 0))
+    {
+        fprintf(stderr, "wine_emu: error: cant mprotect\n");
+        /* big troubles here */
+        return 0;
+    }
+	DTRACEFEMU("\n");
+	
+	/* Here we go again (Increment the PC) */
+    IAR_sig(uc) += 4;
+	
+	/* Tell the SIGBUS Handler it was ours */
+	return 1;
+#else /* defined(WINE_EMU_BIGENDIAN) && defined(__powerpc__) */
+# ifdef WINE_EMU_BIGENDIAN
+#  error WINE_EMU not (yet!) supported on your hardware
+# endif
+	return 0;
+#endif /* defined(WINE_EMU_BIGENDIAN) && defined(__powerpc__) */
+}
+
+HANDLER_DEF(wine_emu_signal_handler)
+{
+	DTRACEFEMU("wine_emu_signal_handler\n");
+    /* Swap signal access. */
+    wine_emu_swap_access(HANDLER_CONTEXT);
+}
+
+/***********************************************************************
+ *		wine_emu_init_bswap
+ *		Make all the auto swapped region unlocked
+ */
+void wine_emu_init_bswap()
+{
+#if WINE_EMU_BIGENDIAN
+    struct sigaction sig_act;
+	DTRACEFEMU("wine_emu_init_bswap\n");
+    
+    /* Set up a signal handler, which will be active until ntdll set up its handler */
+    sig_act.sa_sigaction = (void *)wine_emu_signal_handler;
+    sigemptyset( &sig_act.sa_mask );
+    sigaddset( &sig_act.sa_mask, SIGINT );
+    sigaddset( &sig_act.sa_mask, SIGALRM );
+
+    sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
+    sigaction( SIGBUS, &sig_act, NULL );
+#endif
+}
+
+/***********************************************************************
+ *		emu_save_mem_region
+ *
+ *		Make any memory access to the memory region starting at 'start',
+ *		and 'size' bytes long swapped. This will be done by mprotect the
+ *		pages, to no access, so that every access would en up in a
+ *		SIGBUS caught by the emu_swap_access function.
+ *		
+ *		Return 0 upon success
+ */
+int wine_emu_auto_swap_mem( void *start, unsigned long size, int prot )
+{
+#ifdef WINE_EMU_BIGENDIAN
+	DTRACEFEMU("wine_emu_auto_swap_mem(0x%x, 0x%x, 0x%x) ", (int)start, (int)size, prot);
+	mem_reg *mem = malloc(sizeof(mem_reg));
+	mem->start = start;
+	mem->end = (void *)((int)start + (int)size);
+	mem->prot = prot;
+	mem->next=(void *)-1;
+	
+	if((int)mem_reg_list != -1)
+		mem_reg_list->next=mem;
+	else
+		mem_reg_list=mem;
+    
+    /* Tell Qemu about our mmaped pages */
+    /* FIXME: prot 
+    page_set_flags(start, size, 
+                   PAGE_WRITE | PAGE_READ | PAGE_EXEC | PAGE_VALID);*/
+    
+	mprotect(start, size, 0);
+	DTRACEFEMU("done\n", (int)start, (int)size, prot);
+	return 0;
+#else
+	return 0;
+#endif
+}
+
+/***********************************************************************
+ *		emu_forget_mem_region
+ *
+ */
+int wine_emu_forget_mem_region( void *start )
+{
+#ifdef WINE_EMU_BIGENDIAN
+	mem_reg *reg, *previous = mem_reg_list;
+    DTRACEFEMU("wine_emu_forget_mem_region(0x%x) ", (int)start);
+
+	for( reg = mem_reg_list; reg != (mem_reg *)-1 ; previous=reg, reg = reg->next)
+	{
+		if( reg->start <= start && reg->end > start )
+			break;
+	}
+	previous->next = reg->next;
+
+	if(mprotect(reg->start, (int)reg->end - (int)reg->start, reg->prot))
+		printf("error: cant mprotect\n");
+    
+	free(reg);
+	
+	return 0;
+#else
+	return 0;
+#endif
+}
+
+
+
+
--- /dev/null	Tue Aug 24 17:58:24 2004
+++ libs/emu/emu.c	Tue Aug 24 17:42:46 2004
@@ -0,0 +1,77 @@
+/*
+ * x86 Emulation functions
+ *
+ * Copyright 2004 Pierre d'Herbemont
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include "wine/emu.h"
+
+/***********************************************************************
+ *		wine_emu_init
+ *
+ *		DESCR init emulation
+ *		
+ *		RETURN
+ */
+void wine_emu_init()
+{
+    wine_emu_init_bswap();
+}
+
+/***********************************************************************
+ *		wine_emu_start
+ *
+ *		DESCR start emulation on the peb entry point
+ *		
+ *		RETURN
+ */
+DWORD wine_emu_start(PEB *peb)
+{
+    /* stub right now */
+    fprintf(stderr, "wine_emu_start stub\n");
+    return 0;
+}
+
+#ifdef WINE_EMU_BIGENDIAN
+/* 
+   strcmp strlen don't work in with our byteswapping system.
+   The problem is that they access int by int to what are indeed chars
+*/
+size_t strlen( const char *src )
+{
+	size_t len = 0;
+    while (*src++) len++;
+	return len;
+}
+
+int strcmp( const char *src1, const char *src2 )
+{
+	register signed char res;
+
+	while(1)
+	{
+		if( (res=*src1-*src2++)!=0 || !*src1++)
+			break;
+	}
+	
+	return res;
+}
+#endif
\ No newline at end of file
--- /dev/null	Tue Aug 24 17:58:24 2004
+++ libs/emu/Makefile.in	Mon Aug 23 21:45:12 2004
@@ -0,0 +1,22 @@
+DEFS      = -D__WINESRC__
+DLLFLAGS  = @DLLFLAGS@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+MODULE    = libwine_emu.a
+
+C_SRCS = \
+	bswap.c \
+	emu.c
+
+all: $(MODULE)
+
+ at MAKE_RULES@
+
+$(MODULE): $(OBJS) Makefile.in
+	$(RM) $@
+	$(AR) $@ $(OBJS)
+	$(RANLIB) $@
+
+### Dependencies:


More information about the wine-patches mailing list