For the Nitpickers: Enhanced-mode Windows 3.0 didn’t exactly run a copy of standard-mode Windows inside the virtual machine


Generally speaking, Enhanced-mode Windows 3.0 ran a copy of standard-mode Windows inside the virtual machine. This statement isn’t exactly true, but it’s true enough.

Commenter Nitpicker objected, “Why are you threatening us with the Nitpicker’s Corner for asking about this issue instead of explaining it once and linking it everywhere?”

Okay, first of all, as far as I can tell, you’re the first person to ask about the issue. So you can’t say “Everybody who asks about the issue is threatened with the Nitpicker’s Corner” because up until you made your comment, nobody ever asked. Okay, well, technically you can say it, because every statement quantified over the empty set is true. But it is equally true that, at the time you made your comment, that “Everybody who asks about the issue is awarded a new car.” So it is not a meaningfully true statement.

I haven’t bothered explaining the issue because the issue has never been central to the main point of whatever article happens to bring it up. The statement is true enough for the purpose of discussion, and the various little corners in which the statement breaks down have no bearing on the original topic. Nitpickers would point out that you can’t combine velocities by simple addition because of the laws of Special Relativity. Even when the situation under discussion takes place at non-relativistic speeds.

As for the suggestion, “Explain it once and link it everywhere,” you’re assuming that I can even explain it once, that doing so is less work than just saying “not exactly true, but true enough,” and that I would enjoy explaining it in the first place.

If you don’t like it, you can ask for your money back.

Okay, I went back and dug through the old Windows 3.0 source code to answer this question. It took me about four hours to study it all, try to understand what the code was doing, and then distill the conclusions into this article. Writing up the results took another two hours. That’s six hours I could’ve spent doing something enjoyable.

The 16-bit Windows kernel was actually three kernels. One if you were using an 8086 processor, another if you were using an 80286 processor, and a third if you were using an 80386 processor. The 8086 kernel was a completely separate beast, but the 80286 and 80386 kernels shared a lot of code in common. The major difference between the 80286 and 80386 kernels was in how they managed memory, because the descriptor tables on the 80386 were a different format from the descriptor tables on the 80286. The 80386 memory manager could also take advantage of the new 32-bit registers.

But the difference between the 80286 and 80386 kernels were not based on whether you were running Standard or Enhanced mode. If you’re running on an 80386 processor, then you get the 80386 kernel, regardless of whether you’re using Standard or Enhanced mode Windows. And since Enhanced mode Windows required an 80386 processor, the behavioral changes between Standard and Enhanced mode were restricted to the 80386 kernel.

The 80386 kernel was designed to run as a DPMI client. It asked the DPMI host to take it into protected mode, then used the DPMI interface to do things like allocate selectors and allocate memory. If you ran Windows in Standard mode, then the DPMI host was a custom-built DOS extender that was created just for Standard mode Windows. If you ran Windows in Enhanced mode, then the DPMI host was the 32-bit virtual machine manager. Abstracting to the DPMI interface allowed a single 80386 kernel to run in both Standard and Enhanced modes.

And in fact if you ran Enhanced mode Windows with paging disabled, then the code running in the 80386 kernel was pretty much the same code that ran if you had run the 80386 kernel under Standard mode Windows.

One obvious place where the behavior changed was in the code to manage MS-DOS applications, because Enhanced mode Windows could multi-task MS-DOS applications, and Standard mode Windows could not.

Another place where the behavior changed was in in the code to allocate more selectors: The attempt to retry after extending the local descriptor table was skipped if you were running under the Standard mode DOS extender, because the Standard mode DOS extender didn’t support extending the local descriptor table.

And another difference is that the Windows idle loop in Enhanced mode would issue a special call to release its time slice to any multi-tasking MS-DOS applications. (If you were running in Standard mode, there were no multi-tasking MS-DOS applications, so there was nobody to release your time slice to.)

Another thing special that the 80386 kernel did was register with the virtual machine manager so that it could display an appropriate message when you pressed Ctrl+Alt+Del. For example, you saw this message if you hit Ctrl+Alt+Del while there was a hung Windows application:

Contoso Deluxe Music Composer


This Windows application has stopped responding to the system.

*  Press ESC to cancel and return to Windows.
*  Press ENTER to close this application that is not responding.
   You will lose any unsaved information in this application.
*  Press CTRL+ALT+DEL again to restart your computer. You will
   lose any unsaved information in all applications.

But all these differences are minor in the grand scheme of things. The window manager behaved the same in Standard mode and Enhanced mode. GDI behaved the same in Standard mode and Enhanced mode. Printer drivers behaved the same in Standard mode and Enhanced mode. Only the low-level kernel bits had to change behavior between Standard mode and Enhanced mode, and as you can see, even those behavior changes were relatively minor.

That’s why I said it was “true enough” that what was running inside the virtual machine was a copy of Standard-mode Windows.

Comments (45)
  1. pc says:

    I know you like putting on the air of being grumpy about it, but if you spent six hours researching for this blog post, you might have liked at least a little bit doing the exploration so that you can explain ancient Windows to us. We as readers certainly appreciate it.

    [The six hours was less annoying than having to deal with everybody who says "That's not true. Raymond, what's the REAL story? I demand to know!" -Raymond]
  2. SimonRev says:

    @pc — Raymond is just grumpy because he had to drive to Montanna, bully some security guards, go into a salt mine and read magnetic tape reels to get the code for this article. (see blogs.msdn.com/…/9915989.aspx)

  3. [The six hours was less annoying than having to deal with everybody who says "That's not true. Raymond, what's the REAL story? I demand to know!" -Raymond]

    This is Windows trutherism for you.

  4. Raymond, it appears that you're making a mildly contradictory statement here.  In the opening of today's post, you made of point of emphasizing that there were no people who had asked this quesiion before.  Now you claim that you spent six hours of your life in a way that you would rather not have, because it beats dealing "everyone" who asks for the real story.  There must be something I'm missing.  If you (or anyone) can tell me what it is, I'd be a happy camper.  (Just don't hours of your life on it.  Or even 10 minutes.  Seriously, this is your blog, not ours.  Please remember that above all else.)

    [It's perception bias. The question may not objectively have been asked that often, but it feels like it gets asked a lot because it gets asked each time I mention that "the same kernel runs in enhanced-mode Windows as standard-mode Windows" (which admittedly is not that often either). -Raymond]
  5. Joshua says:

    [And another difference is that the Windows idle loop in Enhanced mode would issue a special call to release its time slice]

    Ah yes the Yield() call. (Not really, but Yield() would call the scheduler which I believe would eventually call this if there was no other standard task to run).

    A very interesting little piece to bubble up from the bottom of the architecture as cooperative multiprocessing rather than preemptive.

    I did find it amusing that Yield() was ported to Win32 as a noop rather than Sleep(0), but that's another story.

  6. Danny says:

    See Ray?! None believes you didn't had fun. C'mon, time to step up with that 12 steps programs and tell us the truth, you DID had fun…a lot actually…I, for one, do have fun when I read 20 years old code of mine (most of the time I think "Jesus, so young and so stupid")

  7. Zenju says:

    empty set

    The set is not empty, it contains exactly one element! I demand a correction of the article!

  8. Anonymous Coward says:

    Okay, first of … meaningfully true statement.

    Erm, if you look back at your own words, you'll realise you're threatening every reader who so much as dares to bring it up. You may claim you have logic on your side, but you can only do so by pretending that things were typed in a different context than they were, so in reality you're just bending the truth until it breaks.

    I also find it impossible to believe that have been spending six hours doing all this horrible research about that subject that doesn't interest you at all even though there'd be no penalty whatsoever for not doing it. It simply doesn't ring true.

    Sorry if this makes me sound grumpy or thankless – I am not – but it would do you no harm to be just a little bit more civilised.

  9. Cesar says:

    Posts like these are why I keep returning to this blog. Retrocomputing details like these are fascinating, and they tell us a piece of our technological history we would not know about otherwise (since few people have access to the Windows 3.x source code). It is even more interesting for people who, like me, had as one of their first exposures to the world of computing the MS-DOS/Win3.x combo. Thanks for writing this post, Raymond!

  10. NB says:

    Which kernel did you get if you had a 386-SX processor?

  11. Klimax says:

    I'm pretty sure that SX didn't matter. (It denoted lack of FP support)

  12. I just want to chime in my thanks, Raymond.  I doubt such thanks is worth 6 hours of your time, but I find these little gems of history fascinating.

    To other readers – I have no idea if MS farms out Raymond to clients, but if they do, I'd be very surprised if it is for less than several hundred dollars an hour.  The fact that Raymond has provided, gratis, a service probably worth a few thousand dollars simply because some readers requested (okay, nagged) it of him is an indication of his service to us.  I'm humbled, given all he's ever gotten from me was my thanks and possibly a buck or two in royalties if his book earned out.

  13. Gerald H. says:

    Thanks for explaining the issue in a way even an idiot such as me could follow and understand at least the rough shape of the beast. Even if it cost you six hours of your life.

  14. Matt says:

    @Joshua: "I did find it amusing that Yield() was ported to Win32 as a noop rather than Sleep(0)"

    Err… semantically Sleep(0) is also a no-op. "sleep for zero milliseconds" and "do nothing" are equivalent, but doing nothing requires less processing to figure that out.

  15. steven says:

    @Klimax No, the SX/DX distinction of lacking FP support was with the 486 only. With the 386, it instead referred to the external bus. The 386SX and 386DX both used 32bit registers and 32bit instructions, but the 386SX's external bus was 16bit.

  16. Thank you for your time! We're glad you chose to share some of it with us.

  17. AC says:

    I find your introduction rant very surprising. People mostly ask you about these things because you're a great source of information and your articles are interesting. But that doesn't mean you are forced to write these articles. Even if it feels like your readers demand it (they do, because it's interesting), you don't have to waste your time if you don't feel like it. Complaining about your readers demanding more doesn't make sense. It's only a sign that you have a large readership.

    However, I am glad you did research this. This post was great.

    I grew up with Win95 upwards, so I've only known 3.1 from other people. I did do some very basic 16bit programming, but nothing fancy. So I'm always amazed with your series about the ingenious hacks that made things possible which on first sight seemed impossible without hardware support.

  18. Paul Parks says:

    @Matt: Sleep(0) is semantically different from NOP on Windows.

    msdn.microsoft.com/…/ms686298.aspx

  19. Joshua says:

    @Anonymous Coward:

    I refer the honourable gentlemen to blogs.msdn.com/…/the+social+skills+of+a+thermonuclear+device

  20. Neil (SM) says:

    Well I suppose threatening one person with the Nitpicker's Corner is effectively threatening all of us!  But that's besides the point since no threat had been made.

  21. mikeb says:

    I'll again just simply state that I enjoy these kinds of articles. For whatever that's worth.

    Thanks Raymond.

  22. Ah, perception bias.  I can definitely sympathize.

  23. Well, thanks for researching this anyway.  The details were very interesting to read.  I didn't realize there were *three* different kernels, each picked depending on the CPU.  Must have been a fun set of configurations for testing (8086 real mode, 286 standard mode, 286 real mode, 386 real mode, 386 standard mode, 386 enhanced mode….).  Can certainly see why real mode was ripped out to simplify things…

  24. JamesW says:

    Thanks for spending the time researching this article. This kind of OS archeology is why I love this blog.

  25. JamesNT says:

    Mr. Chen,

    I would also like to thank you for explaining this issue.  And thank you very much for maintaining this blog.  You are, and always will be, my programming god.

    JamesNT

  26. yuhong2 says:

    Win-OS/2 and NTVDM also ran Win3.x as a DPMI client.

  27. Mark says:

    Neil (SM): the threat was made in both articles as "Don't make me bring back the Nitpicker's Corner".

    I suspect the ambiguity in "threatening… for asking" (it doesn't necessarily imply someone *has* asked) is the source of the assumed transgression.

    Regardless, it's an amusing spin to put on the article – back in the day, the difference between 286 and 386 meant everything.

  28. Clovis says:

    "That's six hours I could've spent doing something enjoyable."

    Raymond – I'd find 6 hours looking at and writing about Windows 3.0 source code pretty cool myself. But when it comes to Windows source code, I can accept you're spoiled for choice.

  29. Neil says:

    I seem to remember reading that Windows 3.1 Standard Mode ran slightly differently on a '386 than Windows 3.0 did but my recollection of how 3.1 was claimed to do it matches what Raymond says for 3.0 so perhaps the claim was wrong after all.

  30. mmx says:

    @Steven Don

    The 386SX had another limitation – address space was limited to 16MB just like a 286, instead of 4GB, as far as I remember at least.

  31. bhtooefr says:

    @mmx: But that, I thought, was only external address space. The MMU supported 32-bit addresses, just like it did in the 386DX.

  32. asdbsd says:

    Raymond is being full-blown tsundere here. "It's not like I made this post for you. O-of course I spent six hours making it, but that's just because you complained! I don't l-like you or anything, I just can't leave you alone because you're so helpless!"

  33. chentiangemalc says:

    I love these windows "archaeology" blog posts…while totally useless information sure brings back memories of working with windows in its infancy…

  34. Dodo the Bird says:

    I'd like to know details of development of DOS 1.0 to DOS 5.x

  35. Observer says:

    "That's six hours I could've spent doing something enjoyable. "

    You mean you don't enjoy the four hours digging through Windows source?

  36. Joshua says:

    @Dodo: I'm pretty sure Raymond doesn't know. He was hired somewhere near the release of Windows 3.1.

  37. ender says:

    @NB: did you mean the buggy 386DX chips, which (IIRC) locked up when running in protected mode?

  38. James Bray says:

    Nice article and thanks for spending the 6 hours researching and writing it.  Seems like quite a few people got something out of it….

  39. @Matt :  "sleep for zero milliseconds" and "do nothing" are emphatically *not* the same thing, semantically or otherwise.

    Calling Sleep(0) let's Windows *know* that you have nothing to do, and that you are so intent on doing nothing that you are happy to give up any remaining part of your time-slice if Windows so decides.

    Doing nothing and letting your manager KNOW you are doing nothing (Sleep(0)), is very, very different from just *doing* nothing (FaceBook()).  :)

  40. Mc says:

    I remember the good old days booting my PC to the DOS prompt then having to decide do I type 'gem' today or 'win'.  386SX at 16Mhz and probably 1Mb of ram.   I did have a SVGA card though and could display 256 colours!

  41. 640k says:

    How could the statement be true when the ia32 hardware only could virtualize real mode clients?

  42. Herbie says:

    I always felt that real-mode Windows was the real achievement and after that Windows just used whatever Intel gave us. That doesn't mean I really enjoyed running real mode…

  43. George says:

    Whether it really matters or not, my feeling on comments on the Internet is to ignore them. Internet debate is nothing like real life. With respect to people who post interesting and useful comments on this blog, of course.

    And no, the irony is not lost on me for posting this :P

  44. Anonymous says:

    What a whiny little girl! Grow a pair, Raymond.

    [This coming from somebody afraid to give his name. -Raymond]

Comments are closed.