Most active commenters
  • deaddodo(7)
  • jcranmer(4)

←back to thread

331 points giuliomagnifico | 19 comments | | HN request time: 1.879s | source | bottom
1. deaddodo ◴[] No.45378189[source]
Nitpick: The author states that removal of 16-bit in Windows 64 was a design decision and not a technical one. That’s not quite true.

When AMD64 is in one of the 64-bit modes, long mode (true 64-bit) or compatibility mode (64-bit with 32-bit compatibility), you can not execute 16-bit code. There are tricks to make it happen, but they all require switching the CPU mode, which is insecure and can cause problems in complex execution environments (such as an OS).

If Microsoft (or Linux, Apple, etc) wanted to support 16-bit code in their 64-bit OSes, they would have had to create an emulator+VM (such as OTVDM/WineVDM) or make costly hacks to the OS.

replies(3): >>45378270 #>>45378503 #>>45378862 #
2. EvanAnderson ◴[] No.45378270[source]
Microsoft has just such an emulator. Via Windows source code leaks the NTVDM (Virtual DOS Machine) from 32-bit Windows versions has been built for 64-bit Windows targets[0].

I don't understand why Microsoft chose to kill it. That's not in their character re: backwards compatibility.

[0] https://github.com/leecher1337/ntvdmx64

Edit: Some nice discussion about the NTVDMx64 when it was released: https://www.vogons.org/viewtopic.php?t=48443

replies(2): >>45379145 #>>45379901 #
3. jcranmer ◴[] No.45378503[source]
I've written code to call 16-bit code from 64-bit code that works on Linux (because that's the only OS where I know the syscall to modify the LDT).

It's actually no harder to call 16-bit code from 64-bit code than it is to call 32-bit code from 64-bit code... you just need to do a far return (the reverse direction is harder because of stack alignment issues). The main difference between 32-bit and 16-bit is that OS's support 32-bit code by having a GDT entry for 32-bit code, whereas you have to go and support an LDT to do 16-bit code, and from what I can tell, Windows decided to drop support for LDTs with the move to 64-bit.

The other difficulty (if I've got my details correct) is that returning from an interrupt into 16-bit code is extremely difficult to do correctly and atomically, in a way that isn't a problem for 32-bit or 64-bit code.

replies(1): >>45379259 #
4. Animats ◴[] No.45378862[source]
It's not so much running 16 bit code, but running something that wants to run on bare metal, i.e. DOS programs that access hardware directly. Maintaining the DOS virtualization box well into the 21st century probably wasn't worth it.

> The 64-bit builds of Windows weren’t available immediately.

There was a year or so between the release of AMD-64 and the first shipping Microsoft OS that supported it.[1] It was rumored that Intel didn't want Microsoft to support AMD-64 until Intel had compatible hardware. Anyone know? Meanwhile, Linux for AMD-64 was shipping, which meant Linux was getting more market share in data centers.[1]

5. deaddodo ◴[] No.45379145[source]
NTVDM requires Virtual 8086 mode in the processor. This doesn't exist in the 64-bit modes, requiring a software emulator. That is why OTVDM/WineVDM exist.

You can see all of this explained in the README for the very project you linked:

```

How does it work?

=================

I never thought that it would be possible at all, as NTVDM on Win32 uses V86 mode of the CPU for fast code execution which isn't available in x64 long mode. However I stumbled upon the leaked Windows NT 4 sourcecode and the guys from OpenNT not only released the source but also patched it and included all required build tools so that it can be compiled without installing anything but their installation package. The code was a pure goldmine and I was curious how the NTVDM works.

It seems that Microsoft bought the SoftPC solution from Insignia, a company that specialised in DOS-Emulators for UNIX-Systems. I found out that it also existed on MIPS, PPC and ALPHA Builds of Windows NT 4 which obviously don't have a V86 mode available like Intel x86 has. It turned out that Insignia shipped SoftPC with a complete emulated C-CPU which also got used by Microsoft for MIPS, PPC and ALPHA-Builds.

```

As to why they didn't continue with that solution, because they didn't want to rely on SoftPC anymore or take on development themselves for a minuscule portion of users who would probably just use 32-bit Windows anyways.

replies(1): >>45379706 #
6. deaddodo ◴[] No.45379259[source]
Executing 16-bit code in Compatibility Mode (not Long Mode) is possible, that's not the problem. The problem is lack of V86 allowing legacy code to run. So Real Mode code is out wholesale (a sizable chunk of legacy software) and segmented memory is out in Protected Mode (nearly the totality of remaining 16-bit code).

So yes, you can write/run 16-bit code in 64-bit Compatibility Mode. You can't execute existing 16-bit software in 64-bit Compatibility Mode. The former is a neat trick, the latter is what people actually expect "16-bit compatibility" to mean.

replies(2): >>45379548 #>>45432033 #
7. jcranmer ◴[] No.45379548{3}[source]
> segmented memory is out in Protected Mode (nearly the totality of remaining 16-bit code).

No, segmented memory is exactly what you can get working. You set up the segments via the LDT, which is still supported even in 64-bit mode; this is how Wine is able to execute Win16 code on 64-bit Linux. (Reading Wine code is how I figured out how to execute 16-bit code from 64-bit code in the first place!)

What doesn't work, if my memory serves me correctly, is all the call gate and task gate stuff. Which is effectively building blocks for an OS kernel that everyone tossed out in the early 90s and instead went with kernel-mode and user-mode with the syscalls (first software interrupts and then the actual syscall instruction in x86-64). You don't need any of that stuff to run most 16-bit code, you just need to emulate the standard Windows DLLs like kernel, ntdll, and user.

replies(1): >>45382621 #
8. EvanAnderson ◴[] No.45379706{3}[source]
Yeah. Like I said, Microsoft had the emulator. NTVDM on x64 is handled just like MIPS or Alpha, by using the SoftPC emulator. It's just a new CPU architecture.

They had a proven and tested emulator yet they chose not to build it for the new x64 CPU architecture. It turns out that it wasn't too hard to build for the new architecture either. That's the crux of my confusion.

It's not like SoftPC was new and unproven code. It doesn't feel like it would have been a major endeavor to keep supporting it.

Obviously, I don't know Microsoft's telemetry told them re: the number of 16-bit application users. I know it impacted a number of my Customers (some of whom are running DOSBox today to keep old fit-for-purpose software working) and I don't support a ton of offices or people.

It seems out of character for Microsoft to make their Customers throw away software.

replies(1): >>45382698 #
9. cesarb ◴[] No.45379901[source]
> I don't understand why Microsoft chose to kill it.

My personal suspicion: it's about handles.

Several kinds of objects in the Windows API are identified by global handles (for instance, HWND for a window), and on 16-bit Windows, these handles are limited to 16 bits (though I vaguely recall reading somewhere that they're actually limited to 15 bits). Not having the possibility of a 16-bit Windows process would allow them to increase the global limit on the number of handles (keeping in mind that controls like buttons are actually nested windows, so it's not just one window handle for each top-level window).

replies(1): >>45381372 #
10. ack_complete ◴[] No.45381372{3}[source]
No need for suspicion, the documentation confirms this was a factor:

https://learn.microsoft.com/en-us/windows/win32/winprog64/ru...

11. deaddodo ◴[] No.45382621{4}[source]
Neither the AMD nor Intel TRMs agree with you. Both confirm that, even with LDTs, segments will not function with the legacy 16-bit wraparound; nor can you run 16-bit code segments. Fairly critical for most 16-bit software. Not to mention another critical incompatibility issue (for some software) that you yourself pointed out: far pointers.

And again, that only covers protected mode software, it doesn’t even touch the sheer cliff that is Real Mode (gating issues, for instance).

You wrote 16-bit code with knowledge of the limits imposed by Long Mode. Congrats. Too bad none of the thousands of pieces of software written in the 80s and 90s had that hindsight, so didn’t. The conversation is about running legacy code, not your/bespoke code.

replies(1): >>45382874 #
12. deaddodo ◴[] No.45382698{4}[source]
Cool, if you read to the last paragraph you would see that I also addressed that point.

They weren’t making them throw away software. Even at the inception of 64-bit Windows, 16-bit software made up a fraction of a percentile of use cases. They continued to support 32-bit Windows for almost two decades later for people that needed 16-bit software. At which point it was a fraction of a fraction of a fraction of users.

Of course it was dropped...30 years later.

13. jcranmer ◴[] No.45382874{5}[source]
I'm successfully running code that was written 10 years before x86-64 was invented on Linux x86-64. You can, too--just find some Win16 software online somewhere and run it under wine, and confirm that it's running without any hardware emulation mode enabled.

And yes, this code is using far pointers.

Do you need me to post my code that loads and executes a NE executable to believe that it's possible?

FWIW, here's what the Intel manual says about running 16-bit code in IA-32e mode:

> In IA-32e mode, the processor supports two sub-modes: compatibility mode and 64-bit mode. 64-bit mode provides 64-bit linear addressing and support for physical address space larger than 64 GBytes. Compatibility mode allows most legacy protected-mode applications to run unchanged.

> In IA-32e mode of Intel 64 architecture, the effects of segmentation depend on whether the processor is running in compatibility mode or 64-bit mode. In compatibility mode, segmentation functions just as it does using legacy 16-bit or 32-bit protected mode semantics.

Those don't sound to me like statements saying that there's no way to get 16-bit legacy applications running on 64-bit mode. Quite the contrary, they're saying that you should expect them to work largely the same.

What does the Intel manual say is actually broken in compatibility mode? This:

> Compatibility mode permits most legacy 16-bit and 32-bit applications to run without re-compilation under a 64-bit operating system. [...] Compatibility mode also supports all of the privilege levels that are supported in 64-bit and protected modes. Legacy applications that run in Virtual 8086 mode or use hardware task management will not work in this mode.

replies(1): >>45387461 #
14. deaddodo ◴[] No.45387461{6}[source]
Funny you gloss over the most important part:

> Legacy applications that run in Virtual 8086 mode or use hardware task management will not work in this mode.

That being said, this isn't worth arguing over. If you can provably run late 1980s-early 1990s 16-bit code in AMD64 compatibility mode, with full execution protections and support of even most not all commercial software; that goes against the general understanding of those architectures. Document it and add it to the academic sphere to expand the knowledge.

replies(2): >>45387859 #>>45389727 #
15. jcranmer ◴[] No.45387859{7}[source]
I can see that DOS applications might require Virtual 8086 mode, but from what I can tell, almost no Win16 applications require it nor require hardware task management (I'm not even sure I'm aware of any application that uses hardware task management!).

Granted, Win16 is not an especially long period of active application development, but I would expect that the vast majority of Win16 applications would work perfectly fine in x86-64 compatibility mode. I know that the ones I have played with do.

16. Agingcoder ◴[] No.45389727{7}[source]
I love your answer.

It’s honest, and actually typical of this kind of problem space where what’s possible exceeds what was expected.

It reminds me of what coders did with older atari st machines to achieve overscan and a whole bunch of other tricks. The manuals explicitly stated that some things were not possible or would cause machine resets … except that there was a way.

17. gldrk ◴[] No.45432033{3}[source]
Properly written Win16 applications are agnostic with respect to memory protection. Windows 3.0 could run in real mode (8086+), standard mode (80286+), or enhanced mode (80386+). Enhanced mode used V86 mode, which didn’t exist on the 80286, to support DOS console windows. In standard mode, Windows suspended itself to allow running DOS applications.

Real mode support was in fact dropped in Windows 3.1, so any program that runs under that is guaranteed to run under Linux/Wine (though not guaranteed not to crash because of some unimplemented API).

In protected mode, all Win16 code runs in ring 1 or 3, including all drivers and application programs, as well as the so-called ‘kernel’, which is just a shared library that provides support for coroutines, among other things. The actual kernel that runs in ring 0 is the DPMI host.

Memory segmentation is 100% supported on AMD64 in compatibility mode. This is entirely independent of the default operand size: it is purely a historical coincidence that 32-bit code segments tend to go hand-in-hand with flat memory models.

replies(1): >>45454767 #
18. deaddodo ◴[] No.45454767{4}[source]
Or you can just join the conversation in the middle instead of seeing all of that addressed in the replies:

> even with LDTs, segments will not function with the legacy 16-bit wraparound; nor can you run 16-bit code segments. [...] <and no far pointers>

And, most importantly:

> That being said, this isn't worth arguing over. If you can provably run late 1980s-early 1990s 16-bit code in AMD64 compatibility mode, with full execution protections and support of even most, not all, commercial software; that goes against the general understanding of those architectures. Document it and add it to the academic sphere to expand the knowledge.

Despite that entire conversation happening almost a week ago.

replies(1): >>45589787 #
19. gldrk ◴[] No.45589787{5}[source]
>even with LDTs, segments will not function with the legacy 16-bit wraparound

Yes, this is why KERNEL exports __AHSHIFT and __AHINCR.

>Despite that entire conversation happening almost a week ago.

It’s difficult enough to find correct information about this stuff. There is no harm in providing corrections.