|
|
#1 |
|
Entwickler
|
OA4/WIN7 The NTVDM CPU has encountered an illegal instruction.
Hallo Ludwig :-)
Jetzt macht er mir zb. diesen Fehler in Win7. Code:
The NTVDM CPU has encountered an illegal instruction. CS:1e3a IP:7ffa OP: ff ff 00 00 02 Choose 'Close' to terminate the application |
|
|
|
|
|
#2 |
|
Entwickler
|
Nachzustellen ist der Fehler recht simpel - einfach aus dem OA4 heraus per F8 den DESK MANAGER starten und die Eingabeaufforderung aufrufen. Dann ein simples DIR starten und nach Rückkehr (EXIT) ins OA4 per ALT+TAB ins Windows wechseln. Schwupps - schon hat man einen dunklen Bildschirm (für ca. 30 sek.) wo man denkt der Rechner hätte sich verabschiedet....
|
|
|
|
|
|
#3 |
|
Moderator
|
Tja, ist leider ein Windows 7 Problem. Da kann ich auch nicht viel machen leider.
Deutet sehr auf den Videotreiber hin. Siehe hierzu auch: http://www.experts-exchange.com/Micr..._22391981.html Nachdem wir ja wissen, dass Microschrott die Videotreiberunterstützung in Vista schon ziemlich ruiniert hat (ich sag nur Vollbild), liegt die Vermutung nahe, dass NTVDM nun nichteinmal mehr 100% mit dem Standard VGA-Treiber kompatibel ist. Allerdings habe ich zu demselben Fehler öfters schon gelesen, dass man die TEMP und TMP Environment-Variablen auf ein Verzeichnis setzen sollte, welches einen kurzen Standard DOS-Dateinamen enthält, vielleicht hilft das ja wirklich was? ![]() Code:
mkdir C:\temp set TEMP=C:\TEMP set TMP=C:\TEMP oa4
|
|
|
|
|
|
#4 |
|
Moderator
|
#unhide (This post can be viewed by guests also)
Hallo ! Ich hab mir das Problem jetzt doch mal näher angesehen und einen Patch dafür gemacht, nachdem M$ leider noch immer säumig ist. Nachdem er nicht nur deutschsprachige OA-Benutzer interessieren könnte, habe ich meine Erklärungen dafür auf Englisch geschrieben... Analysis and fix for the fullscreen switching bug in Windows 7 ================================================== ============ You may already know that ALT+Enter is a commonly used hotkey to switch application between window mode and full-screen mode. For the cmd prompt, the hotkey should work as expected on prior windows OS up to windows XP and for example enters real Text mode for DOS applications. But for Windows Vista and Windows 7, cmd can't be switched to full-screen mode, this is by design. For further information see http://support.microsoft.com/kb/926657 There is a very interesting article explaining the rasons behind this, which I recommend you to read: http://colinxu.wordpress.com/2011/02...ssue-analysis/ Now it's also known and explained in the KB-Article, that you can get back fullscreen with either a WDM-driver for the Windows XP display driver model or to switch back to the default VGA video driver, which still supports the old driver model. This works, but there are some issues that users experienced, most notably a bug in the Full screen switching code that causes a NTVDM lockup which I will cover in this article. How to enable Fullscreen for your DOS apps ========================================== But first, how to conveniently use DOS Fullscreen applications without the need to be stuck with the VGA driver all the time? The preferred method is to install the XPDM display driver for your graphics board, but if this doesn't work, I also have a very convenient solution. So each approach is described here: Installing the XPDM driver for your video card ------------------------------------------- First, check if there is a Windows XP videp driver available for your graphics board. You need to have the driver installation (.inf) files available, so it won't help to just have an .exe Installer, because most likely this installer checks for the OS version and refuses to run on Windows 7. So in case you just get an .exe, you first need to extract the .inf and .sys files from it, i.e. via 7-zip. Here is a thread describing how to extract Intel video drivers for instance: https://communities.intel.com/thread/12591 After you have the .inf files, you need to check if they contain a section for Windows 7 or if the refuse to run there. Intel Video drivers i.e. have this section: Code:
[IntelGfx.NTx86.6.0] ; no install on Vista/Win7 [IntelGfx.NTx86.6.2] ; no install on Win8 [IntelGfx.NTx86.5.1] %iSNBGM1% = iSNBM0, PCI\VEN_8086&DEV_0106 %iSNBGD1% = iSNBD0, PCI\VEN_8086&DEV_0102 %iSNBGM2% = iSNBM0, PCI\VEN_8086&DEV_0116 %iSNBGD2% = iSNBD0, PCI\VEN_8086&DEV_0112 %iSNBGM2P% = iSNBM0, PCI\VEN_8086&DEV_0126 %iSNBGD2P% = iSNBD0, PCI\VEN_8086&DEV_0122 %iSNBGD3% = iSNBD0, PCI\VEN_8086&DEV_010A %iIVBGD0% = iIVBD0, PCI\VEN_8086&DEV_0162 %iIVBGM0% = iIVBM0, PCI\VEN_8086&DEV_0166 %iIVBGD0SRV% = iIVBD0, PCI\VEN_8086&DEV_016A %iIVBGD0GT1% = iIVBD0, PCI\VEN_8086&DEV_0152 %iIVBGM0GT1% = iIVBM0, PCI\VEN_8086&DEV_0156 %iIVBGD0SRVGT1% = iIVBD0, PCI\VEN_8086&DEV_015A it doesn't contain any entries. So simply copy all the PCI strings from Windows XP section (IntelGfx.NTx86.5.1) to this section (just place the entries right under [IntelGfx.NTx86.6.0] line. After fixing the .inf file, go to the Devie manager, uninstall the WDDM driver and update the driver to the XPDM driver by pointing the installation source to the diectory you have your .inf file in. If everything works, it will detect and install the XP driver and if you have luck, you are then running the XP driver which supports fullscreen. If you fail or are unabe to do this, please consider the following option instead: Using Fullsreen by dynamically switching between VGA and WDDM --------------------------------------------------------------- Note: This is just meant for users that don't have a Windows XP Display driver available for their Video card, using the XP Video driver is still the preferred method as it saves you don't need to switch between the video modes as described here. However the XPDM display driver may have performance issues, so you can decide which works better for you. In Windows 7, you can dynamically enable and disable the video driver without reboot, which is great because this way, you can also script this and therefore make a batchfile, which disables your current WDM video driver so that you have the standard VGA XPDM video driver, then switch to fullscreen, use your DOS app and after you are done restore the WDM video driver with devcon. I made a patch that automates this for you which can be found here Otherwise here is how to do it: * Download devcon [http://support.microsoft.com/kb/311272] and place it in your application directory, i.e. C:\OA4 * Put my Fullscreen switch utility (fullscr) attached below into your application directory. * Now create a batchfile to start your application, i.e. STARTOA4.bat with the following content: ------------------------------------------------------------------------------ Code:
@echo off
c:
cd \oa4
setlocal enableDelayedExpansion
for /f "tokens=1 skip=1 delims=:" %%I in ('devcon listclass display') do set J=%%I && devcon disable "!J:~0,44!"
fullscr
oa4.exe
fullscr 2
for /f "tokens=1 skip=1 delims=:" %%I in ('devcon listclass display') do set J=%%I && devcon enable "!J:~0,44!"
endlocalYou obviously have to adapt OA4.EXE to the application file for your application to start (i.e. you may have a batch file to start, then use "call mybat.bat" so that the startoa.bat isn't quit) and the "cd" at the beginning to go to your application's directory. This is necessary, as all Batch files that are run as admin via a link start in %SystemRoot%, so you have to go to your dir first. * Now as devcon is messing around with the system hardware, it needs Administration rights to do its task. So you now should create a shortcut to STARTOA4.BAT, i.e. on your desktop and in its properties under "Advanced..." select [x] Run as administrator. Done, now everytime you click your shortcut, video mode is switched to standard VGA, then your DOS APP is run in fullscreen and after exit, VGA card driver is restored back by enabling it. The fullscr 2 command does a switch back to windowed mode [fullscr.exe was updated on 2016/10/13 to support this], as some WDDM video drivers crash when switching back from textmode directly when reenabling. I hope it works for you. Don't forget to change the video resolution when in Standard VGA mode to your normal resolution, as it's usually impractical to be stuck at 640x480 and even the Standard VGA driver normally supports higher resolutions, but default is 640x480 when you disable your WDDM Display driver for the first time. As you now have the possibility to run your application in full screen text mode, now let's go for the bugs that you are facing. The Fullscreen NTVDM Bug ======================== Just try the following to reproduce it: Just run your favourite DOS program in full screen mode, either by using the trick mentioned above or by generally running in Standard VGA mode and editing the settings of your favourite DOS program to switch it to Full screen (Properties of .EXE -> Screen -> change from Windowed to Full screen) so that it starts in full screen mode. Also ensure that you enabled the possibility to capture ALT+Tab for switch (default). When the DOS App starts in Full-screen, try to switch away with ALT+TAB and boom, your machine keeps hangig for almost a Minute, afterwars you are back in the GUI mode and have a message box telling you "NTVDM has encountered a system error. The parameter is incorrect". This is especially naughty combined with the bug that the guy in the blog mentioned above found. Once you switched to VGA and back to the driver, Fullscreen is not blocked and therefore you also get into this lockup trouble, once you notice that the mode switch went wrong and you want to go back (i.e. by pressing ALT+RETURN again). So that's pretty annoying, of course, so time to debug this issue. It's not easy to find, as you can't have your debugger open while in full screen, so I attached the WinDbg kernel debugger to the COM port and tried to debug a usermode application with it. Let's see where it hangs in ntvdm: Code:
1: kd> !process 0 0 ntvdm.exe
PROCESS 84171460 SessionId: 1 Cid: 0f04 Peb: 7ffd6000 ParentCid: 0968
DirBase: 3ed32500 ObjectTable: 8633df00 HandleCount: 60.
Image: ntvdm.exe
1: kd> .process /r /p 84171460
Implicit process is now 84171460
.cache forcedecodeuser done
Loading User Symbols
..........................
1: kd> !process 84171460
PROCESS 84171460 SessionId: 1 Cid: 0f04 Peb: 7ffd6000 ParentCid: 0968
DirBase: 3ed32500 ObjectTable: 8633df00 HandleCount: 60.
Image: ntvdm.exe
VadRoot 85d8ee60 Vads 66 Clone 0 Private 285. Modified 53. Locked 0.
DeviceMap 8a275650
Token 9f245ac8
ElapsedTime 00:00:07.140
UserTime 00:00:00.000
KernelTime 00:00:00.000
QuotaPoolUsage[PagedPool] 0
QuotaPoolUsage[NonPagedPool] 0
Working Set Sizes (now,min,max) (1010, 50, 345) (4040KB, 200KB, 1380KB)
PeakWorkingSetSize 1010
VirtualSize 56 Mb
PeakVirtualSize 56 Mb
PageFaultCount 1153
MemoryPriority BACKGROUND
BasePriority 8
CommitCharge 644
THREAD 84dd25e0 Cid 0f04.07ac Teb: 7ffdf000 Win32Thread: fe50add8 WAIT: (UserRequest) UserMode Non-Alertable
841180e8 NotificationEvent
Not impersonating
DeviceMap 8a275650
Owning Process 0 Image: <Unknown>
Attached Process 84171460 Image: ntvdm.exe
Wait Start TickCount 3571787 Ticks: 257 (0:00:00:04.015)
Context Switch Count 225
UserTime 00:00:00.187
KernelTime 00:00:00.437
Win32 Start Address ntvdm!EntryPoint (0x0e2e5095)
Stack Init 8a5c5fd0 Current 8a5c5bc8 Base 8a5c6000 Limit 8a5c3000 Call 0
Priority 10 BasePriority 8 PriorityDecrement 2 IoPriority 2 PagePriority 5
ChildEBP RetAddr
8a5c5be0 82687b15 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
8a5c5c18 82686403 nt!KiSwapThread+0x266
8a5c5c40 826802cf nt!KiCommitThreadWait+0x1df
8a5c5cb8 8284a515 nt!KeWaitForSingleObject+0x393
8a5c5d20 8265c42a nt!NtWaitForSingleObject+0xc6
8a5c5d20 76e564f4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 8a5c5d34)
0122f9d8 76e55e6c ntdll!KiFastSystemCallRet (FPO: [0,0,0])
0122f9dc 7502179c ntdll!NtWaitForSingleObject+0xc (FPO: [3,0,0])
0122fa48 752ef003 KERNELBASE!WaitForSingleObjectEx+0x98 (FPO: [SEH])
0122fa60 752eefb2 kernel32!WaitForSingleObjectExImplementation+0x75 (FPO: [3,0,4])
0122fa74 0e323125 kernel32!WaitForSingleObject+0x12 (FPO: [2,0,0])
0122fa8c 0e32321c ntvdm!CheckScreenSwitchRequest+0x2f (FPO: [1,0,0])
0122faa8 0e2e53e4 ntvdm!cpu_simulate+0xd4 (FPO: [0,1,4])
0122fab4 0e2e535f ntvdm!host_main+0x5f (FPO: [2,0,4])
0122faf0 0e2e559c ntvdm!main+0x3a (FPO: [SEH])
0122fbd0 752f1174 ntvdm!host_main+0x217 (FPO: [SEH])
0122fbdc 76e6b3f5 kernel32!BaseThreadInitThunk+0xe (FPO: [1,0,0])
0122fc1c 76e6b3c8 ntdll!__RtlUserThreadStart+0x70 (FPO: [SEH])
0122fc34 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [2,2,0])
THREAD 840f78f0 Cid 0f04.0268 Teb: 7ffde000 Win32Thread: fe4e1008 WAIT: (UserRequest) UserMode Alertable
841180e8 NotificationEvent
Not impersonating
DeviceMap 8a275650
Owning Process 0 Image: <Unknown>
Attached Process 84171460 Image: ntvdm.exe
Wait Start TickCount 3571786 Ticks: 258 (0:00:00:04.031)
Context Switch Count 16
UserTime 00:00:00.000
KernelTime 00:00:00.000
Win32 Start Address ntvdm!ConsoleEventThread (0x0e317abb)
Stack Init 8a5e1fd0 Current 8a5e1bc8 Base 8a5e2000 Limit 8a5df000 Call 0
Priority 13 BasePriority 10 PriorityDecrement 2 IoPriority 2 PagePriority 5
ChildEBP RetAddr
8a5e1be0 82687b15 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
8a5e1c18 82686403 nt!KiSwapThread+0x266
8a5e1c40 826802cf nt!KiCommitThreadWait+0x1df
8a5e1cb8 8284a515 nt!KeWaitForSingleObject+0x393
8a5e1d20 8265c42a nt!NtWaitForSingleObject+0xc6
8a5e1d20 76e564f4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 8a5e1d34)
0238fca0 76e55e6c ntdll!KiFastSystemCallRet (FPO: [0,0,0])
0238fca4 0e3164eb ntdll!NtWaitForSingleObject+0xc (FPO: [3,0,0])
0238fcb4 0e317a38 ntvdm!nt_process_suspend_event+0x1b (FPO: [0,0,0])
0238fd44 0e317b01 ntvdm!nt_event_loop+0x1a1 (FPO: [0,31,4])
0238fd78 752f1174 ntvdm!ConsoleEventThread+0x46 (FPO: [SEH])
0238fd84 76e6b3f5 kernel32!BaseThreadInitThunk+0xe (FPO: [1,0,0])
0238fdc4 76e6b3c8 ntdll!__RtlUserThreadStart+0x70 (FPO: [SEH])
0238fddc 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [2,2,0])
THREAD 83fb9d48 Cid 0f04.0ff4 Teb: 7ffdd000 Win32Thread: 00000000 WAIT: (WrLpcReply) UserMode Non-Alertable
83fb9f7c Semaphore Limit 0x1
Waiting for reply to ALPC Message 9ef6f548 : queued at port 840941d8 : owned by process 84101200
Not impersonating
DeviceMap 8a275650
Owning Process 0 Image: <Unknown>
Attached Process 84171460 Image: ntvdm.exe
Wait Start TickCount 3571791 Ticks: 253 (0:00:00:03.953)
Context Switch Count 52
UserTime 00:00:00.015
KernelTime 00:00:00.000
Win32 Start Address ntvdm!HeartBeatThread (0x0e309a56)
Stack Init 8a633fd0 Current 8a633ad0 Base 8a634000 Limit 8a631000 Call 0
Priority 15 BasePriority 15 PriorityDecrement 0 IoPriority 2 PagePriority 5
ChildEBP RetAddr
8a633ae8 82687b15 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
8a633b20 82686403 nt!KiSwapThread+0x266
8a633b48 826802cf nt!KiCommitThreadWait+0x1df
8a633bc0 826cfb66 nt!KeWaitForSingleObject+0x393
8a633be8 8288ebee nt!AlpcpSignalAndWait+0x7b
8a633c0c 82884c6f nt!AlpcpReceiveSynchronousReply+0x27
8a633c9c 828782ca nt!AlpcpProcessSynchronousRequest+0x276
8a633cf8 8288fb17 nt!LpcpRequestWaitReplyPort+0x6a
8a633d20 8265c42a nt!NtRequestWaitReplyPort+0x4c
8a633d20 76e564f4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 8a633d34)
024dfa5c 76e558ac ntdll!KiFastSystemCallRet (FPO: [0,0,0])
024dfa60 752f1331 ntdll!NtRequestWaitReplyPort+0xc (FPO: [3,0,0])
024dfa80 752ecbcb kernel32!ConsoleClientCallServer+0x88 (FPO: [4,0,4])
024dfb40 752ecb55 kernel32!GetConsoleScreenBufferInfoEx+0x3d (FPO: [2,41,4])
024dfbb0 0e311cb5 kernel32!GetConsoleScreenBufferInfo+0x1b (FPO: [2,24,0])
024dfbf0 0e31210d ntvdm!resizeWindow+0x28 (FPO: [2,9,4])
024dfc04 0e3123ce ntvdm!textResize+0x5b (FPO: [0,0,0])
024dfc10 0e312611 ntvdm!nt_init_screen+0x1ce (FPO: [0,0,0])
024dfc24 0e2fc60f ntvdm!nt_set_paint_routine+0x1b2 (FPO: [2,0,4])
024dfc3c 0e319249 ntvdm!choose_vga_display_mode+0x16d (FPO: [0,0,4])
024dfc64 0e3195f4 ntvdm!syncVGAEmulationToHardware+0x399 (FPO: [0,5,4])
024dfc68 0e319795 ntvdm!fullScreenToWindowed+0xf (FPO: [0,0,0])
024dfca4 0e3095ca ntvdm!DoHandShake+0x13a (FPO: [SEH])
024dfcc0 0e309916 ntvdm!DelayHeartBeat+0x53 (FPO: [1,2,4])
024dfcdc 0e309ad0 ntvdm!Win32_host_timer+0x19 (FPO: [0,2,0])
024dfd10 752f1174 ntvdm!HeartBeatThread+0x7a (FPO: [SEH])
024dfd1c 76e6b3f5 kernel32!BaseThreadInitThunk+0xe (FPO: [1,0,0])
024dfd5c 76e6b3c8 ntdll!__RtlUserThreadStart+0x70 (FPO: [SEH])
024dfd74 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [2,2,0])when waiting for a LPC message. We have to consider the new console architecture of Windows 7 which is very well explained here: http://blogs.technet.com/b/askperf/a...sole-host.aspx There now is a seperated Usermode process called ConHost.exe that hosts a console. It is talked to by a LPC call. So NTVDM is asking ConHost about GetConsoleScreenBufferInfo, but ConHost.exe is not replying causing the hang. That means we have to debug ConHost and check where it locks up: Code:
1: kd> !process 0 0 conhost.exe
PROCESS 84101200 SessionId: 1 Cid: 0548 Peb: 7ffd8000 ParentCid: 018c
DirBase: 3ed323a0 ObjectTable: 9e88c418 HandleCount: 46.
Image: conhost.exe
1: kd> .process /r /p 84101200
Implicit process is now 84101200
.cache forcedecodeuser done
Loading User Symbols
.................
1: kd> !process 84101200
PROCESS 84101200 SessionId: 1 Cid: 0548 Peb: 7ffd8000 ParentCid: 018c
DirBase: 3ed323a0 ObjectTable: 9e88c418 HandleCount: 46.
Image: conhost.exe
VadRoot 8590b548 Vads 44 Clone 0 Private 166. Modified 0. Locked 0.
DeviceMap 8a275650
Token 863c3a98
ElapsedTime 00:00:07.046
UserTime 00:00:00.000
KernelTime 00:00:00.015
QuotaPoolUsage[PagedPool] 0
QuotaPoolUsage[NonPagedPool] 0
Working Set Sizes (now,min,max) (904, 50, 345) (3616KB, 200KB, 1380KB)
PeakWorkingSetSize 904
VirtualSize 39 Mb
PeakVirtualSize 39 Mb
PageFaultCount 926
MemoryPriority BACKGROUND
BasePriority 8
CommitCharge 204
THREAD 840ef030 Cid 0548.0230 Teb: 7ffde000 Win32Thread: fe9d9dd8 WAIT: (UserRequest) UserMode Non-Alertable
83ef73b8 SynchronizationEvent
Not impersonating
DeviceMap 8a275650
Owning Process 0 Image: <Unknown>
Attached Process 84101200 Image: conhost.exe
Wait Start TickCount 3571791 Ticks: 253 (0:00:00:03.953)
Context Switch Count 98
UserTime 00:00:00.000
KernelTime 00:00:00.031
Win32 Start Address conhost!ConsoleLpcThread (0x00dc159c)
Stack Init 8a5d9fd0 Current 8a5d9bc8 Base 8a5da000 Limit 8a5d7000 Call 0
Priority 11 BasePriority 8 PriorityDecrement 2 IoPriority 2 PagePriority 5
ChildEBP RetAddr
8a5d9be0 82687b15 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
8a5d9c18 82686403 nt!KiSwapThread+0x266
8a5d9c40 826802cf nt!KiCommitThreadWait+0x1df
8a5d9cb8 8284a515 nt!KeWaitForSingleObject+0x393
8a5d9d20 8265c42a nt!NtWaitForSingleObject+0xc6
8a5d9d20 76e564f4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 8a5d9d34)
004af6ac 76e55e6c ntdll!KiFastSystemCallRet (FPO: [0,0,0])
004af6b0 76e3fc72 ntdll!NtWaitForSingleObject+0xc (FPO: [3,0,0])
004af714 76e3fb56 ntdll!RtlpWaitOnCriticalSection+0x13e (FPO: [2,17,4])
004af73c 00dc1584 ntdll!RtlEnterCriticalSection+0x150 (FPO: [1,3,4])
004af744 00dc17df conhost!LockConsole+0xb (FPO: [0,0,0])
004af74c 00dc4577 conhost!RevalidateConsole+0xa (FPO: [1,0,0])
004af774 00dc1661 conhost!SrvGetConsoleScreenBufferInfo+0x15 (FPO: [2,6,4])
004af840 752f1174 conhost!ConsoleLpcThread+0x13e (FPO: [1,45,0])
004af84c 76e6b3f5 kernel32!BaseThreadInitThunk+0xe (FPO: [1,0,0])
004af88c 76e6b3c8 ntdll!__RtlUserThreadStart+0x70 (FPO: [SEH])
004af8a4 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [2,2,0])
THREAD 84064a28 Cid 0548.06b8 Teb: 7ffdf000 Win32Thread: fe9f6b80 WAIT: (UserRequest) UserMode Non-Alertable
84103500 SynchronizationEvent
83e5a858 NotificationEvent
Not impersonating
DeviceMap 8a275650
Owning Process 0 Image: <Unknown>
Attached Process 84101200 Image: conhost.exe
Wait Start TickCount 3571791 Ticks: 253 (0:00:00:03.953)
Context Switch Count 90
UserTime 00:00:00.000
KernelTime 00:00:00.140
Win32 Start Address conhost!ConsoleInputThread (0x00dc300a)
Stack Init 8a5f5fd0 Current 8a5f5748 Base 8a5f6000 Limit 8a5f3000 Call 544
Priority 8 BasePriority 8 PriorityDecrement 0 IoPriority 2 PagePriority 5
ChildEBP RetAddr
8a5f5760 82687b15 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
8a5f5798 82686403 nt!KiSwapThread+0x266
8a5f57c0 826826ef nt!KiCommitThreadWait+0x1df
8a5f593c 8284b625 nt!KeWaitForMultipleObjects+0x535
8a5f5bc8 8284b392 nt!ObpWaitForMultipleObjects+0x262
8a5f5d18 8265c42a nt!NtWaitForMultipleObjects+0xcd
8a5f5d18 76e564f4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 8a5f5d34)
0097f508 76e55e4c ntdll!KiFastSystemCallRet (FPO: [0,0,0])
0097f50c 00de2f04 ntdll!NtWaitForMultipleObjects+0xc (FPO: [5,0,0])
0097f650 00dcee01 conhost!DisplayModeTransition+0x6fe (FPO: [2,71,4])
0097f6e8 767986ef conhost!ConsoleWindowProc+0x419 (FPO: [4,31,4])
0097f714 76798876 USER32!InternalCallWinProc+0x23
0097f78c 767970f4 USER32!UserCallWinProcCheckWow+0x14b (FPO: [SEH])
0097f7e8 7679738f USER32!DispatchClientMessage+0xda (FPO: [SEH])
0097f810 76e5642e USER32!__fnDWORD+0x24 (FPO: [1,3,0])
0097f83c 76798f8f ntdll!KiUserCallbackDispatcher+0x2e (FPO: [0,0,0])
0097f840 76798fc2 USER32!NtUserGetMessage+0xc (FPO: [4,0,0])
0097f85c 00dc30bb USER32!GetMessageW+0x33 (FPO: [4,0,4])
0097f8a0 752f1174 conhost!ConsoleInputThread+0xed (FPO: [1,8,4])
0097f8ac 76e6b3f5 kernel32!BaseThreadInitThunk+0xe (FPO: [1,0,0])
0097f8ec 76e6b3c8 ntdll!__RtlUserThreadStart+0x70 (FPO: [SEH])
0097f904 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [2,2,0])look on it. First interesting up in the stack is LockConsole: Code:
1: kd> u conhost!LockConsole conhost!LockConsole: 00dc1579 68c081df00 push offset conhost!gConsoleInformation (00df81c0) 00dc157e ff155c13dc00 call dword ptr [conhost!_imp__RtlEnterCriticalSection (00dc135c)] 00dc1584 c3 ret RevalidateConsole just calls LockConsole and always returns 0: Code:
1: kd> u conhost!RevalidateConsole conhost!RevalidateConsole: 00dc17d5 8bff mov edi,edi 00dc17d7 55 push ebp 00dc17d8 8bec mov ebp,esp 00dc17da e89afdffff call conhost!LockConsole (00dc1579) 00dc17df 8b4508 mov eax,dword ptr [ebp+8] 00dc17e2 c700c081df00 mov dword ptr [eax],offset conhost!gConsoleInformation (00df81c0) 00dc17e8 33c0 xor eax,eax 00dc17ea 5d pop ebp 00dc17eb c20400 ret 4 Code:
... conhost!ConsoleWindowProc+0x28: 00dc2f2b c745ac01000000 mov dword ptr [ebp-54h],1 00dc2f32 e842e6ffff call conhost!LockConsole (00dc1579) 00dc2f37 8b0d6082df00 mov ecx,dword ptr [conhost!gConsoleInformation+0xa0 (00df8260)] 00dc2f3d 8b355882df00 mov esi,dword ptr [conhost!gConsoleInformation+0x98 (00df8258)] ... 00dc2fca 7409 je conhost!ConsoleWindowProc+0x306 (00dc2fd5) 00dc2fcc e834e5ffff call conhost!UnlockConsole (00dc1505) 00dc2fd1 8365ac00 and dword ptr [ebp-54h],0 00dc2fd5 ff75b4 push dword ptr [ebp-4Ch] DisplayModeTransition. Now let's check DisplayModeTransition: where it hangs: Code:
conhost!DisplayModeTransition+0xb5: 00de28bb 7512 jne conhost!DisplayModeTransition+0xc9 (00de28cf) 00de28bd 8b357013dc00 mov esi,dword ptr [conhost!_imp__DbgPrintEx (00dc1370)] 00de28c3 68c030de00 push offset conhost!`string' (00de30c0) 00de28c8 51 push ecx 00de28c9 6a70 push 70h 00de28cb ffd6 call esi 00de28cd ebcd jmp conhost!DisplayModeTransition+0x96 (00de289c) 00de28cf f705cc82df0000020000 test dword ptr [conhost!gConsoleInformation+0x10c (00df82cc)],200h 00de28d9 8b357013dc00 mov esi,dword ptr [conhost!_imp__DbgPrintEx (00dc1370)] 00de28df 8b3d2413dc00 mov edi,dword ptr [conhost!_imp__NtSetEvent (00dc1324)] 00de28e5 0f84e7000000 je conhost!DisplayModeTransition+0x1cc (00de29d2) 00de28eb 838d10ffffffff or dword ptr [ebp-0F0h],0FFFFFFFFh 00de28f2 53 push ebx 00de28f3 ff35fc82df00 push dword ptr [conhost!gConsoleInformation+0x13c (00df82fc)] 00de28f9 c7850cffffff00ba3cdc mov dword ptr [ebp-0F4h],0DC3CBA00h 00de2903 ffd7 call edi 00de2905 3bc3 cmp eax,ebx 00de2907 89851cffffff mov dword ptr [ebp-0E4h],eax 00de290d 0f8c86000000 jl conhost!DisplayModeTransition+0x193 (00de2999) 00de2913 a1cc81df00 mov eax,dword ptr [conhost!gConsoleInformation+0xc (00df81cc)] 00de2918 a38084df00 mov dword ptr [conhost!gConsoleInformation+0x2c0 (00df8480)],eax 00de291d e81edcffff call conhost!UnlockConsoleForCurrentThread (00de0540) 00de2922 898504ffffff mov dword ptr [ebp-0FCh],eax 00de2928 8d850cffffff lea eax,[ebp-0F4h] 00de292e 50 push eax 00de292f 53 push ebx 00de2930 6a01 push 1 00de2932 8d85ecfeffff lea eax,[ebp-114h] 00de2938 50 push eax 00de2939 ffb508ffffff push dword ptr [ebp-0F8h] 00de293f ff15f412dc00 call dword ptr [conhost!_imp__NtWaitForMultipleObjects (00dc12f4)] 00de2945 89851cffffff mov dword ptr [ebp-0E4h],eax 00de294b 8d8500ffffff lea eax,[ebp-100h] 00de2951 50 push eax 00de2952 e87eeefdff call conhost!RevalidateConsole (00dc17d5) 00de2957 3bc3 cmp eax,ebx 00de2959 898514ffffff mov dword ptr [ebp-0ECh],eax 00de295f 7d27 jge conhost!DisplayModeTransition+0x182 (00de2988) 00de2961 399d00ffffff cmp dword ptr [ebp-100h],ebx 00de2967 7414 je conhost!DisplayModeTransition+0x177 (00de297d) 00de2969 8b8504ffffff mov eax,dword ptr [ebp-0FCh] 00de296f 53 push ebx 00de2970 ff350483df00 push dword ptr [conhost!gConsoleInformation+0x144 (00df8304)] 00de2976 a38484df00 mov dword ptr [conhost!gConsoleInformation+0x2c4 (00df8484)],eax 00de297b ffd7 call edi 00de297d 8b8514ffffff mov eax,dword ptr [ebp-0ECh] 00de2983 e91a060000 jmp conhost!DisplayModeTransition+0x79c (00de2fa2) 00de2988 ffb504ffffff push dword ptr [ebp-0FCh] 00de298e e88bdbffff call conhost!LockConsoleForCurrentThread (00de051e) 00de2993 891d8084df00 mov dword ptr [conhost!gConsoleInformation+0x2c0 (00df8480)],ebx 00de2999 399d1cffffff cmp dword ptr [ebp-0E4h],ebx 00de299f 7431 je conhost!DisplayModeTransition+0x1cc (00de29d2) 00de29a1 8125cc82df00ffbfffff and dword ptr [conhost!gConsoleInformation+0x10c (00df82cc)],0FFFFBFFFh 00de29ab 53 push ebx 00de29ac ff350483df00 push dword ptr [conhost!gConsoleInformation+0x144 (00df8304)] 00de29b2 ffd7 call edi ... stripped pseudocode to better understand what is going on here: Code:
#define CONSOLE_VDM_REGISTERED 0x200
g_uOwningThread = gConsoleInformation.OwningThread;
nRecursions = UnlockConsoleForCurrentThread();
dwWaitRet = NtWaitForMultipleObjects(HandleCount, &Handles, WaitAny, 0, &Timeout);
dwRevalConsRet = RevalidateConsole(&pstgConsoleInformation);
if ( dwRevalConsRet >= 0 )
{
LockConsoleForCurrentThread(nRecursions);
g_uOwningThread = 0;
if (dwWaitRet) {
// ERROR: VDM not responding to initial request
...
}
if ( arg_1 == FALSE )
{
// Display Mode transition to windowed
...
// Flag 0x200 seems to indicate, that we are currently operating in
// real textmode Fullscreen
if ( gConsoleInformation_Flags & CONSOLE_VDM_REGISTERED )
{
NtSetEvent(hObject, 0);
fsctrlstr.StateHeader = g_BaseAddress;
fsctrlstr.StateLength = g_Length;
if (NtWaitForMultipleObjects(HandleCount, &Handles, WaitAny, 0, &Timeout) < 0 ||
GdiFullscreenControl(FullscreenControlSaveHardwareState, &State, StateSize, &State, &StateSize) < 0)
{
// ERROR: VDM not responding: Save Video States Failed
}
else
{
ConsoleControl(ConsoleSetVDMCursorBounds, NULL, 0);
ConnectToEmulator(FALSE);
}
if ( gConsoleInformation_Flags & CONSOLE_VDM_REGISTERED )
{
Timeout = (LARGE_INTEGER)-600000000i64;
dwWaitRet = NtSetEvent(hObject, 0);
if ( dwWaitRet >= 0 )
dwWaitRet = NtWaitForMultipleObjects(HandleCount, &Handles, WaitAny, 0, &Timeout);
...
}
}
}
}
if ( pstgConsoleInformation )
{
g_nRecursions = nRecursions;
NtSetEvent(g_hDoneEvent, 0);
}
return dwRevalConsRet;0, that means that the first IF path is always taken and the rest after that path will never be reached. That dead code is a good place that can be used for a patch lateron. What is interesting are the functions UnlockConsoleForCurrentThread and LockConsoleForCurrentThread: Code:
1: kd> u conhost!UnlockConsoleForCurrentThread conhost!UnlockConsoleForCurrentThread: 00de0540 8bff mov edi,edi 00de0542 56 push esi 00de0543 8b35c881df00 mov esi,dword ptr [conhost!gConsoleInformation+0x8 (00df81c8)] 00de0549 85f6 test esi,esi 00de054b 760c jbe conhost!UnlockConsoleForCurrentThread+0x19 (00de0559) 00de054d 57 push edi 00de054e 8bfe mov edi,esi 00de0550 e8b00ffeff call conhost!UnlockConsole (00dc1505) 00de0555 4f dec edi 00de0556 75f8 jne conhost!UnlockConsoleForCurrentThread+0x10 (00de0550) 00de0558 5f pop edi 00de0559 8bc6 mov eax,esi 00de055b 5e pop esi 00de055c c3 ret Code:
typedef struct _RTL_CRITICAL_SECTION {
PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
LONG LockCount;
LONG RecursionCount;
HANDLE OwningThread; // from the thread's ClientId->UniqueThread
HANDLE LockSemaphore;
ULONG_PTR SpinCount; // force size on 64-bit systems when packed
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;Recursions, the console is Unlocked the number of recursions given. Now the counterpart LockConsoleForCurrentThread: Code:
1: kd> u conhost!LockConsoleForCurrentThread conhost!LockConsoleForCurrentThread: 00de051e 8bff mov edi,edi 00de0520 55 push ebp 00de0521 8bec mov ebp,esp 00de0523 56 push esi 00de0524 8b7508 mov esi,dword ptr [ebp+8] 00de0527 eb05 jmp conhost!LockConsoleForCurrentThread+0x10 (00de052e) 00de0529 e84b10feff call conhost!LockConsole (00dc1579) 00de052e 3935c881df00 cmp dword ptr [conhost!gConsoleInformation+0x8 (00df81c8)],esi 00de0534 75f3 jne conhost!LockConsoleForCurrentThread+0xb (00de0529) 00de0536 5e pop esi 00de0537 5d pop ebp 00de0538 c20400 ret 4 already locked. In the above code, it's adding back the number of recursive Locks that were taken and released prior to NtWaitForMultipleObjects() call. Fine so far, but there also is a call to RevalidateConsole() which does a LockConsole internally as seen above. This doesn't hurt, as LockConsole only adds locks, if there are too few, but as RevalidateConsole() already adds the missing lock, it doesn't do anything. As there is already a lock from the ConsoleWindowProc in place, the call to Revalidateconsole() is unnecessary, as LockConsoleForCurrentThread() will also be able to add the missing lock itself. Its return values are of no use either, as the code branch is never taken. So this call is another thing that can be eliminated. -> Even more space Now where does the deadlock finally happen? It's the NtWaitForMultipleObjects call after ConnectToEmulator(), so my assumption about what is happening here is the following: Normally there is always one event queued to the VDM, then the event hObject is signalled to actually run the task in the VDM and then it's waiting for the VDM to complete the task by waiting on the wait-handles via NtWaitForMultipleObjects. Now one of these tasks calls GetConsoleScreenBufferInfo (As seen in the stack above), which in turn is waiting for the lock. As the lock is actually being held by the ConsoleWindowProc --> DEADLOCK!! Now it seems that this may be expected so there are the UnlockConsoleForCurrentThread and LockConsoleForCurrentThread functions that temporarily remove the lock to prevent such situations while waiting for the console to execute the requested task and afterwards immediately place a lock on it again. But this is only done on the first Wait-call and the deadlock-Condition actually occurs on the third NtWaitForMultipleObjects call. These code blocks are only used for NTVDM processing anway (as they are guarded by CONSOLE_VDM_REGISTERED flags), so I guess this was just a programming error. So this leads us to a strategy for fixing: How to patch this deadlock ========================== The simplest solution would be to just eliminate all the locking calls and just leave the UnlockConsoleForCurrentThread call so that there are no locks to wait for. This indeed works, but doesn't look like a proper solution. When having a look at the way the NtWaitForMultipleObjects function is called in all 3 places, it can be seen that it's always the same call and it's always using the same variables. This gives us the opportunity to reuse the existing calls to it and just add a wrapper with UnlockConsoleForCurrentThread before and LockConsoleForCurrentThread afterwards so that it's "guarded" by the Mutex releasing functions. In pseudocode, we would replace all NtWaitForMultipleObjects calls with: Code:
nRecursions = UnlockConsoleForCurrentThread(); dwWaitRet = NtWaitForMultipleObjects(HandleCount, &Handles, WaitAny, 0, &Timeout); LockConsoleForCurrentThread(nRecursions); is implemented in the ASM-code: Code:
007A2905 |. 3BC3 CMP EAX,EBX 007A2907 |. 8985 1CFFFFFF MOV DWORD PTR SS:[EBP-E4],EAX 007A290D |. 0F8C 86000000 JL conhost.007A2999 007A2913 |. A1 CC817B00 MOV EAX,DWORD PTR DS:[7B81CC] 007A2918 |. A3 80847B00 MOV DWORD PTR DS:[7B8480],EAX 007A291D |. E8 1EDCFFFF CALL conhost.007A0540 ; UnlockConsoleForCurrentThread 007A2922 |. 8985 04FFFFFF MOV DWORD PTR SS:[EBP-FC],EAX 007A2928 |. 8D85 0CFFFFFF LEA EAX,DWORD PTR SS:[EBP-F4] 007A292E |. 50 PUSH EAX 007A292F |. 53 PUSH EBX 007A2930 |. 6A 01 PUSH 1 007A2932 |. 8D85 ECFEFFFF LEA EAX,DWORD PTR SS:[EBP-114] 007A2938 |. 50 PUSH EAX 007A2939 |. FFB5 08FFFFFF PUSH DWORD PTR SS:[EBP-F8] 007A293F |. FF15 F4127800 CALL DWORD PTR DS:[<&ntdll.NtWaitForMult>; ntdll.ZwWaitForMultipleObjects 007A2945 |. 8985 1CFFFFFF MOV DWORD PTR SS:[EBP-E4],EAX 007A294B |. 8D85 00FFFFFF LEA EAX,DWORD PTR SS:[EBP-100] 007A2951 |. 50 PUSH EAX ; /Arg1 007A2952 |. E8 7EEEFDFF CALL conhost.007817D5 ; \RevalidateConsole 007A2957 |. 3BC3 CMP EAX,EBX 007A2959 |. 8985 14FFFFFF MOV DWORD PTR SS:[EBP-EC],EAX 007A295F |. 7D 27 JGE SHORT conhost.007A2988 007A2961 |. 399D 00FFFFFF CMP DWORD PTR SS:[EBP-100],EBX 007A2967 |. 74 14 JE SHORT conhost.007A297D 007A2969 |. 8B85 04FFFFFF MOV EAX,DWORD PTR SS:[EBP-FC] 007A296F |. 53 PUSH EBX 007A2970 |. FF35 04837B00 PUSH DWORD PTR DS:[7B8304] 007A2976 |. A3 84847B00 MOV DWORD PTR DS:[7B8484],EAX 007A297B |. FFD7 CALL EDI 007A297D |> 8B85 14FFFFFF MOV EAX,DWORD PTR SS:[EBP-EC] 007A2983 |. E9 1A060000 JMP conhost.007A2FA2 007A2988 |> FFB5 04FFFFFF PUSH DWORD PTR SS:[EBP-FC] ; /Arg1 007A298E |. E8 8BDBFFFF CALL conhost.007A051E ; \LockConsoleForCurrentThread 007A2993 |. 891D 80847B00 MOV DWORD PTR DS:[7B8480],EBX 007A2999 |> 399D 1CFFFFFF CMP DWORD PTR SS:[EBP-E4],EBX the NtWaitForMultipleObjects function (only those who are used that have gConsoleInformation_Flags set to CONSOLE_VDM_REGISTERED (0x200), as only they are relevant for Fullscreen handling): Code:
007A2DD8 |. 0F8C 95000000 JL conhost.007A2E73 007A2DDE |. 8D85 0CFFFFFF LEA EAX,DWORD PTR SS:[EBP-F4] 007A2DE4 |. 50 PUSH EAX 007A2DE5 |. 53 PUSH EBX 007A2DE6 |. 6A 01 PUSH 1 007A2DE8 |. 8D85 ECFEFFFF LEA EAX,DWORD PTR SS:[EBP-114] 007A2DEE |. 50 PUSH EAX 007A2DEF |. FFB5 08FFFFFF PUSH DWORD PTR SS:[EBP-F8] 007A2DF5 |. FF15 F4127800 CALL DWORD PTR DS:[<&ntdll.NtWaitForMult>; ntdll.ZwWaitForMultipleObjects 007A2DFB |. 8985 1CFFFFFF MOV DWORD PTR SS:[EBP-E4],EAX 007A2E01 |. 3D 02010000 CMP EAX,102 007A2EE5 |. 7C 23 JL SHORT conhost.007A2F0A 007A2EE7 |. 8D85 0CFFFFFF LEA EAX,DWORD PTR SS:[EBP-F4] 007A2EED |. 50 PUSH EAX 007A2EEE |. 53 PUSH EBX 007A2EEF |. 6A 01 PUSH 1 007A2EF1 |. 8D85 ECFEFFFF LEA EAX,DWORD PTR SS:[EBP-114] 007A2EF7 |. 50 PUSH EAX 007A2EF8 |. FFB5 08FFFFFF PUSH DWORD PTR SS:[EBP-F8] 007A2EFE |. FF15 F4127800 CALL DWORD PTR DS:[<&ntdll.NtWaitForMult>; ntdll.ZwWaitForMultipleObjects 007A2F04 |. 8985 1CFFFFFF MOV DWORD PTR SS:[EBP-E4],EAX 007A2F0A |> 399D 1CFFFFFF CMP DWORD PTR SS:[EBP-E4],EBX So the first function that does the locked calls can be rewritten to immediately lock again after the wait and reused in all functions. Be aware that the code is a minefield full of relocations because of the many globals that get used and these places cannot be overwritten with our code without removing them from the relocation table. On the other hand, code that is necessary and contains relocations shouldn't be removed as this would also require touching the relocations. Therefore a solution is needed that just fits in place. So here is my solution to this (see comments for details) Code:
0046290D EB 48 JMP SHORT conhost.00462957 ; Jump to regained space that does the actual 0046290F 90 NOP ; JL that should be at that place and then 00462910 90 NOP ; issue the CALL to the original code before 00462911 90 NOP ; continuing 00462912 90 NOP 00462913 |. A1 CC814700 MOV EAX,DWORD PTR DS:[4781CC] ; ATTN: Relocation fixups! 00462918 |. A3 80844700 MOV DWORD PTR DS:[478480],EAX ; ATTN: Relocation fixups! 0046291D |. E8 1EDCFFFF CALL conhost.00460540 ; UnlockConsoleForCurrentThread 00462922 |. 8985 04FFFFFF MOV DWORD PTR SS:[EBP-FC],EAX 00462928 |. 8D85 0CFFFFFF LEA EAX,DWORD PTR SS:[EBP-F4] 0046292E |. 50 PUSH EAX 0046292F |. 53 PUSH EBX 00462930 |. 6A 01 PUSH 1 00462932 |. 8D85 ECFEFFFF LEA EAX,DWORD PTR SS:[EBP-114] 00462938 |. 50 PUSH EAX 00462939 |. FFB5 08FFFFFF PUSH DWORD PTR SS:[EBP-F8] 0046293F |. FF15 F4124400 CALL DWORD PTR DS:[<&ntdll.NtWaitForMult>; ntdll.ZwWaitForMultipleObjects 00462945 |. 8985 1CFFFFFF MOV DWORD PTR SS:[EBP-E4],EAX 0046294B FFB5 04FFFFFF PUSH DWORD PTR SS:[EBP-FC] ; Lock was placed here instead of RevalidateConsole 00462951 E8 C8DBFFFF CALL conhost.0046051E ; LockConsoleForCurrentThread 00462956 C3 RETN ; RETURN from CALL 00462957 7C 40 JL SHORT conhost.00462999 ; Here is the JL that originally was above 00462959 E8 B5FFFFFF CALL conhost.00462913 ; Now call the original code 0046295E EB 33 JMP SHORT conhost.00462993 ; And continue at the code after the original Lock 00462960 90 NOP ; Align 00462961 |. 399D 00FFFFFF CMP DWORD PTR SS:[EBP-100],EBX ; -- Start of dead code 00462967 |. 74 14 JE SHORT conhost.0046297D 00462969 |. 8B85 04FFFFFF MOV EAX,DWORD PTR SS:[EBP-FC] 0046296F |. 53 PUSH EBX 00462970 |. FF35 04834700 PUSH DWORD PTR DS:[478304] 00462976 |. A3 84844700 MOV DWORD PTR DS:[478484],EAX 0046297B |. FFD7 CALL EDI 0046297D |> 8B85 14FFFFFF MOV EAX,DWORD PTR SS:[EBP-EC] 00462983 |. E9 1A060000 JMP conhost.00462FA2 00462988 |> FFB5 04FFFFFF PUSH DWORD PTR SS:[EBP-FC] ; /Arg1 0046298E |. E8 8BDBFFFF CALL conhost.0046051E ; \LockConsoleForCurrentThread 00462993 |. 891D 80844700 MOV DWORD PTR DS:[478480],EBX ; -- End of dead code, execution continues here 00462999 |> 399D 1CFFFFFF CMP DWORD PTR SS:[EBP-E4],EBX Code:
00462DD8 |. 0F8C 95000000 JL conhost.00462E73 00462DDE E8 30FBFFFF CALL conhost.00462913 ; Call our new wait function from above 00462DE3 EB 1C JMP SHORT conhost.00462E01 ; And continue at original location after wait 00462DE5 |. 53 PUSH EBX ; Start of dead code 00462DE6 |. 6A 01 PUSH 1 00462DE8 |. 8D85 ECFEFFFF LEA EAX,DWORD PTR SS:[EBP-114] 00462DEE |. 50 PUSH EAX 00462DEF |. FFB5 08FFFFFF PUSH DWORD PTR SS:[EBP-F8] 00462DF5 |. FF15 F4124400 CALL DWORD PTR DS:[<&ntdll.NtWaitForMult>; ntdll.ZwWaitForMultipleObjects 00462DFB |. 8985 1CFFFFFF MOV DWORD PTR SS:[EBP-E4],EAX ; End of dead code 00462E01 |. 3D 02010000 CMP EAX,102 ; First instruction after Wait Code:
00462EE5 |. 7C 23 JL SHORT conhost.00462F0A 00462EE7 E8 27FAFFFF CALL conhost.00462913 00462EEC EB 1C JMP SHORT conhost.00462F0A 00462EEE |. 53 PUSH EBX 00462EEF |. 6A 01 PUSH 1 00462EF1 |. 8D85 ECFEFFFF LEA EAX,DWORD PTR SS:[EBP-114] 00462EF7 |. 50 PUSH EAX 00462EF8 |. FFB5 08FFFFFF PUSH DWORD PTR SS:[EBP-F8] 00462EFE |. FF15 F4124400 CALL DWORD PTR DS:[<&ntdll.NtWaitForMult>; ntdll.ZwWaitForMultipleObjects 00462F04 |. 8985 1CFFFFFF MOV DWORD PTR SS:[EBP-E4],EAX 00462F0A |> 399D 1CFFFFFF CMP DWORD PTR SS:[EBP-E4],EBX Btw.: CONHOST issues some debug messages, if you attached a kernel debugger, you can use the command Code:
ed Kd_USERGDI_MASK ff Why is this not happening when starting the console in windowed mode? ================================================== =================== As we have seen in the stack trace at the time of deadlock above, there are some functions on the stack that finally cause a call to GetConsoleScreenBufferInfo API which causes the deadlock. So let's trace down the function calls on the stack and compare the execution flow to see where it differs between start in full screen and start in windowed mode (and then sithcing to fulscreen). The function in nt_init_screen+0x1ce seems to be good candidate, so let's trace it. Let's have a look at the function s a whole first: Code:
0: kd> u ntvdm!nt_init_screen+0x11c ntvdm!nt_init_screen+0x11c: 0e5e231c 8bff mov edi,edi 0e5e231e 53 push ebx 0e5e231f 33db xor ebx,ebx 0e5e2321 391d4483620e cmp dword ptr [ntvdm!soft_reset (0e628344)],ebx 0e5e2327 0f842b010000 je ntvdm!nt_init_screen+0x258 (0e5e2458) 0e5e232d 56 push esi 0e5e232e be49040000 mov esi,449h 0e5e2333 56 push esi 0e5e2334 e8451f0100 call ntvdm!sas_hw_at (0e5f427e) 0e5e2339 3c10 cmp al,10h 0e5e233b 7643 jbe ntvdm!nt_init_screen+0x180 (0e5e2380) 0e5e233d 56 push esi 0e5e233e e8dc210100 call ntvdm!sas_hw_at_no_check (0e5f451f) 0e5e2343 3c04 cmp al,4 0e5e2345 7228 jb ntvdm!nt_init_screen+0x16f (0e5e236f) 0e5e2347 56 push esi 0e5e2348 e8d2210100 call ntvdm!sas_hw_at_no_check (0e5f451f) 0e5e234d 3c07 cmp al,7 0e5e234f 741e je ntvdm!nt_init_screen+0x16f (0e5e236f) 0e5e2351 33c0 xor eax,eax 0e5e2353 391dacc3630e cmp dword ptr [ntvdm!EGA_GRAPH+0xc (0e63c3ac)],ebx 0e5e2359 0f95c0 setne al 0e5e235c 40 inc eax 0e5e235d 0faf05ecc4630e imul eax,dword ptr [ntvdm!PCDisplay+0xc (0e63c4ec)] 0e5e2364 0faf05e8c4630e imul eax,dword ptr [ntvdm!PCDisplay+0x8 (0e63c4e8)] 0e5e236b 8bf0 mov esi,eax 0e5e236d eb0d jmp ntvdm!nt_init_screen+0x17c (0e5e237c) 0e5e236f 8b3534c5630e mov esi,dword ptr [ntvdm!PCDisplay+0x54 (0e63c534)] 0e5e2375 0faf35e8c4630e imul esi,dword ptr [ntvdm!PCDisplay+0x8 (0e63c4e8)] 0e5e237c 3bf3 cmp esi,ebx 0e5e237e 7505 jne ntvdm!nt_init_screen+0x185 (0e5e2385) 0e5e2380 be80020000 mov esi,280h 0e5e2385 391d54d9650e cmp dword ptr [ntvdm!sc+0x34 (0e65d954)],ebx 0e5e238b 754d jne ntvdm!nt_init_screen+0x1da (0e5e23da) 0e5e238d 391d7c2b630e cmp dword ptr [ntvdm!BeepLastDuration+0x38 (0e632b7c)],ebx 0e5e2393 7521 jne ntvdm!nt_init_screen+0x1b6 (0e5e23b6) 0e5e2395 a1f0c4630e mov eax,dword ptr [ntvdm!PCDisplay+0x10 (0e63c4f0)] 0e5e239a 3b05782b630e cmp eax,dword ptr [ntvdm!BeepLastDuration+0x34 (0e632b78)] 0e5e23a0 7514 jne ntvdm!nt_init_screen+0x1b6 (0e5e23b6) 0e5e23a2 393d602b630e cmp dword ptr [ntvdm!BeepLastDuration+0x1c (0e632b60)],edi 0e5e23a8 750c jne ntvdm!nt_init_screen+0x1b6 (0e5e23b6) 0e5e23aa 3935702b630e cmp dword ptr [ntvdm!BeepLastDuration+0x2c (0e632b70)],esi 0e5e23b0 0f8497000000 je ntvdm!nt_init_screen+0x24d (0e5e244d) 0e5e23b6 a13cc5630e mov eax,dword ptr [ntvdm!PCDisplay+0x5c (0e63c53c)] 0e5e23bb 0fafc7 imul eax,edi 0e5e23be 8935b0d9650e mov dword ptr [ntvdm!sc+0x90 (0e65d9b0)],esi 0e5e23c4 a3acd9650e mov dword ptr [ntvdm!sc+0x8c (0e65d9ac)],eax 0e5e23c9 e8e4fcffff call ntvdm!textResize (0e5e20b2) 0e5e23ce a1f0c4630e mov eax,dword ptr [ntvdm!PCDisplay+0x10 (0e63c4f0)] 0e5e23d3 a3782b630e mov dword ptr [ntvdm!BeepLastDuration+0x34 (0e632b78)],eax 0e5e23d8 eb61 jmp ntvdm!nt_init_screen+0x23b (0e5e243b) 0e5e23da 33db xor ebx,ebx 0e5e23dc 43 inc ebx 0e5e23dd 391d7c2b630e cmp dword ptr [ntvdm!BeepLastDuration+0x38 (0e632b7c)],ebx 0e5e23e3 752a jne ntvdm!nt_init_screen+0x20f (0e5e240f) 0e5e23e5 393d602b630e cmp dword ptr [ntvdm!BeepLastDuration+0x1c (0e632b60)],edi 0e5e23eb 7522 jne ntvdm!nt_init_screen+0x20f (0e5e240f) 0e5e23ed 3935702b630e cmp dword ptr [ntvdm!BeepLastDuration+0x2c (0e632b70)],esi 0e5e23f3 751a jne ntvdm!nt_init_screen+0x20f (0e5e240f) 0e5e23f5 a1682b630e mov eax,dword ptr [ntvdm!BeepLastDuration+0x24 (0e632b68)] 0e5e23fa 3b054cd9650e cmp eax,dword ptr [ntvdm!sc+0x2c (0e65d94c)] 0e5e2400 750d jne ntvdm!nt_init_screen+0x20f (0e5e240f) 0e5e2402 a1582b630e mov eax,dword ptr [ntvdm!BeepLastDuration+0x14 (0e632b58)] 0e5e2407 3b0504d9650e cmp eax,dword ptr [ntvdm!host_screen_scale (0e65d904)] 0e5e240d 743e je ntvdm!nt_init_screen+0x24d (0e5e244d) 0e5e240f a13cc5630e mov eax,dword ptr [ntvdm!PCDisplay+0x5c (0e63c53c)] 0e5e2414 0fafc7 imul eax,edi 0e5e2417 8935b0d9650e mov dword ptr [ntvdm!sc+0x90 (0e65d9b0)],esi 0e5e241d a3acd9650e mov dword ptr [ntvdm!sc+0x8c (0e65d9ac)],eax 0e5e2422 e8eefcffff call ntvdm!graphicsResize (0e5e2115) 0e5e2427 a14cd9650e mov eax,dword ptr [ntvdm!sc+0x2c (0e65d94c)] 0e5e242c a3682b630e mov dword ptr [ntvdm!BeepLastDuration+0x24 (0e632b68)],eax 0e5e2431 a104d9650e mov eax,dword ptr [ntvdm!host_screen_scale (0e65d904)] 0e5e2436 a3582b630e mov dword ptr [ntvdm!BeepLastDuration+0x14 (0e632b58)],eax 0e5e243b 891d7c2b630e mov dword ptr [ntvdm!BeepLastDuration+0x38 (0e632b7c)],ebx 0e5e2441 8935702b630e mov dword ptr [ntvdm!BeepLastDuration+0x2c (0e632b70)],esi 0e5e2447 893d602b630e mov dword ptr [ntvdm!BeepLastDuration+0x1c (0e632b60)],edi 0e5e244d a1782b630e mov eax,dword ptr [ntvdm!BeepLastDuration+0x34 (0e632b78)] 0e5e2452 a39cd9650e mov dword ptr [ntvdm!sc+0x7c (0e65d99c)],eax 0e5e2457 5e pop esi 0e5e2458 5b pop ebx 0e5e2459 c3 ret 0e5e23c9 e8e4fcffff call ntvdm!textResize (0e5e20b2) when starting in full screen mode. So now trace the function in windowed mode: Code:
0: kd> ! process 0 0 ntvdm.exe
PROCESS 840d8030 SessionId: 1 Cid: 08b8 Peb: 7ffda000 ParentCid: 0968
DirBase: 3ed323a0 ObjectTable: 9ea89170 HandleCount: 59.
Image: ntvdm.exe
0: kd> .process /r /p 840d8030
Implicit process is now 840d8030
.cache forcedecodeuser done
Loading User Symbols
..........................
0: kd> ba e1 ntvdm!nt_set_paint_routine+0x1ad
0: kd> g
Display Mode transition to windowed
Breakpoint 1 hit
ntvdm!nt_set_paint_routine+0x1ad:
001b:0e6d260c e80bfdffff call ntvdm!nt_init_screen+0x11c (0e6d231c)
1: kd> t
ntvdm!nt_init_screen+0x11c:
001b:0e6d231c 8bff mov edi,edi
001b:0e6d231f 33db xor ebx,ebx
001b:0e6d2321 391d4483710e cmp dword ptr [ntvdm!soft_reset (0e718344)],ebx
001b:0e6d2327 0f842b010000 je ntvdm!nt_init_screen+0x258 (0e6d2458)
001b:0e6d232d 56 push esi
001b:0e6d232e be49040000 mov esi,449h
001b:0e6d2333 56 push esi
001b:0e6d2334 e8451f0100 call ntvdm!sas_hw_at (0e6e427e)
001b:0e6d2339 3c10 cmp al,10h
001b:0e6d233b 7643 jbe ntvdm!nt_init_screen+0x180 (0e6d2380)
001b:0e6d2380 be80020000 mov esi,280h
001b:0e6d2385 391d54d9740e cmp dword ptr [ntvdm!sc+0x34 (0e74d954)],ebx
001b:0e6d238b 754d jne ntvdm!nt_init_screen+0x1da (0e6d23da)
001b:0e6d238d 391d7c2b720e cmp dword ptr [ntvdm!BeepLastDuration+0x38 (0e722b7c)],ebx
001b:0e6d2393 7521 jne ntvdm!nt_init_screen+0x1b6 (0e6d23b6)
001b:0e6d2395 a1f0c4720e mov eax,dword ptr [ntvdm!PCDisplay+0x10 (0e72c4f0)]
001b:0e6d239a 3b05782b720e cmp eax,dword ptr [ntvdm!BeepLastDuration+0x34 (0e722b78)]
001b:0e6d23a0 7514 jne ntvdm!nt_init_screen+0x1b6 (0e6d23b6)
001b:0e6d23a2 393d602b720e cmp dword ptr [ntvdm!BeepLastDuration+0x1c (0e722b60)],edi
001b:0e6d23a8 750c jne ntvdm!nt_init_screen+0x1b6 (0e6d23b6)
001b:0e6d23aa 3935702b720e cmp dword ptr [ntvdm!BeepLastDuration+0x2c (0e722b70)],esi
001b:0e6d23b0 0f8497000000 je ntvdm!nt_init_screen+0x24d (0e6d244d)
001b:0e6d244d a1782b720e mov eax,dword ptr [ntvdm!BeepLastDuration+0x34 (0e722b78)]
001b:0e6d2452 a39cd9740e mov dword ptr [ntvdm!sc+0x7c (0e74d99c)],eax
001b:0e6d2457 5e pop esi
001b:0e6d2458 5b pop ebxLet's have a look at some pseudocode again: Code:
if (dw0e722b7c || dw0e72c4f0 != dw0e722b78 || dw0e722b60 != edi || dw0e722b70 != esi)
{
...
textResize();
}when starting in windowed mode, but when starting in full scren mode, there seems to be a difference: Code:
0: kd> dd ntvdm!PCDisplay+0x10 0e5dc4f0 00000010 0: kd> dd ntvdm!BeepLastDuration+0x34 0e5d2b78 00000008 conhost not to permit calls from NTVDM while it's processing some requests. The patcher =========== I wrote a little patcher that applies the patches and hopefully works for every released version of conhost.exe on Windows 7. Just download the patch and run it as administrator and then check if the bug is fixed. I'd love to hear from you if it worked for you too. The file can be downloaded as unregistered member from here: http://www.waldbauer.com/tmp/reference.php? Geändert von leecher (10.11.2016 um 01:16 Uhr) Grund: Added reference to automatic fullscreen switcher |
|
|
|
|
|
#5 |
|
Moderator
|
#unhide (This post can be viewed by guests also)
NTVDM Fullscren Issue #2 ======================== Today I noticed another problem with the NTVDM Fullscreen handling in Windows 7. I can't call it a bug, as it's by design, but it's an annoyance anyway. When running DBASE for DOS, I noticed that switching between windowed mode and Fullscreen in some cases took 5 seconds to react which is very annoying and gives the impression that the NTVDM got stuck. This issue is not with all DOS-applications, but it can be reproduced with DBASE. This time, it's not CONHOST which is at fault, but it's NTVDM itself. When attaching WinDbg to the failed process, the following Stacktrace can be seen (we already know this one from the CONHOST bug..): Code:
kd> !process 0 0 ntvdm.exe
PROCESS 863ef2a8 SessionId: 1 Cid: 06f4 Peb: 7ffdf000 ParentCid: 0f04
DirBase: 3f4c7580 ObjectTable: 9498ccd0 HandleCount: 158.
Image: ntvdm.exe
kd> .process /r /p 863ef2a8
Implicit process is now 863ef2a8
.cache forcedecodeuser done
Loading User Symbols
........................................
kd> !process 863ef2a8
PROCESS 863ef2a8 SessionId: 1 Cid: 06f4 Peb: 7ffdf000 ParentCid: 0f04
DirBase: 3f4c7580 ObjectTable: 9498ccd0 HandleCount: 158.
Image: ntvdm.exe
VadRoot 86200e58 Vads 110 Clone 0 Private 462. Modified 375. Locked 0.
DeviceMap 97da9648
Token 973c1040
ElapsedTime 00:06:20.128
UserTime 00:00:00.000
KernelTime 00:00:00.000
QuotaPoolUsage[PagedPool] 0
QuotaPoolUsage[NonPagedPool] 0
Working Set Sizes (now,min,max) (1672, 50, 345) (6688KB, 200KB, 1380KB)
PeakWorkingSetSize 1699
VirtualSize 77 Mb
PeakVirtualSize 78 Mb
PageFaultCount 2880
MemoryPriority BACKGROUND
BasePriority 8
CommitCharge 1898
...
THREAD 851e2040 Cid 06f4.0818 Teb: 7ffdc000 Win32Thread: 00000000 WAIT: (UserRequest) UserMode Non-Alertable
860a7ff0 NotificationEvent
8637c6e8 NotificationEvent
Not impersonating
DeviceMap 97da9648
Owning Process 863ef2a8 Image: ntvdm.exe
Attached Process N/A Image: N/A
Wait Start TickCount 139029 Ticks: 109 (0:00:00:01.703)
Context Switch Count 3186
UserTime 00:00:00.000
KernelTime 00:00:00.171
Win32 Start Address ntvdm!HeartBeatThread (0x0e2c9a56)
Stack Init 93e3ffd0 Current 93e3f748 Base 93e40000 Limit 93e3d000 Call 0
Priority 15 BasePriority 15 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
ChildEBP RetAddr
93e3f760 82899e2d nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
93e3f798 82898c87 nt!KiSwapThread+0x266
93e3f7c0 82894a64 nt!KiCommitThreadWait+0x1df
93e3f93c 82a46b0c nt!KeWaitForMultipleObjects+0x535
93e3fbc8 82a46879 nt!ObpWaitForMultipleObjects+0x262
93e3fd18 82859896 nt!NtWaitForMultipleObjects+0xcd
93e3fd18 77ac70f4 nt!KiSystemServicePostCall (FPO: [0,3] TrapFrame @ 93e3fd34)
012cfa5c 77ac6a44 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
012cfa60 75d56a8e ntdll!ZwWaitForMultipleObjects+0xc (FPO: [5,0,0])
012cfafc 7650be2e KERNELBASE!WaitForMultipleObjectsEx+0x100 (FPO: [SEH])
012cfb44 7650be9c kernel32!WaitForMultipleObjectsExImplementation+0xe0 (FPO: [5,8,4])
012cfb60 0e2d96b7 kernel32!WaitForMultipleObjects+0x18 (FPO: [4,0,0])
012cfbac 0e2c95ca ntvdm!DoHandShake+0x5c (FPO: [SEH])
012cfbc8 0e2c9916 ntvdm!DelayHeartBeat+0x53 (FPO: [1,2,4])
012cfbe4 0e2c9ad0 ntvdm!Win32_host_timer+0x19 (FPO: [0,2,0])
012cfc18 7650ee1c ntvdm!HeartBeatThread+0x7a (FPO: [SEH])
012cfc24 77ae37eb kernel32!BaseThreadInitThunk+0xe (FPO: [1,0,0])
012cfc64 77ae37be ntdll!__RtlUserThreadStart+0x70 (FPO: [SEH])
012cfc7c 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [2,2,0])Code:
ntvdm!DoHandShake: 0e4c965b 6a14 push 14h 0e4c965d 68f8e04f0e push offset ntvdm!mouse_cursor_mode_change+0x4d3 (0e4fe0f8) 0e4c9662 e8cdc6fcff call ntvdm!_SEH_prolog4 (0e495d34) 0e4c9667 33db xor ebx,ebx 0e4c9669 895de4 mov dword ptr [ebp-1Ch],ebx 0e4c966c a1c0d1530e mov eax,dword ptr [ntvdm!hErrorHardwareEvent (0e53d1c0)] 0e4c9671 8945dc mov dword ptr [ebp-24h],eax 0e4c9674 a1a4d4530e mov eax,dword ptr [ntvdm!hMainThreadSuspended (0e53d4a4)] 0e4c9679 8945e0 mov dword ptr [ebp-20h],eax 0e4c967c ff35b4d4530e push dword ptr [ntvdm!hResume (0e53d4b4)] 0e4c9682 ff15b011490e call dword ptr [ntvdm!_imp__ResetEvent (0e4911b0)] 0e4c9688 ff35acd4530e push dword ptr [ntvdm!hSuspend (0e53d4ac)] 0e4c968e 8b3d7411490e mov edi,dword ptr [ntvdm!_imp__SetEvent (0e491174)] 0e4c9694 ffd7 call edi 0e4c9696 c605c42d510e01 mov byte ptr [ntvdm!HandshakeInProgress (0e512dc4)],1 0e4c969d 891dc8d1530e mov dword ptr [ntvdm!HandshakeStage (0e53d1c8)],ebx 0e4c96a3 68f4010000 push 1F4h 0e4c96a8 53 push ebx 0e4c96a9 8d45dc lea eax,[ebp-24h] 0e4c96ac 50 push eax 0e4c96ad 6a02 push 2 0e4c96af 8b35cc11490e mov esi,dword ptr [ntvdm!_imp__WaitForMultipleObjects (0e4911cc)] 0e4c96b5 ffd6 call esi 0e4c96b7 3d02010000 cmp eax,102h 0e4c96bc 7547 jne ntvdm!DoHandShake+0xaa (0e4c9705) 0e4c96be b814070000 mov eax,714h 0e4c96c3 f0810800000001 lock or dword ptr [eax],1000000h 0e4c96ca ff352ce0530e push dword ptr [ntvdm!CurrentMonitorTeb (0e53e02c)] 0e4c96d0 e81fa70000 call ntvdm!ThreadLookUp (0e4d3df4) 0e4c96d5 3bc3 cmp eax,ebx 0e4c96d7 7408 je ntvdm!DoHandShake+0x86 (0e4c96e1) 0e4c96d9 50 push eax 0e4c96da 6a01 push 1 0e4c96dc e877d10200 call ntvdm!NtVdmControl (0e4f6858) 0e4c96e1 bbc0270900 mov ebx,927C0h 0e4c96e6 53 push ebx 0e4c96e7 6a00 push 0 0e4c96e9 8d45dc lea eax,[ebp-24h] 0e4c96ec 50 push eax 0e4c96ed 6a02 push 2 0e4c96ef ffd6 call esi 0e4c96f1 83f801 cmp eax,1 0e4c96f4 7427 je ntvdm!DoHandShake+0xc2 (0e4c971d) 0e4c96f6 c705c8d1530e14000000 mov dword ptr [ntvdm!HandshakeStage (0e53d1c8)],14h 0e4c9700 e9d4000000 jmp ntvdm!DoHandShake+0x17e (0e4c97d9) 0e4c9705 3bc3 cmp eax,ebx 0e4c9707 750f jne ntvdm!DoHandShake+0xbd (0e4c9718) 0e4c9709 c705c8d1530e0a000000 mov dword ptr [ntvdm!HandshakeStage (0e53d1c8)],0Ah 0e4c9713 e9c1000000 jmp ntvdm!DoHandShake+0x17e (0e4c97d9) ... ntvdm!hErrorHardwareEvent and ntvdm!hMainThreadSuspended with a timeout of 5000ms (1F4h). Bingo! Now obviously normally the hMainThreadSuspended needs to get satisfied, we're not keen on a handshake error. If the wait times out (return value is WAIT_TIMEOUT=102h) then a Wakeup-call to the Monitor in the kernel, which is responsible for the V86 execution of the program is being sent via NtVdmControl and then there is another Wait for 60 seconds (927C0h) this time. This gives us a clue where to search for where the necessary condition is being set: Code:
ntvdm!cpu_simulate: 0e4d3148 8bff mov edi,edi 0e4d314a 55 push ebp 0e4d314b 8bec mov ebp,esp 0e4d314d 51 push ecx 0e4d314e 64a118000000 mov eax,dword ptr fs:[00000018h] 0e4d3154 53 push ebx 0e4d3155 a32ce0530e mov dword ptr [ntvdm!CurrentMonitorTeb (0e53e02c)],eax 0e4d315a 64a118000000 mov eax,dword ptr fs:[00000018h] 0e4d3160 56 push esi 0e4d3161 8bb0180f0000 mov esi,dword ptr [eax+0F18h] 0e4d3167 33db xor ebx,ebx 0e4d3169 57 push edi 0e4d316a bf00020000 mov edi,200h 0e4d316f 3bf3 cmp esi,ebx 0e4d3171 0f846a010000 je ntvdm!cpu_simulate+0x199 (0e4d32e1) 0e4d3177 8d8674060000 lea eax,[esi+674h] 0e4d317d c60001 mov byte ptr [eax],1 0e4d3180 c786d802000007000100 mov dword ptr [esi+2D8h],10007h 0e4d318a 3818 cmp byte ptr [eax],bl 0e4d318c 0f8448010000 je ntvdm!cpu_simulate+0x192 (0e4d32da) 0e4d3192 f6051407000003 test byte ptr ds:[714h],3 0e4d3199 7405 je ntvdm!cpu_simulate+0x58 (0e4d31a0) 0e4d319b e87b090000 call ntvdm!DispatchInterrupts (0e4d3b1b) 0e4d31a0 e8aef6ffff call ntvdm!getMSW (0e4d2853) 0e4d31a5 a801 test al,1 0e4d31a7 7456 je ntvdm!cpu_simulate+0xb7 (0e4d31ff) 0e4d31a9 391d54df500e cmp dword ptr [ntvdm!VDMForWOW (0e50df54)],ebx 0e4d31af 7524 jne ntvdm!cpu_simulate+0x8d (0e4d31d5) 0e4d31b1 e843f6ffff call ntvdm!getIF (0e4d27f9) 0e4d31b6 85c0 test eax,eax 0e4d31b8 751b jne ntvdm!cpu_simulate+0x8d (0e4d31d5) 0e4d31ba 81ff00020000 cmp edi,200h 0e4d31c0 7513 jne ntvdm!cpu_simulate+0x8d (0e4d31d5) 0e4d31c2 8d45fc lea eax,[ebp-4] 0e4d31c5 50 push eax 0e4d31c6 6a0d push 0Dh 0e4d31c8 c745fc03000000 mov dword ptr [ebp-4],3 0e4d31cf ff159814490e call dword ptr [ntvdm!_imp__NtVdmControl (0e491498)] 0e4d31d5 81a698030000fffffdff and dword ptr [esi+398h],0FFFDFFFFh 0e4d31df 391dc42d510e cmp dword ptr [ntvdm!HandshakeInProgress (0e512dc4)],ebx ; BINGO #1! 0e4d31e5 740b je ntvdm!cpu_simulate+0xaa (0e4d31f2) 0e4d31e7 ff35a4d4530e push dword ptr [ntvdm!hMainThreadSuspended (0e53d4a4)] ; Our wait condition 0e4d31ed e804ffffff call ntvdm!CheckScreenSwitchRequest (0e4d30f6) ; Aha, what's that? 0e4d31f2 881d3865500e mov byte ptr [ntvdm!MainThreadInMonitor (0e506538)],bl 0e4d31f8 e84f160000 call ntvdm!FastEnterPm (0e4d484c) 0e4d31fd eb2b jmp ntvdm!cpu_simulate+0xe2 (0e4d322a) 0e4d31ff 818e9803000000000200 or dword ptr [esi+398h],20000h 0e4d3209 391dc42d510e cmp dword ptr [ntvdm!HandshakeInProgress (0e512dc4)],ebx ... of the NTVDM, which is the trap handler for V86 execution. Code:
ntvdm!CheckScreenSwitchRequest: 0e4d30f6 8bff mov edi,edi 0e4d30f8 55 push ebp 0e4d30f9 8bec mov ebp,esp 0e4d30fb 56 push esi 0e4d30fc 8b357811490e mov esi,dword ptr [ntvdm!_imp__WaitForSingleObject (0e491178)] 0e4d3102 57 push edi 0e4d3103 6a00 push 0 0e4d3105 ff35acd4530e push dword ptr [ntvdm!hSuspend (0e53d4ac)] 0e4d310b ffd6 call esi 0e4d310d 8b3db011490e mov edi,dword ptr [ntvdm!_imp__ResetEvent (0e4911b0)] 0e4d3113 eb1f jmp ntvdm!CheckScreenSwitchRequest+0x3e (0e4d3134) 0e4d3115 ff157411490e call dword ptr [ntvdm!_imp__SetEvent (0e491174)] 0e4d311b 6aff push 0FFFFFFFFh 0e4d311d ff35b4d4530e push dword ptr [ntvdm!hResume (0e53d4b4)] 0e4d3123 ffd6 call esi 0e4d3125 ff7508 push dword ptr [ebp+8] 0e4d3128 ffd7 call edi 0e4d312a 6a00 push 0 0e4d312c ff35acd4530e push dword ptr [ntvdm!hSuspend (0e53d4ac)] 0e4d3132 ffd6 call esi 0e4d3134 ff7508 push dword ptr [ebp+8] 0e4d3137 85c0 test eax,eax 0e4d3139 74da je ntvdm!CheckScreenSwitchRequest+0x1f (0e4d3115) 0e4d313b ffd7 call edi 0e4d313d 5f pop edi 0e4d313e 5e pop esi 0e4d313f 5d pop ebp 0e4d3140 c20400 ret 4 NTVDM is assuming that the hosted DOS application generates some traps that cause it to return to the cpu_simulate thread which in turn checks for HandshakeInProgress in multiple places. If the is is set, it suspends execution of the DOS application and the signals success by setting the hMainThreadSuspended event which in turn releases the Wait-condition in DoHandshake and let it continue its screen switch routine. After that the main thread can be resumed and DOS-application is happy to continue its execution. But if the application like DBASE isn't doing any traps, the Wait-call runs into its 5 second timeout and this causes it to finally wake up the V86 MONITOR in kernel via NtVdmControl syscall and then finally the event gets trapped and everything continues as expected. Now why didn't this occur i.e. in the Windows XP version of NTVDM? When looking at the DoHandshake() code in there, it just does a normal SuspendThread(MainThread); in there and everything is working flawlessly. Why M$ decided to change this behaviour is unknown to me, I guess only their architects can tell us. So this time, it's not a bug, but I think the timeout of 5 seconds is a bad choice and a bit too high and therefore causes annoyance to the user. So let's change it to another value, i.e. 500ms which looks fair considered the fact that there is a wakeup-call to the Monitor in case of timeout anyway: Search for Code:
68 88 13 00 00 53 8D 45 DC 50 Code:
68 F4 01 00 00 ... When patching ntvdm in Windows\System32 directory, ensure that you have permissions to do so, so doing Code:
takeown /f ntvdm.exe icacls ntvdm.exe /grant [your username]:F Of course, you can also use a little patcher that I wrote for your convenience: Just run ntvdm_pat.exe to patch your Windows 7 NTVDM to 500ms timeout. If you want to use a different timeout value, please pass the desired value to it on the command line, i.e. if you want to use 200ms timeout, run: Code:
ntvdm_pat 200 for whatever reason cannot stick with Windows XP (i.e. because of a lack of drivers). Direct download: http://www.waldbauer.com/tmp/dl.php?download=ntvdmpatch |
|
|
|
|
|
#6 |
|
Moderator
|
NTVDM fullscreen and startup issue with VGA BIOS of Intel video cards
What is it
---------- Short version: A patch that fixes a glitch in the BIOS of some Intel VGA onboard graphics adapters (i.e. 4010U, 4340 i3 and 4200U i5, 4600...) that cause NTVDM startup to be delayed for 5-10 seconds and also causes slow text output and other INT10h operations (1char / second) in fullscreen mode. Long version: Recently I bought a new Mainboard with an Intel 4600 Onboard Graphics adapter card. When starting the NTVDM on this machine, I encountered a 5-10 second delay on NTVDM startup. But that wasn't all, things got even worse when trying to switch to Textmode Fullscreen. The character output was 1 char/second, which is obviously an unacceptable speed. So I researched the Internet and found 2 threads in the product forums of Microsoft and Intel: https://social.technet.microsoft.com...itproappcompat http://communities.intel.com/message/234383 Microsoft didn't care to answer to the problem at all and in Intel forums someone from Intel just answered that their boards were not tested for 16bit compatibility and therefore they don't care about the problem (which I cannot really believe, as if that would be true, text output in BIOS or Linux console would also not work properly). Some people in the Intel-forum reported that they now had to order a bunch of new graphics cards just because of this bug! The sheer ignorance of both companies regarding this problem really upset me and so it was my turn to investigate the problem and fix it, like many times before ![]() First, I needed to find out whom to blame for this mess. Intel or Microsoft? Interestingly, they are both to blame in a certain way, but a problem with NTVDM suprisingly is even benifical for solving the Intel video BIOS bug. Sounds a bit confusing? You can read more in the technical details below. Microsoft's fault is to not implement IN/OUT on 32bit Ports in NTVDM. But even if that had been implemented, Intel's BIOS wouldn't work properly, it would even cause more problems. Intel on the other hand expects MMIO ports to be accessinble which isn't the cause in a V86 environment like the NTVDM. Therefore it runs in a 1 second timeout on every operation, even though it seems to work fine without using these MMIO-Ports. So their fault is to try MMIO access for 1 second each time instead of just skipping over it if it fails for unknown reasons. The problem in fact can be solved by jumping over the check routine, which is just 1 byte to patch in the Video BIOS. Fortunately the NTVDM mapping of the BIOS address space can be patched in memory via a NTVDM extension DLL, so that you don't need to reflash your VGA BIOS. System Requirements ------------------- Should work on any Windows-PC with affected Intel Onboard Graphics board and NTVDM. How to Install -------------- Go to the bin-Directory, right click on intelvidfix.inf and click install. How to Uninstall ---------------- Open command shell as Administrator (rightclick on Command Prompt in Start/Programs/Accessories, Run as Administrator) Go to bin directory and then: Code:
RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection DefaultUninstall 132 intelvidfix.inf ----------------- Now how did I find out what was going on here? Obviously it was a problem with the Video BIOS, as the real Video BIOS only gets executed when the DOS application is running in full screen mode, otherwise it just BOPs to the VGA emulation of the NTVDM for windowed mode. So we know that INT 10h is responsible for doing Video IO. Therefore I traced through a simple call to INT10h for outputting a character with the excellent DEBUGX.COM utility from the FreeDOS project which in contrast to Microsoft's classic DEBUG.EXE also supports 32bit code like used in the Intel VGA BIOS and many new BIOSes lately. I cut out the register content view on places where it's not interesting for a better overview: Code:
-rx 386 regs on -a 1628:0100 mov ax, 0e20 1628:0103 -p DPMI entry hooked, new entry=0F61:02BC 1628:0103 0000 ADD [BX+SI],AL DS:0000=CD -t =C000:0014 1000 EAX=00000E20 EBX=00000000 ECX=00000000 EDX=00000000 ESP=0000FFFE EBP=00000000 ESI=00000000 EDI=00000000 EIP=000028E8 EFL=00033286 NV UP EI NG NZ NA PE NC DS=1628 ES=1628 SS=1628 CS=C000 FS=0000 GS=0000 C000:28E8 FB STI C000:28E9 FC CLD ....snip.... C000:28F9 8BEC MOV BP,SP C000:28FB E8F72E CALL 57F5 C000:57F9 66BE00540400 MOV ESI,00045400 C000:57FF E88211 CALL 6984 C000:6984 51 PUSH CX C000:6985 B502 MOV CH,02 C000:6987 6652 PUSH EDX C000:6989 6650 PUSH EAX C000:698B 2E8B161AE3 MOV DX,CS:[E31A] CS:E31A=F000 C000:6990 668BC6 MOV EAX,ESI C000:6993 8AC8 MOV CL,AL C000:6995 24FC AND AL,FC EAX=00045400 EBX=00000000 ECX=00000200 EDX=0000F000 ESP=0000FFCA EBP=0000FFE0 ESI=00045400 EDI=00000000 EIP=00006997 EFL=00033246 NV UP EI PL ZR NA PE NC DS=1628 ES=1628 SS=1628 CS=C000 FS=0000 GS=0000 C000:6997 66EF OUT DX,EAX ; Output 45400 on Port F000 EAX=00045400 EBX=00000000 ECX=00000200 EDX=0000F004 ESP=0000FFCA EBP=0000FFE0 ESI=00045400 EDI=00000000 EIP=0000699E EFL=00033246 NV UP EI PL ZR NA PE NC DS=1628 ES=1628 SS=1628 CS=C000 FS=0000 GS=0000 C000:699E 66ED IN EAX,DX ; Read from port F004 to EAX EAX=0004FFFF EBX=00000000 ECX=00000200 EDX=0000F004 ESP=0000FFCA EBP=0000FFE0 ESI=00045400 EDI=00000000 EIP=000069A3 EFL=00033246 NV UP EI PL ZR NA PE NC DS=1628 ES=1628 SS=1628 CS=C000 FS=0000 GS=0000 C000:69A3 C0E103 SHL CL,03 ; Intersting, only AX is filled C000:69A6 66D3E8 SHR EAX,CL ; and not entire EAX! So this C000:69A9 6692 XCHG EAX,EDX ; is the MS 32bit IO bug EAX=0000F004 EBX=00000000 ECX=00000200 EDX=0004FFFF ESP=0000FFCA EBP=0000FFE0 ESI=00045400 EDI=00000000 EIP=000069AB EFL=00033246 NV UP EI PL ZR NA PE NC DS=1628 ES=1628 SS=1628 CS=C000 FS=0000 GS=0000 C000:69AB 6658 POP EAX C000:69AD 8AC2 MOV AL,DL C000:69AF 80FD00 CMP CH,00 C000:69B2 740A JZ 69BE C000:69B4 8BC2 MOV AX,DX C000:69B6 80FD01 CMP CH,01 C000:69B9 7403 JZ 69BE C000:69BB 668BC2 MOV EAX,EDX C000:69BE 665A POP EDX C000:69C0 59 POP CX C000:69C1 C3 RET EAX=0004FFFF EBX=00000000 ECX=00000000 EDX=00000000 ESP=0000FFD6 EBP=0000FFE0 ESI=00045400 EDI=00000000 EIP=00005802 EFL=00033202 NV UP EI PL NZ NA PO NC DS=1628 ES=1628 SS=1628 CS=C000 FS=0000 GS=0000 C000:5802 6683F8FF CMP EAX,-01 ; Here it is compared with C000:5806 665E POP ESI ; FFFFFFFF, which fails and C000:5808 6658 POP EAX ; wouldn't fail if MS C000:580A C3 RET ; implemented 32bit IO support C000:28FE 0F848E00 JZ 2990 ; So no jump here, instead it C000:2902 E81E0B CALL 3423 ; continues.... ...snip... C000:343C E89D38 CALL 6CDC ; Not so important for us C000:343F B9E803 MOV CX,03E8 ; Init loop counter with 1000! C000:3442 E83F35 CALL 6984 ; we already know function 6984 EAX=0004FFFF EBX=00000000 ECX=000003E8 EDX=80000000 ESP=0000FFD0 EBP=0000FFE0 ESI=00045400 EDI=00000000 EIP=00003445 EFL=00033202 NV UP EI PL NZ NA PO NC DS=1628 ES=1628 SS=1628 CS=C000 FS=0000 GS=0000 C000:3445 66A900000040 TEST EAX,40000000; High word remains 0004 C000:344B 750A JNZ 3457 ; So we don't get out of here C000:344D 51 PUSH CX ; until loop is over C000:344E B90100 MOV CX,0001 ; Sleep for 1ms C000:3451 E8842E CALL 62D8 ; Sleep routine C000:3454 59 POP CX EAX=0004FFFF EBX=00000000 ECX=000003E8 EDX=80000000 ESP=0000FFD0 EBP=0000FFE0 ESI=00045400 EDI=00000000 EIP=00003455 EFL=00033216 NV UP EI PL NZ AC PE NC DS=1628 ES=1628 SS=1628 CS=C000 FS=0000 GS=0000 C000:3455 E2EB LOOPW 3442 ; And it loops another 999 times ... According to 2nd Generation Intel Core Processor Family Desktop Datasheet, Vol. 2 - Section: Device 2 I/O Registers: F000 is the MMIO Address Register F004 is the MMIO Data Register They are specific for the Intel-Board and are not available to our NTVDM emulation and therefore cannot be accessed, always returning FF on read. Now first thing that comes to our mind when just seeing the loop that loops for 1000 times is why the VGA BIOS is assuming that these non-Standard I/O ports are there and causing a loop for 1000 iterations for every read attempt. That doesn't look very smart and is the cause for the huge delay. But then we can see that it's actually checked above if these ports are there and if not (so if EAX is FFFFFFFF), they are not used and code should jump over. This should theoretically be the case, except that the IN to the EAX register just fills the lower AX register and leaves the high word of the register untouched. So this leads us to believe that this is a NTVDM problem and not a BIOS bug. When digging through the NTVDM, it can be seen that they just didn't implement IN/OUT for 32bit registers but just 8 and 16 bit. I even made a patch for NTVDM to support 32bit IN/OUT (yes, it's possible to patch it in order to do so, if you are interested in the patch, just contact me), but then I realized that this maked things even worse. Why? Because of the destination of the Jump, if the check for FFFFFFFF succeeds: Code:
C000:28FE 0F848E00 JZ 2990 do anything at all! From testing the application in fulscreen operation, I was able to see that it currently does its operations very slowly, but it does them fine. So the correct way to fix this problem is not to teach NTVDM how to handle 32bit IN/OUT port access, but instead just JMP out of the loop with the 1000 iterations and tadaa - Startup delay of NTVDM is gone and fullscreen operations work normally! So we just change: Code:
C000:344B 750A JNZ 3457 Code:
C000:344B EB0A JMP 3457 VDD (Virtual Device Driver) for NTVDM. Memory for the VGA BIOS is mapped at address C0000 in process address space and is mapped R/W, so DLL can access memory there and just change 75 to EB and done. So I don't know if the address layout of all the Intel VGA BIOSses is the same as mine, I also impemented a pattern matching scan that searches the VGA BIOS area for the asm code ocmbination at this place and tries to patch it if pattern is found. I don't know every Intel VGA BIOS, I just had the one from my card, but for this it worked fine. If it doesn't fix it for your card, just send me an e-mail and I will give you instructions how to dump your VGA BIOS so that I can analyze it and update my patcher to also work with your VGA BIOS version. For further information, just contact me. Direct download (no registration needed) -> http://www.waldbauer.com/tmp/dl.php?...ad=intelvidfix |
|
|
|
|
|
#7 |
|
Moderator
|
NTVDM mode switching bug in some NVIDIA GEFORCE VGA BIOSses
#unhide (This post can be viewed by guests also)
First of all, please check if this doesn't remedy your problem: http://www.volny.cz/martin.sulak/ Download-Link for the driver: http://web.archive.org/web/200512240...k/videoprt.zip Only use my workaround if this drivers doesn't work for you like it finally did for me! My patch only makes textmodes work whereas above mentioned patch should also enable other video modes, as it fixes the root cause of the problem. What is it ---------- Short version: A patch that fixes a problem with some Video BIOSses on textmode switching (INT 10h Function 0) when running in the Windows NTVDM on fullscreen (this also affects Windows XP NTVDM!). Long version: Some years ago I bought a NVIDIA GEFORCE PCIE Graphics card that supported VGA, SVIDEO and DVI output, as I needed all of them. The card worked fine except for one strange behaviour: When I tried to start a DOS application in fullscreen, it immediately crashed back to Windows. And when starting a DOS application from a fullscreen console, the screen just went blank and the application seemed to be stuck. I was able go back to windowed mode with ALT+RETURN, but then the application that I started had quit. When attaching a debugger to the NTVDM, I saw that the VGA BIOS code crashed on mode change! As this seems to be a generic problem with various NVIDIA GEFORCE BIOSses I decided to fix this by writing a TSR that hooks INT 10h function 0 and does the classic port I/O necessary to do a mode transition at least in text modes 2 and 3, which are most common for textmode applications. This lets me run textmode applications on cards with the flawed VGA BIOSses again and may be useful for other users experiencing the same issues on their graphic cards. System Requirements ------------------- Should work on any Windows-PC with affected Graphics board and NTVDM. How to Install -------------- 1) Copy FIXTMODE.COM from the bin directory to your Windows\SYSTEM32 directory 2) Edit AUTOEXEC.NT in your Windows\system32 directory and add the command Code:
LH FIXTMODE How to Uninstall ---------------- Edit AUTOEXEC.NT in your windows\system32 directory and remove FIXTMODE command. If you want, you can also delete FIXTMODE.COM from your system32 directory again. Compiling --------- The Assembler sourcecode of the utilities is in the SRC directory. You can compile them using Borland Turbo Assembler (TASM) with: Code:
TASM FIXTMODE TLINK /t FIXTMODE ----------------- The installation of the INT10h handler is a bit of a problem, because it cannot "forward" the Mode switch commands down the chain as this would call original Video BIOS which crashes. Normaly we would just install ourselves as INT10 handler BUT NTVDM works windowed and fullscreen. Therefore it has its own INT10h dispatcher which should be called and in turn calls Video BIOS. So we have to update its pointer to Video BIOS function in order to not mess up windowed operation of NTVDM. In my copies of NTDOS.SYS in XP, there is a JMP (EA) at ES:951 to the original video BIOS. In Windows 7, it'S at ES:969. In case it's not changed, in subsequent versions of NTVDM, we can overwrite it. The code has a fallback to do a INT 10h hook if it fails to find the address at the specified offsets so that it still works at least, but windowed operation is flawed then. If this is the case, please report this to me and which version of NTDOS.SYS you are using. One interesting thing to also note is that we don't need to waste memory for the tables with the VGA controller settings to be used to switch to textmodes 2 and 3 as these tables are already present in memory at the beginning of the NTDOS segment. It's called "baby mode table" and is used internally by the NTVDM on startup to do basic initialization. So the TSR tries to determine the correct segment by reading INT 16h handler assuming that it still points to the correct segment of NTDOS.SYS. That's why it is important to place it very early in AUTOEXEC.NT before other TSRs are loaded that may hook INT 16h. For more details, just have a look at the sourcecode, it is well documented and should be self-explanatory. For further information, just contact me. You can download this patch also as unregistered User: http://www.waldbauer.com/tmp/dl.php?download=fixtmode |
|
|
|
|
|
#8 |
|
Moderator
|
NTVDM Helper to enable Fullscreen operation with WDDM display driver
#unhide (This post can be viewed by guests also)
What is it ---------- Short version: A package that enables you to switch between Windowed and Fullscreen mode in a console in Windows 7 like it used to be in Windows XP, even though you are using a WDDM display driver. Long version: You may already know that ALT+Enter is a commonly used hotkey to switch application between window mode and full-screen mode. For the cmd prompt, the hotkey should work as expected on prior windows OS up to windows XP and for example enters real text mode for DOS applications. But for Windows Vista and Windows 7, cmd can't be switched to full-screen mode, this is by design. For further information see http://support.microsoft.com/kb/926657 There is a very interesting article explaining the rasons behind this: https://colinxu.wordpress.com/2011/0...ssue-analysis/ Now it's also known and explained in the KB-Article, that you can get back fullscreen with either a XPDM-driver for the Windows XP display driver model or to switch back to the default VGA video driver, which still supports the old driver model. Now the problem with a XPDM Display driver for Windows 7 is that it doesn't support video accelleration on Windows 7, i.e. Window movement or scrolling through websites in your browser can be a bit stuttering which isn't a nice user experience. As expained in the document of my CONHOST-Patch, Windows 7 thankfully has the ability to enable and disable an active Video driver on-the-fly. When disabling the WDDM driver, you fall back to the dafault Standard VGA display driver which supports fullscreen textmode. I presented a method that uses the utility DEVCON to disable and re-enable the WDDM diplay driver in a batch file. While this method works, it is a bit annoying to use, as one would have to create a startup batchfile for every application that should work with fullscreen. Additionally the "Start as fullscreen" in the PIF file still doesn't work and you don't have the ability to switch from a windowed session to fullscreen on-the-fly, like it used to be in Windows XP. Additionally you need administrative rights to get the fullscreen switching to occur. Running as Administrator gives you another environment than running as user. And finally, you may also want your Win32 console in fullscreen, not only DOS-applications. So I had the idea to automate these tasks when either pressing ALT+ENTER or when a console window wants so switch to fullscreen mode. How it works ------------ The package is divided into multiple components: * fullscrswitch service (with .dll file for eventlog messages) * conhostfldr loader process, which is used in each session to inject the conhostf.dll into the CONHOST.EXE process * The conhostd.dll library which operates inside CONHOST.EXE process to patch it accordingly for fullscreen operation and communicate with the service. First of all, disabling the WDDM driver is a privileged operation, so administrative privileges are necessary for this. Therefore it made sense to move this functionality to a Windows-service which runs in the privileged context of the SYSTEM-user. The service exposes its driver disable/enable services via a service control code and also via a named pipe (.\pipe\fullscrswitch). It is desirable that the WDDM driver stays disabled after switching around between desktop and fullscreen console until all console windows that use Fullscreen have closed. When all windows get closed (i.e. due to an exit of the DOS application or the user just closing the console window), the driver switches back to the accellerated WDDM graphics mode. So as long as you use Textmode fullscreen actively, you are limited to the XPDM VGA driver and as soon as you do not need it anymore, you get back your accelerated WDDM driver. Due to the architecture of the new Windows console, every console has a CONHOST.EXE process attached to it. So the fullscreen service has to inject some loader code into every new CONHOST.EXE process in order to capture ALT+RETURN keypresses or fullscreen switch requests, then register the CONHOST.EXE process PID with the fullscreen switching service and perform the WDDM driver disable task. This is done by sending the PID of the CONHOST.EXE process to the named pipe. The service registers the PID of the CONHOST in an internal list and then waits on the process handle, until it gets signalled, which is the case when the process terminates. As soon as all processes that registered with the fullscreen switching service terminated, it is safe to switch back to the WDDM driver, as there are no more processes depending fullscreen operation. The service writes back a BOOL TRUE on the named pipe to the caller in order to signal that disabling driver succeeded and it can continue its operation with fullscreen capabilities available now. Now there needs to be a way to inject the conhostf.dll library into each CONHOST.EXE process so that it can communicate with the service when needed and modify its behaviour so that Fullscreen support gets available again. For this, there is a nice facility in Windows: WinEvent hooks that get called on various events, i.e. also console events. So you can get notified when i.e. a new console application is starting. Additionally you have the opportunity to get injected into the target process (to do the patching), which is exactly what is needed. Unfortunately there needs to be a "host" application that contains the DLL to be injected which also needs to have a running message pump. This is only possible in the context of the user that is currently connected to the console. As this is not possibe for a System service, a helper process is needed which is called conhostfldr.exe that does the injection and acts as a container for the loader DLL to be injected into CONHOST process. This process needs high privileges in context of the user so that the target DLL can also be injected into elevated console windows. The service registers for logon/logoff notifications and therefore gets notified when a user connects to the physical console. If the session currently doesn't have the loader process running, it tries to start it in the context of the user of the respective console session. It keeps an internal list of the running instances and sessions. When a user logs off or the service has to terminate, the loader process for the sessions need to be terminated and the hook DLL needs to get unregistered. To do this, and also to prevent being launched twice within a session, the loader creates an Event named "conhostfldr" and checks for it in its main message loop. As soon as this event gets signalled, it terminates. As the events are unique per session, the service is able to find the event in the \Sessions namespace for the respective session and can set the event causing the loader process to terminate properly and unregister the hook libraray from the console window. The injected library needs to adjust some internal functions of CONHOST. As symbols and locations for these functions are not public, it is using Microsoft Symbol Server to resolve them by name. Symbol Server keeps debug information for every version of Microsoft libraries and can download the appropriate symbol file via the Internet (there are plenty of CONHOST.EXE releases for Windows 7 with different offsets each, therefore this seems to be the only viable solution). One problem is that conhost.exe checks for a fullscreen capable VGA display driver during startup in internal function InitializeFullScreen(). Now if you start up a console with WDDM driver enabled the appropriate values are no initalized. When you start a DOS application in console, the NTVDM registers itself with a call to RegisterConsoleVDM() also supplying event handles to events that are needed during Fullscreen negotiation. Unfortunately the conhost.exe server part of this function ignores these handles if the fullscreen flag (0x10000000) is not set in gConsoleInformation.Flags. This flag normally gets set after successful fullscreen initialization in InitializeFullScreen() function. Now if you fake fullscreen initiaization, RegisterConsoleVDM saves the handles, but it also requests the size of the state buffer from the VGA driver with a call to GDI function GdiFullscreenControl(FullscreenControlRegisterVdm, ...). As at this time there is no VGA driver available, the function then fails preventing a startup of the DOS application. Fortunately, the value it requests there is always static for VGA cards, so the loader DLL can simply hook the GdiFullscreenControl function and fake the return value. Then the loader can pretend that fullscreen is available during console startup by setting above mentioned flag. If the user then really requests fullscreen operation, InitializeFullScreen() can be called after disabling the WDDM driver as at this point the function will then succeed ensuring correct operation. The hook DLL has to monitor SrvSetConsoleDisplayMode call to check for CONSOLE_FULLSCREEN_MODE call and the console window procedure to check for ALT+RETURN keypress and then disable WDDM driver accordingly. With all these 3 components in place, fullscreen switching should work. Of course, it's not as fast as on Windows XP, because there is overhead for disabling the driver, so if you can, using Windows XP is still the preferred method, but with this patch you can at least partly restore some of the lost functionality. Prerequestites -------------- All patches can be downloaded at http://www.waldbauer.com/tmp/reference.php * CONHOST patch The CONHOST.EXE on Windows 7 has a severe bug that causes it to hang on switching back from Fullscreen mode to desktop. This patch fixes it. * NTVDM transition timeout patch There is a very large timeout of 5 seconds when switching back from fullscreen to windowed mode. This is annoying, so with this patch you can reduce this waiting time that occurs with some DOS applications. Conditional prerequesites ------------------------- If you have an Intel I3 or newer onboard graphics adapter and you experience a startup delay from 5-10 seconds while starting a DOS-application, there may be problem with the BIOS of the Intel graphics adapter and you may need the * NTVDM (Intel VGA BIOS patch) If the video BIOS crashes on fullscreen or on mode switch, it is very likely that the standard VGA driver doesn't know about the ports that your video BIOS needs to route through to the NTVDM. This is recommended for example for NVIDIA cards. In this case, you can try this driver: * http://www.rayer.g6.cz/download/videoprt.zip If the driver above doesn't help or work and you have problems on video mode switch of text modes, you can try this patch: * NTVDM (NVIDIA GEFORCE VGA BIOS patch) Recommended patches to enhance your DOS experience -------------------------------------------------- Is Windows 7 doesn't work correctly with the PC speaker and instead outputs BEEPS via the sine wave usermode beep agent, get back the real PC speaker support with the * BEEPx (SPKRFIX 32 bit) The AltGR-Key is not handled correctly in NTVDM on Windows Vista or above, so you need to install the * ALTGR IAT FILTER HOOK Then you can use the normal KB16.COM keyboard driver which you can add to your AUTOEXEC.NT file in the SYSTEM32 Windows directory. System Requirements ------------------- Should work on any Windows 7 32bit machine. It is advisable to have a running Internet connection on the first launch of a console window on the patched system to enable symbol server fetching the symbols required for proper operation of the patch. As soon as the symbols got fetched, you don't need Internet connection anymore unless you update your CONHOST.EXE process, i.e. by Windows update, in which case the patcher will try to fetch the symbols again automatically. How to Install -------------- The installation doesn't work from a Network path, you need to run it from a local directory. You need administrtive privileges to install. 1) Right-click on the conhostf.inf file in the bin\fullscrswitch subdirectory and choose "Install". If it works correctly, some files would have been copied and a new service named fullscrswitch is started. 2) This step is not absolutely necessary and has the drawback of using more diskspace than necessary, so this is optional: Normally the loader tries to fetch the CONHOST.EXE symbols that it needs for operation from Microsoft Symbol Server on first run, but lately the symbols server sometimes is a bit unstable and fails to deliver the files just in time. So you can optionally install all the conhost.exe symbols that I know (which may not match your conhost.exe, but you can give it a try anyway). In case you want to install all the symbol files, just run opt\install.bat and check if it copied the files successfully. Now you can try to open a new console and see if ALT+RETURN works for switching to fullscreen. If the console hangs some time on first start, it tries to fetch the symbols from symbol server. If it fails, it gives up after some time and you get your console, but ALT+RETURN is not working. So as long as there is some freeze on opening a new console, it tries to fetch the symbols and you should try opening a new console (after freeze times out) as long as this delay is still there. If it doesn't work afterwards (even though it opens up fast), try to reboot the machine once so that it gets ensured that the conhostdfldr.exe process gets started correctly by the fullscrswitch service (you can check with task manager). If everything works fine, you should also be able to start your DOS applications directly in fullscreen again. However be aware that there are some conditions where it may hang your graphics card (also depends a bit on your WDDM driver and how stable it is). For example do not try to launch a DOS application fullscreen that immediately exits, because the fast switching of the VGA driver may cause a lockup. So when experimenting with it, be prepared that you may need to reboot your machine if something goes wrong. There also is a nasty issue with some Intel Onboard video drivers that causes the disabling of the driver (to enable VGA) to block for approx. 10 seconds every second time you try, as it seems. I haven't analyzed this bug in the Intel video driver yet as it seems to occur only with this cheap onboard stuff (where you also need the Intel video fix patch from above). So if possible better use a dedicated card. As debugging kernel drivers is not so easy I don't know it if it's worth the hassle, using a dedicated Graphics card is better anyway. If this is really the only adapter you can use, maybe we can find a fix for it together with Intel, just contact me. When you use it and it switches to VGA mode, you may be set back to 640x480 resolution when you go back to the desktop, which is quite unpleasant. Just use properties of display and switch to the maximum available resolution that works with your monitor and VGA driver supports (i.e. if possible the same resolution as with your normal video adapter driver) to get back normal screen resolution in this mode. Windows will remember the settings on next mode switch. How to Uninstall ---------------- Go to control panel, Add/Remove programs and remove "Console Fullscreen Patch". Alternatively, you can run the following command on elevated command prompt: Code:
RunDll32 setupapi.dll,InstallHinfSection DefaultUninstall 132 conhostf.Inf |
|
|
|
|
|
#9 |
|
Registrierter Benutzer
|
Hi
I have a problem that is somewhat similar in that I also have a computer with Intel integrated graphic. It's a Zotac ZBOX with Intel Celeron N3050 and Intel Graphics with PCI Id 8086:22B1. I can confirm that text output in real mode during booting is really slow, although that is not the problem. I did a fresh install of Windows 7. When I start any program that needs DOS mode, NTVDM starts and uses 100% of one CPU core. It happens with every program, like command.com. This is not just a 10 second delay, I waited for more that 45 minutes and nothing happens. This happens in window mode and even with remote desktop. When I try to switch to fullscreen, I get the message that fullscreen is not supported by the system. It also happened before and after I installed the driver for the Intel graphics. I tried the utilities from this thread, but without success. conhost_pat says "cannot open file for writing", but Process Monitor doesn't show that it tries to open any file. The others seem fine but don't change anything. Do you have and additional hints what I can try? |
|
|
|
|
|
#10 |
|
Moderator
|
Hi,
Conhost outputs this error if it cannot open the file. Did you ensure that you closed all console windows before patching and also eliminated every running conhost.exe process in the system before patching? If your BIOS has a flaw, you will need to debug it like I described in my VGA BIOS patch. Step through the assembly code and see where it loops. Maybe you can identify the flaw. Theoretically if could be possible that it is related to the requirement of 32bit I/O which NTVDM isn't normally capable of. You would also see this in the debugger (look for IN/OUT on 32bit registers like EAX, EBX....). If this is the case, I can provide you a patch that enables 32bit I/O in NTVDM. I can't do analysis here, as I don't have a machine with this flaw to debug. I could take a quick look at your machine i.e. via Teamviewer, if I can find something, I MAY be able to do a raw cost estimation after having a look at it for approx. one hour, if I find a hint. As I don't have such a machine here, you can either send me a machine with this hardware and I send it back after checking it, or you will have to provide access to the machine while I work on it, which means that you may not be able to use it for a few evenings. That's all I can offer you so far. |
|
|
|
Antwort schreiben... |
| Themen-Optionen | Thema durchsuchen |
|
|
Ähnliche Themen
|
||||
| Thema | Autor | Forum | Antworten | Letzter Beitrag |
| OA4QRY.DLL API Dokumentation & Beispiele | waldbauer.com | SPI OA4 Open Access II/III/IV (2,3,4) Anwender Forum | 2 | 07.06.2008 14:57 |