diff --git a/patches/krnl386.exe16-GDT_LDT_Emulation/0001-krnl386.exe16-Emulate-mov-Eb-Gb-instruction-on-x86-p.patch b/patches/krnl386.exe16-GDT_LDT_Emulation/0001-krnl386.exe16-Emulate-mov-Eb-Gb-instruction-on-x86-p.patch new file mode 100644 index 00000000..7d341ef9 --- /dev/null +++ b/patches/krnl386.exe16-GDT_LDT_Emulation/0001-krnl386.exe16-Emulate-mov-Eb-Gb-instruction-on-x86-p.patch @@ -0,0 +1,90 @@ +From 3b1a8788726b7031baa66985329f4071fc0600a7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Fri, 26 Feb 2016 23:14:25 +0100 +Subject: krnl386.exe16: Emulate 'mov Eb, Gb' instruction on x86 processor + architecture. + +Stolen from Sebastian Lackners ntorkrnl implementation. +--- + dlls/krnl386.exe16/instr.c | 35 +++++++++++++++++++++++++++++------ + 1 file changed, 29 insertions(+), 6 deletions(-) + +diff --git a/dlls/krnl386.exe16/instr.c b/dlls/krnl386.exe16/instr.c +index b44bd55..b0de30f 100644 +--- a/dlls/krnl386.exe16/instr.c ++++ b/dlls/krnl386.exe16/instr.c +@@ -113,7 +113,7 @@ static BOOL INSTR_ReplaceSelector( CONTEXT *context, WORD *sel ) + + + /* store an operand into a register */ +-static void store_reg( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int long_op ) ++static void store_reg_word( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int long_op ) + { + switch((regmodrm >> 3) & 7) + { +@@ -152,6 +152,22 @@ static void store_reg( CONTEXT *context, BYTE regmodrm, const BYTE *addr, int lo + } + } + ++/* store an operand into a byte register */ ++static void store_reg_byte( CONTEXT *context, BYTE regmodrm, const BYTE *addr ) ++{ ++ switch((regmodrm >> 3) & 7) ++ { ++ case 0: context->Eax = (context->Eax & 0xffffff00) | *addr; break; ++ case 1: context->Ecx = (context->Ecx & 0xffffff00) | *addr; break; ++ case 2: context->Edx = (context->Edx & 0xffffff00) | *addr; break; ++ case 3: context->Ebx = (context->Ebx & 0xffffff00) | *addr; break; ++ case 4: context->Eax = (context->Eax & 0xffff00ff) | (*addr << 8); break; ++ case 5: context->Ecx = (context->Ecx & 0xffff00ff) | (*addr << 8); break; ++ case 6: context->Edx = (context->Edx & 0xffff00ff) | (*addr << 8); break; ++ case 7: context->Ebx = (context->Ebx & 0xffff00ff) | (*addr << 8); break; ++ } ++} ++ + /*********************************************************************** + * INSTR_GetOperandAddr + * +@@ -333,7 +349,7 @@ static BOOL INSTR_EmulateLDS( CONTEXT *context, BYTE *instr, int long_op, + + /* Now store the offset in the correct register */ + +- store_reg( context, *regmodrm, addr, long_op ); ++ store_reg_word( context, *regmodrm, addr, long_op ); + + /* Store the correct segment in the segment register */ + +@@ -689,19 +705,26 @@ DWORD __wine_emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT *context ) + } + return ExceptionContinueExecution; + ++ case 0x8a: /* mov Eb, Gb */ + case 0x8b: /* mov Ev, Gv */ + { +- BYTE *addr = INSTR_GetOperandAddr(context, instr + 1, long_addr, ++ BYTE *data = INSTR_GetOperandAddr(context, instr + 1, long_addr, + segprefix, &len); ++ unsigned int data_size = (*instr == 0x8b) ? (long_op ? 4 : 2) : 1; + struct idtr idtr = get_idtr(); +- unsigned int offset = addr - idtr.base; ++ unsigned int offset = data - idtr.base; + +- if (offset <= idtr.limit + 1 - (long_op ? 4 : 2)) ++ if (offset <= idtr.limit + 1 - data_size) + { + idt[1].LimitLow = 0x100; /* FIXME */ + idt[2].LimitLow = 0x11E; /* FIXME */ + idt[3].LimitLow = 0x500; /* FIXME */ +- store_reg( context, instr[1], (BYTE *)idt + offset, long_op ); ++ ++ switch (*instr) ++ { ++ case 0x8a: store_reg_byte( context, instr[1], (BYTE *)idt + offset ); break; ++ case 0x8b: store_reg_word( context, instr[1], (BYTE *)idt + offset, long_op ); break; ++ } + context->Eip += prefixlen + len + 1; + return ExceptionContinueExecution; + } +-- +2.7.1 + diff --git a/patches/krnl386.exe16-GDT_LDT_Emulation/0002-krnl386.exe16-Emulate-GDT-and-LDT-access.patch b/patches/krnl386.exe16-GDT_LDT_Emulation/0002-krnl386.exe16-Emulate-GDT-and-LDT-access.patch new file mode 100644 index 00000000..fe945dfd --- /dev/null +++ b/patches/krnl386.exe16-GDT_LDT_Emulation/0002-krnl386.exe16-Emulate-GDT-and-LDT-access.patch @@ -0,0 +1,117 @@ +From 1de2ab4f1d48391f112897c2c89d4c1d77d4ac3f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Sat, 27 Feb 2016 00:04:10 +0100 +Subject: krnl386.exe16: Emulate GDT and LDT access. + +--- + dlls/krnl386.exe16/instr.c | 64 +++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 55 insertions(+), 9 deletions(-) + +diff --git a/dlls/krnl386.exe16/instr.c b/dlls/krnl386.exe16/instr.c +index b0de30f..865d944 100644 +--- a/dlls/krnl386.exe16/instr.c ++++ b/dlls/krnl386.exe16/instr.c +@@ -67,7 +67,7 @@ static inline void *get_stack( CONTEXT *context ) + } + + #include "pshpack1.h" +-struct idtr ++struct dtr + { + WORD limit; + BYTE *base; +@@ -75,19 +75,41 @@ struct idtr + #include "poppack.h" + + static LDT_ENTRY idt[256]; ++static LDT_ENTRY gdt[8192]; ++static LDT_ENTRY ldt[8192]; + +-static inline struct idtr get_idtr(void) ++static BOOL emulate_idtr( BYTE *data, unsigned int data_size, unsigned int *offset ) + { +- struct idtr ret; + #if defined(__i386__) && defined(__GNUC__) ++ struct dtr ret; + __asm__( "sidtl %0" : "=m" (ret) ); ++ *offset = data - ret.base; ++ return (*offset <= ret.limit + 1 - data_size); + #else +- ret.base = (BYTE *)idt; +- ret.limit = sizeof(idt) - 1; ++ return FALSE; + #endif +- return ret; + } + ++static BOOL emulate_gdtr( BYTE *data, unsigned int data_size, unsigned int *offset ) ++{ ++#if defined(__i386__) && defined(__GNUC__) ++ struct dtr ret; ++ __asm__( "sgdtl %0" : "=m" (ret) ); ++ *offset = data - ret.base; ++ return (*offset <= ret.limit + 1 - data_size); ++#else ++ return FALSE; ++#endif ++} ++ ++static inline WORD get_ldt(void) ++{ ++ WORD seg = 1; ++#if defined(__i386__) && defined(__GNUC__) ++ __asm__( "sldt %0" : "=m" (seg) ); ++#endif ++ return seg; ++} + + /*********************************************************************** + * INSTR_ReplaceSelector +@@ -711,10 +733,9 @@ DWORD __wine_emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT *context ) + BYTE *data = INSTR_GetOperandAddr(context, instr + 1, long_addr, + segprefix, &len); + unsigned int data_size = (*instr == 0x8b) ? (long_op ? 4 : 2) : 1; +- struct idtr idtr = get_idtr(); +- unsigned int offset = data - idtr.base; ++ unsigned int offset; + +- if (offset <= idtr.limit + 1 - data_size) ++ if (emulate_idtr( data, data_size, &offset )) + { + idt[1].LimitLow = 0x100; /* FIXME */ + idt[2].LimitLow = 0x11E; /* FIXME */ +@@ -728,6 +749,31 @@ DWORD __wine_emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT *context ) + context->Eip += prefixlen + len + 1; + return ExceptionContinueExecution; + } ++ ++ if (emulate_gdtr( data, data_size, &offset )) ++ { ++ static BOOL initialized; ++ ++ if (!initialized) ++ { ++ WORD index = get_ldt() >> 3; ++ gdt[index].BaseLow = ((DWORD_PTR)ldt & 0x0000FFFF); ++ gdt[index].HighWord.Bytes.BaseMid = ((DWORD_PTR)ldt & 0x00FF0000) >> 16; ++ gdt[index].HighWord.Bytes.BaseHi = ((DWORD_PTR)ldt & 0xFF000000) >> 24; ++ gdt[index].LimitLow = 0xFFFF; ++ gdt[index].HighWord.Bits.Pres = 1; ++ ++ initialized = TRUE; ++ } ++ ++ switch (*instr) ++ { ++ case 0x8a: store_reg_byte( context, instr[1], (BYTE *)gdt + offset ); break; ++ case 0x8b: store_reg_word( context, instr[1], (BYTE *)gdt + offset, long_op ); break; ++ } ++ context->Eip += prefixlen + len + 1; ++ return ExceptionContinueExecution; ++ } + } + break; /* Unable to emulate it */ + +-- +2.7.1 + diff --git a/patches/krnl386.exe16-GDT_LDT_Emulation/definition b/patches/krnl386.exe16-GDT_LDT_Emulation/definition new file mode 100644 index 00000000..9edbcfd4 --- /dev/null +++ b/patches/krnl386.exe16-GDT_LDT_Emulation/definition @@ -0,0 +1 @@ +Fixes: [30237] Implement emulation of GDT and LDT access in Win98 mode diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index c3ca2a2c..72347d02 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -174,6 +174,7 @@ patch_enable_all () enable_kernel32_SetFileInformationByHandle="$1" enable_kernel32_TimezoneInformation_Registry="$1" enable_kernel32_VerifyVersionInfo="$1" + enable_krnl386_exe16_GDT_LDT_Emulation="$1" enable_krnl386_exe16_Invalid_Console_Handles="$1" enable_libs_Debug_Channel="$1" enable_libs_Unicode_Collation="$1" @@ -667,6 +668,9 @@ patch_enable () kernel32-VerifyVersionInfo) enable_kernel32_VerifyVersionInfo="$2" ;; + krnl386.exe16-GDT_LDT_Emulation) + enable_krnl386_exe16_GDT_LDT_Emulation="$2" + ;; krnl386.exe16-Invalid_Console_Handles) enable_krnl386_exe16_Invalid_Console_Handles="$2" ;; @@ -4163,6 +4167,23 @@ if test "$enable_kernel32_VerifyVersionInfo" -eq 1; then ) >> "$patchlist" fi +# Patchset krnl386.exe16-GDT_LDT_Emulation +# | +# | This patchset fixes the following Wine bugs: +# | * [#30237] Implement emulation of GDT and LDT access in Win98 mode +# | +# | Modified files: +# | * dlls/krnl386.exe16/instr.c +# | +if test "$enable_krnl386_exe16_GDT_LDT_Emulation" -eq 1; then + patch_apply krnl386.exe16-GDT_LDT_Emulation/0001-krnl386.exe16-Emulate-mov-Eb-Gb-instruction-on-x86-p.patch + patch_apply krnl386.exe16-GDT_LDT_Emulation/0002-krnl386.exe16-Emulate-GDT-and-LDT-access.patch + ( + echo '+ { "Michael Müller", "krnl386.exe16: Emulate '\''mov Eb, Gb'\'' instruction on x86 processor architecture.", 1 },'; + echo '+ { "Michael Müller", "krnl386.exe16: Emulate GDT and LDT access.", 1 },'; + ) >> "$patchlist" +fi + # Patchset krnl386.exe16-Invalid_Console_Handles # | # | This patchset fixes the following Wine bugs: