The "technical details" link has some good discussion for that project. Interesting that he chose .NET to write this. I guess the abstract machine being emulated is pretty ancient, you don't necessarily need a performance-squeezing, non-GC language.
This is going to sound weird but for one particularly old and tricky game, I had amazingly good success with ReactOS in a virtual machine. Moreso than running a virtual machine with Windows 95/98. However, I can't help but think there must be a better way.
Does that work on 64-bit (ie any modern) linux? I remember there being some issue with switching back to 16-bit mode after entering (I think they were calling it) Long Mode, but I don't remember if that got fixed, and I don't have a 16-bit linux-userland-executable format handy to test it.
They are mostly 32-bit, so you can run them on any Windows 10 build. MS has worked pretty hard to maintain backward compatibility. They should mostly work, maybe requiring a little fiddling with the compatibility settings. But it’s not perfect, and I hear you might have better luck with WINE with some applications.
The break is with 16-bit applications, which 64-bit Windows 10 no longer supports. You can still run them on 32-bit Windows 10.
All that winevdm does is emulate the 16-bit processor and translate 16-bit-Windows api calls to their modern equivalent, so you can run 16-bit programs on 64-bit Windows again.
I don't have the right hardware to test this right now, but I believe unmodified system 7 binaries (and earlier) should run on up to OS X 10.4.11 from 2007 on PowerPC Macs, using the Classic environment.
In an alternative reality where PowerPC stayed competitive, I wonder how long they would have maintained the compat-layer. Given it's apple, probably not long, but I think it's worth pointing out backwards compat was only broken when both the OS and the CPU were changed (twice in the CPU's case).
My understanding is that running 16 bit code on a modern CPU is itself a sort of backwards compat mode which isn't supported in 64 bit operation, so you need a full emulator to run the executable. Neither Apple nor Microsoft seem keen on keeping CPU emulators around long term (IIRC Windows used to have something like this built-in for emulating 80286s for Win16, mostly for non-x86 arches like Alpha/MIPS/PowerPC, I think?)
Actually, running 16 bit code is perfectly supported on 64 bit CPUs (for obvious reasons -- you still need 16 bit to boot a BIOS), and even you can seamlessly switch between 16bit and 64bit modes at runtime (early 64 bit linux could even run vm86plus).
It was a political choice by Microsoft to drop 16 bit Windows support in 64 bit Windows. This is the limit of their famous backwards compatibility -- still impressive, though.
This also happened during the era where they were getting criticism from all sides due to crappy Windows security (think XP pre-SP2 times) and they may have seen the 16 bit support code as a liability.
The AMD64 architecture is older than UEFI. When it was released, _all_ computers booted using a 16bit BIOS.
Even today all desktop computers I know still ship a BIOS compatibility module meaning they still carry a BIOS which includes 16 bits code. All Windows 32-bits (not only supported, but still being sold) require a BIOS. OEMs regularly use FreeDOS for flashing stuff -- which requires a BIOS.
Only a couple laptops I've seen as full-fledged UEFI (no CSM) devices. They won't boot 32bit Windows nor anything before Windows 8.
Oh, sure -- the CPUs themselves can run in 16 bit mode, but after switching to 64 bit long mode I was under the impression you couldn't invoke vm86 mode. But I've never really played with 16 bit before.
I guess I was confusing it with BSD -- on at least NetBSD and I think OpenBSD, there's an in-kernel (16 bit) x86 emulator used for certain ACPI functions, like calling VGA BIOS code (option ROMs?) when waking from suspend-to-RAM.
There's also an option to just use native real mode, but the man page says "this may result in direct reboots".
Yes you can switch back to 16bit, and in early x64 Linux there was even support for the vm86plus() API, which allowed stuff such as dosemu to run natively (and even let DOS programs bitbang your IO ports). Eventually this was removed from upstream but there was a patch floating around which I used for some time.
Whatever one _wants_ to do it or not is another story. Even on 32-bit kernels I don't think vm86plus is enabled by default (nor is LDT changing from user-space) because of the crazy ways you can use it to break things.
> It was a political choice by Microsoft to drop 16 bit Windows support in 64 bit Windows. This is the limit of their famous backwards compatibility -- still impressive, though.
No... it wasn't political. It was a deliberate design decision for technical reasons ( https://docs.microsoft.com/en-us/windows/win32/winprog64/run... )
HANDLEs on 64bit windows have 32bits that are valid whereas HANDLES on 32bit windows only have 16bits that are valid. So unless Microsoft wanted to completely negate the value of going to 64bit in the first place, e.g. expanding the limits on programs to be less restrictive, it was always going to have something to give.
Because 32bit code often "thunked"^1 in 16bit code they couldn't really support it because even in 32bit mode HANDLEs still have 32bits of valid HANDLE. So a HANDLE passed to 16bit code wouldn't round trip correctly due to truncation.
Nor is it like MS could emulate this like the OPs code does, because that would require rewriting applications that had already shipped from ISVs that don't exist anymore or magically understanding when an application has 16bit code and needs to get fake HANDLEs neither of which is easy in reality. In the end it was easier to just ship a 32bit version of windows for those that still needed that support.
1^ This was only possible because FAR pointers in 16bit mode are still 32 bits and thus size of a pointer was in effect the same. So they could operate in the same address space. In 64bit mode this isn't the case because there are no FAR pointers and segmentation.
Fair enough, though it's still not a hardware reason.
You could have just given 16bit handles to all 32bit programs, with the con being harder 64<->32 interoperability (since sending a handle from 64 to 32/16 would require faking it), but then you would not break _existing_ applications at least. Guessing 32bit handles also broke quite some 32 bit applications.
In retrospective, I would not have made it the way I describe either way, since it looks like people could care less about old 16-bit compatibility, and on the other hand 32<->64 coexistence was common for quite a while.
So unfortunately people do care, it's why 32bit windows is still a thing. Most of the people that care however are large legacy enterprises that are running line of business applications that they don't have the source code for or require libraries they don't have the source code for. While they are migrating it's not a quick process in many cases.
As for 16bit HANDLEs for 32bit programs, it wouldn't have solved the issue as the HANDLEs are kernel tokens. The kernel doesn't actually care whether the user space application is 32 bit or 64bit in many cases. That's all handled via WoW64CPU.dll and friends. They proxy all kernel calls from 32bit code and then segment switch to a 64bit segment before calling the kernel. The same happens in reverse when coming back. So it would incur significant performance overhead in many cases to add that when it isn't really necessary and would negatively impact already memory constrained programs. Instead MS chose to let them get the best benefits they could from 64bit mode: all 4GB the 32bit address space can be used for 32bit things instead of just the bottom 2/3GB (depending on being flagged /LARGEADDRESSAWARE). In the end it's a lot more complicated than just telling people that aren't using very memory intensive apps in the first place to just run 32bit Windows which already works... and supports vm86 mode.
Technically, the kernel does not need to care, other than providing an API to create a 16-bit alias to a handle. An API which the 32/16-bit APIs will use transparently, as well as 64-bit programs explicitly whenever they want to send to a potentially 32/16-bit process.
I thought that the specific primitives needed to make NTVDM work were removed from AMD64, specifically that you cant go to Virtual 8086 mode, directly from long mode, without another reset inducing mode change someplace else? I read an article about this like 5 years ago.
Mostly true, this would be protected mode 16bit code (286), not DOS code or real mode code. Protected mode 16bit code was rare and thus support was less needed.
But you _can_ go into vm86 mode from long mode. Linux used to allow you to do that and there was even a patch floating around to restore this when it was removed from the kernel.
Not as simple as it sounds, HANDLEs are universal on windows. So it requires user mode code to both be in on the charade and to play nice, which it rarely ever does. The issue being things like GetWindowHandle, CreateMutex etc. Passing a Mutex or Event handle to another process is not uncommon on windows. Yes in theory you could just block off the lower 64k Handles as compat handles but it makes code complicated and that leads to unnecessary bugs in code that has to handle it. It's a lot simpler at the end of the day to just ask customers that need that support to just run 32bit windows which has NTVDM support for real mode code and simple 16bit protected mode support that's transparent and just works. So yes they could have done that... but the complication isn't worth it when they have something that works just fine already at no extra cost to development or client; and these apps are being phased out largely anyway. Long story short: the solution sounds simple but once you start plugging all the holes and corner cases it gets insanely complicated very quickly.
Like I'm running 95 era software and it mostly works fine on Win10, I have one application that cant deal with 64 bit, needs 32 bit windows, as it has serial drivers that dont work in 64 bit.
Windows 95/98 programs are Win32 programs. Most of them should run just fine on modern Windows[1], with the exception of system utilities and such that shipped with VxDs to provide functionality from kernel mode.
[1] Some of them might require Administrator to run if they were not sufficiently multi-user aware to support Windows NT.
I assume that it is primarily not about DirectX (or specifically DirectDraw) compatibility but about W9x games assuming that they can use DirectDraw to setup particular video mode, somehow get pointer to directly mapped framebuffer with particular organization and pixel format, write into that directly and completely ignore DirectDraw after the initialization.
VMware still works great for older operating systems. I've had nothing but trouble with Hyper-V and VirtualBox lately.
It's sad because VirtualBox used to work okay but the legacy AMD NIC and SoundBlaster drivers have been bitrotting in the last few years and Hyper-V's predecessor Virtual PC used to be great with older OSes too.
If you prefer free software KVM/virt-manager works just fine as well there's just a bit more fiddling with options to make things happy.
PCem. It's not exactly fast, because it meticulously emulates PC hardware (and thus requires obtaining the original firmware in some cases); running Win9x requires a rather beefy CPU. But for the same reason, it's really good at backwards compatibility.
The linked software contains a CPU emulator, since 64-bit Windows cannot execute programs in 16-bit mode.
Regardless, I would argue Wine is an emulator. It emulates Windows's behavior, so it is perfectly fine to describe it as an emulator in some contexts. This pedantic nit-picking is really tiresome.
Super interesting, I've been looking for something like this for a while. My grandfather still plays the original Age of Empires, and when he finally upgraded to Windows 10, we found that the game would no longer run. Luckily at that point AoE: Definitive Edition was on its way, and he bought that when it came out, but it got me thinking about stuff that's too recent for DOSBox but too old for modern Windows. It's a shame that he had to re-buy the game when he still had the original CD for it because there was no way of running it in Windows 10.
49 comments
[ 2.6 ms ] story [ 107 ms ] threadFor example you can run Windows 95 release of The Neverhood in Wine, which has some 16-bit parts (though practically, ScummVM is a better option).
Does that work on 64-bit (ie any modern) linux? I remember there being some issue with switching back to 16-bit mode after entering (I think they were calling it) Long Mode, but I don't remember if that got fixed, and I don't have a 16-bit linux-userland-executable format handy to test it.
But I tested it last quite a long time go.
The break is with 16-bit applications, which 64-bit Windows 10 no longer supports. You can still run them on 32-bit Windows 10.
All that winevdm does is emulate the 16-bit processor and translate 16-bit-Windows api calls to their modern equivalent, so you can run 16-bit programs on 64-bit Windows again.
In an alternative reality where PowerPC stayed competitive, I wonder how long they would have maintained the compat-layer. Given it's apple, probably not long, but I think it's worth pointing out backwards compat was only broken when both the OS and the CPU were changed (twice in the CPU's case).
My understanding is that running 16 bit code on a modern CPU is itself a sort of backwards compat mode which isn't supported in 64 bit operation, so you need a full emulator to run the executable. Neither Apple nor Microsoft seem keen on keeping CPU emulators around long term (IIRC Windows used to have something like this built-in for emulating 80286s for Win16, mostly for non-x86 arches like Alpha/MIPS/PowerPC, I think?)
It was a political choice by Microsoft to drop 16 bit Windows support in 64 bit Windows. This is the limit of their famous backwards compatibility -- still impressive, though.
This also happened during the era where they were getting criticism from all sides due to crappy Windows security (think XP pre-SP2 times) and they may have seen the 16 bit support code as a liability.
Even today all desktop computers I know still ship a BIOS compatibility module meaning they still carry a BIOS which includes 16 bits code. All Windows 32-bits (not only supported, but still being sold) require a BIOS. OEMs regularly use FreeDOS for flashing stuff -- which requires a BIOS.
Only a couple laptops I've seen as full-fledged UEFI (no CSM) devices. They won't boot 32bit Windows nor anything before Windows 8.
I guess I was confusing it with BSD -- on at least NetBSD and I think OpenBSD, there's an in-kernel (16 bit) x86 emulator used for certain ACPI functions, like calling VGA BIOS code (option ROMs?) when waking from suspend-to-RAM.
There's also an option to just use native real mode, but the man page says "this may result in direct reboots".
Whatever one _wants_ to do it or not is another story. Even on 32-bit kernels I don't think vm86plus is enabled by default (nor is LDT changing from user-space) because of the crazy ways you can use it to break things.
No... it wasn't political. It was a deliberate design decision for technical reasons ( https://docs.microsoft.com/en-us/windows/win32/winprog64/run... ) HANDLEs on 64bit windows have 32bits that are valid whereas HANDLES on 32bit windows only have 16bits that are valid. So unless Microsoft wanted to completely negate the value of going to 64bit in the first place, e.g. expanding the limits on programs to be less restrictive, it was always going to have something to give.
Because 32bit code often "thunked"^1 in 16bit code they couldn't really support it because even in 32bit mode HANDLEs still have 32bits of valid HANDLE. So a HANDLE passed to 16bit code wouldn't round trip correctly due to truncation.
Nor is it like MS could emulate this like the OPs code does, because that would require rewriting applications that had already shipped from ISVs that don't exist anymore or magically understanding when an application has 16bit code and needs to get fake HANDLEs neither of which is easy in reality. In the end it was easier to just ship a 32bit version of windows for those that still needed that support.
1^ This was only possible because FAR pointers in 16bit mode are still 32 bits and thus size of a pointer was in effect the same. So they could operate in the same address space. In 64bit mode this isn't the case because there are no FAR pointers and segmentation.
You could have just given 16bit handles to all 32bit programs, with the con being harder 64<->32 interoperability (since sending a handle from 64 to 32/16 would require faking it), but then you would not break _existing_ applications at least. Guessing 32bit handles also broke quite some 32 bit applications.
In retrospective, I would not have made it the way I describe either way, since it looks like people could care less about old 16-bit compatibility, and on the other hand 32<->64 coexistence was common for quite a while.
As for 16bit HANDLEs for 32bit programs, it wouldn't have solved the issue as the HANDLEs are kernel tokens. The kernel doesn't actually care whether the user space application is 32 bit or 64bit in many cases. That's all handled via WoW64CPU.dll and friends. They proxy all kernel calls from 32bit code and then segment switch to a 64bit segment before calling the kernel. The same happens in reverse when coming back. So it would incur significant performance overhead in many cases to add that when it isn't really necessary and would negatively impact already memory constrained programs. Instead MS chose to let them get the best benefits they could from 64bit mode: all 4GB the 32bit address space can be used for 32bit things instead of just the bottom 2/3GB (depending on being flagged /LARGEADDRESSAWARE). In the end it's a lot more complicated than just telling people that aren't using very memory intensive apps in the first place to just run 32bit Windows which already works... and supports vm86 mode.
...then use a translation table. If the system is 64-bit, there's certainly enough room and speed for one!
16-bit applications would not be able to handle more than 64k handles either way.
I can send it to you.
Like I'm running 95 era software and it mostly works fine on Win10, I have one application that cant deal with 64 bit, needs 32 bit windows, as it has serial drivers that dont work in 64 bit.
[1] Some of them might require Administrator to run if they were not sufficiently multi-user aware to support Windows NT.
It's sad because VirtualBox used to work okay but the legacy AMD NIC and SoundBlaster drivers have been bitrotting in the last few years and Hyper-V's predecessor Virtual PC used to be great with older OSes too.
If you prefer free software KVM/virt-manager works just fine as well there's just a bit more fiddling with options to make things happy.
https://pcem-emulator.co.uk/
Regardless, I would argue Wine is an emulator. It emulates Windows's behavior, so it is perfectly fine to describe it as an emulator in some contexts. This pedantic nit-picking is really tiresome.
"Wine (originally an acronym for "Wine Is Not an Emulator")..."