Antwort schreiben...
 
Themen-Optionen Thema durchsuchen
Alt 08.10.2009, 17:05   #1
waldbauer.com
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
waldbauer.com ist offline   Mit Zitat antworten
Alt 20.11.2009, 10:06   #2
waldbauer.com
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....
waldbauer.com ist offline   Mit Zitat antworten
Alt 24.11.2009, 23:06   #3
leecher
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
Sonst hilft wohl nur Beschwerdemail an M$ schreiben, warum sie immer alles kaputt machen müssen oder einen eignenen DOS-Emulationslayer wie DosBox verwenden. Andernfalls muss man leider mit dem Problem leben, wenn man unbedingt mit Windows >XP arbeiten will
leecher ist offline   Mit Zitat antworten
Alt 31.08.2014, 22:29   #4
leecher
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
As you can see, there is a section for Win7 (IntelGfx.NTx86.6.0), but
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!"
endlocal
------------------------------------------------------------------------------
You 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])
The last thread is interesting to us, it hangs at GetConsoleScreenBufferInfo
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])
Seems like both threads have a deadlock condition, so time to take a closer
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
So there is a global Critical section object for the lock.
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
Now let's have a look at ConsoleWindowProc, which is calling DisplayModeTransition:

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]
So the global lock is being held by ConsoleWindowProc when calling
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
...
As the function is quite long and a bit complicated, let me wrap this up for you as
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;
First thing to notice: As seen above, RevalidateConsole always returns
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;
So gConsoleInformation.RecursionCount gets returned and if there are
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
So it calls LockConsole for the given number of recursions, unless it's
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);
To see how this can be accomplished, have a look at how this Sequence
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
Now let's also have a look at the other places in the code, that call
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
It can be seen that the code for calling it is always the same.
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
Now the CALLs to Wait function get substituted like this:

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
Same here:

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
So finally this is now fixed, as M$ doesn't seem to care.
Btw.: CONHOST issues some debug messages, if you attached a kernel debugger,
you can use the command

Code:
 ed Kd_USERGDI_MASK ff
to enable tracing these messages.

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
A lot of compares in there! We know from the stack trace above that it hits
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     ebx
The function should hit 0e5e23b6, but it never does.
Let's have a look at some pseudocode again:

Code:
if (dw0e722b7c || dw0e72c4f0 != dw0e722b78 || dw0e722b60 != edi || dw0e722b70 != esi)
{
  ...
  textResize();
}
So it seems, that everything is equal already (text size already calcualted?)
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
So that's the reason for this. From my point of view, it's still the fault of
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?
Angehängte Dateien
Dateityp: zip conhost_pat.zip‎ (4.0 KB, 17x aufgerufen)
Dateityp: exe fullscr.exe‎ (1.0 KB, 11x aufgerufen)

Geändert von leecher (10.11.2016 um 01:16 Uhr) Grund: Added reference to automatic fullscreen switcher
leecher ist offline   Mit Zitat antworten
Alt 02.10.2016, 13:24   #5
leecher
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])
So it's stuck at the first WaitForMultipleObjects call in ntvdm!DoHandShake:

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)
...
As can be seen, there are 2 handles being waited on:
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
...
So there are multiple calls to ntvdm!CheckScreenSwitchRequest in cpu_simulate
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
So we finally get the idea what is going on here:
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
in NTVDM and replace it with i.e.:

Code:
  68 F4 01 00 00 ...
for 500ms.
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
before.
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
This should fix another annoying behaviour of Windows 7 NTVDM for people who
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
Angehängte Dateien
Dateityp: zip ntvdm_pat.zip‎ (8.8 KB, 9x aufgerufen)
leecher ist offline   Mit Zitat antworten
Alt 15.10.2016, 11:36   #6
leecher
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
Technical details
-----------------
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
...
So first of all, what is this dubois Port at F000?
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
This jumps to the END of the interrupt routine so in this case it doesn't
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
to

Code:
C000:344B EB0A              JMP     3457
In order to accomplish this, a litte DLL is generated that is loaded as a
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
Angehängte Dateien
Dateityp: zip intelvidfix.zip‎ (11.1 KB, 44x aufgerufen)
leecher ist offline   Mit Zitat antworten
Alt 17.10.2016, 00:23   #7
leecher
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
very early in the file so that it gets loaded before other applications.

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
Technical details
-----------------
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
Angehängte Dateien
Dateityp: zip fixtmode.zip‎ (6.3 KB, 13x aufgerufen)
leecher ist offline   Mit Zitat antworten
Alt 10.11.2016, 01:14   #8
leecher
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
For further information, just contact me.
Angehängte Dateien
Dateityp: zip conhostf.zip‎ (1.38 MB, 14x aufgerufen)
leecher ist offline   Mit Zitat antworten
Alt 25.07.2017, 00:10   #9
RalfFriedl
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?
RalfFriedl ist offline   Mit Zitat antworten
Alt 26.07.2017, 20:57   #10
leecher
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.
leecher ist offline   Mit Zitat antworten


Antwort schreiben...

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche


Ä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