Hello!
The idea of having tests for our win16 functionality has been raised every so often, but never actualized. I would like to change that now. I think win16 has been broken several times recently, especially with large scale refactoring like the PE conversion and wow64 work, and I'd like to put tests in place to stop that happening. I'd also like to have a way to easily *write* tests for nontrivial functionality, which is currently something of an ordeal.
By my understanding, the big blocker for having win16 tests in tree is the lack of a usable win16 compiler. Existing win16 compilers are mostly hard to find; OpenWatcom is sometimes mentioned, but that only has win32 builds (as far as I'm aware), which makes it hard if not impossible to integrate into Wine.
I've spent a while over the past year or so trying a certain idea, where we write a small win16 entry point, and use generic thunks to call into win32 code, then use generic thunks the other way (WOWCallback16Ex) to call back into win16 functions. I managed to get a working PoC that actually worked on Windows XP; however, it did not work on Windows 98 [1].
In light of this, I tried a different approach. I considered but ultimately rejected the idea of introducing Win16 support into GCC [2], and instead tried an experiment to see if I could write an extremely minimalist, non-optimizing Win16 compiler myself from "scratch" [3]. It turns out that I could, in the span of what didn't end up being more than a couple months' worth of weekends.
The compiler is called Rosé, and it lives here:
https://gitlab.winehq.org/zfigura/rose
It is not fully featured; it's still missing a few notable pieces (in particular: unions, multiple code segments) but it is reasonably complete, and I was able to use it to compile a modified version of winetest.exe, and produce working executables for Windows 98.
It is therefore my proposal to use this compiler in Wine, and write in-tree Win16 tests. Here are some of the important considerations involved in this proposal:
* The compiler is small and could potentially be easily just imported into Wine. I don't have any feelings about continuing to maintain it outside of Wine—i.e. it could easily just be imported and any further development done in Wine (much like e.g. widl). "Small" here means about 15k LoC across a few files, including the builtin CRT and headers.
* NE executables, unlike both their predecessor (MZ) and successor (PE), cannot output to a controlling console, and in general have no concept of a stdin/stdout/stderr. This does not fit well with wine tests, which are built to run with a console. There is also not much in the way of IPC available to a win16 process. They can, on the other hand, open a file and output to it.
For Marvin (or gitlab CI), this is not a huge concern, but for development it's a bit more important. In light of this we may want to write a small win32 wrapper for win16 tests, possibly one that self-extracts the win16 test.
* In order to properly test Win16 we need a contemporaneous test VM, I think ideally 98. A modern 32-bit Windows machine (of which I think we still have some) will *run* 16-bit code, and may be usable to test *some* functionality, but I do not think the results can be trusted.
This is probably a more general problem—I think our current ability to test native ddraw is similarly worthless. (ddraw is also harder, though, because we need contemporaneous *hardware* as well.) There may be other areas where our current CI is not very valuable and we really do want to test old Windows versions, although I can't think of any off the top of my head.
Thoughts and opinions? If not (as per usual) I will try to put together a patch series soon.
--Zeb
[1] In a sense this is actually very similar to how we currently implement 16-bit DLLs in Wine, except that we use a private thunk instead of the exported generic thunks [CallProcEx32W], so I spent some time refactoring various parts of krnl386 and winebuild to match my proposed design. This was going well up until I tried running the executable on Windows 98. It turns out that, unlike with NT, one cannot call any win32 functions from the 32-bit DLL without crashing. This may not be prohibitive per se [if we avoid ever making any win32 calls] but it did impose some pretty severe limitations. It's also worth mentioning that the process of refactoring was *very* convoluted, things had to be moved around very carefully in order to work.
[2] The idea of introducing compiler support into GCC has obvious advantages: not just the reuse of frontend and optimization code, but the dialect is something that will already be perfectly familiar to a Wine developer. However, it also has disadvantages: it would take a lot of time to become familiar with gcc, and I expect that segmented address spaces will be very hard to fit into the GCC code and probably not accepted upstream.
[3] In fact it is not built from scratch, but rather built from the HLSL compiler. This is largely because I am very familiar with the HLSL compiler, and familiarity is very important. I also found it far less daunting to start with the HLSL compiler, rip out everything specific to HLSL, rather than to start from scratch even using the HLSL compiler as a model.
Hello Zeb,
I'd love to see Win16 tests in upstream Wine, so thanks for working on this! This would make picking changes from winevdm (the fork) into Wine a lot easier I think.
OpenWatcom is sometimes mentioned, but that only has win32 builds (as far as I'm aware), which makes it hard if not impossible to integrate into Wine.
You can compile OpenWatcom on Linux, or did I misunderstand that? I always thought the problem with OpenWatcom was that it's not as easily available as gcc and to avoid the dependency.
The compiler is called Rosé, and it lives here:
https://gitlab.winehq.org/zfigura/rose
It is not fully featured; it's still missing a few notable pieces (in particular: unions, multiple code segments) but it is reasonably complete, and I was able to use it to compile a modified version of winetest.exe, and produce working executables for Windows 98.
Could you provide a minimal example of a working program that uses MessageBoxA or printf?
- The compiler is small and could potentially be easily just imported into
Wine. I don't have any feelings about continuing to maintain it outside of Wine—i.e. it could easily just be imported and any further development done in Wine (much like e.g. widl). "Small" here means about 15k LoC across a few files, including the builtin CRT and headers.
Not that my opinion mattered a lot, but I would like having it under the Wine umbrella, makes my setup easier.
- NE executables, unlike both their predecessor (MZ) and successor (PE),
cannot output to a controlling console, and in general have no concept of a stdin/stdout/stderr. This does not fit well with wine tests, which are built to run with a console. There is also not much in the way of IPC available to a win16 process. They can, on the other hand, open a file and output to it.
Maybe a stupid question, but won't dos console interrupts works for console?
- In order to properly test Win16 we need a contemporaneous test VM, I think
ideally 98. A modern 32-bit Windows machine (of which I think we still have some) will *run* 16-bit code, and may be usable to test *some* functionality, but I do not think the results can be trusted.
Hm, I always thought XP would be a good win16 test-target. But then again, there is no XP VM either.
[2] The idea of introducing compiler support into GCC has obvious advantages: not just the reuse of frontend and optimization code, but the dialect is something that will already be perfectly familiar to a Wine developer. However, it also has disadvantages: it would take a lot of time to become familiar with gcc, and I expect that segmented address spaces will be very hard to fit into the GCC code and probably not accepted upstream.
Since gcc is capable of generating "fake" 16bit code using -m16, is this something that could be reused? Although I don't think one could get segmentation to work without way too much effort.
Regards, Fabian Maurer
On Saturday, 21 October 2023 17:38:29 CDT Fabian Maurer wrote:
Hello Zeb,
I'd love to see Win16 tests in upstream Wine, so thanks for working on this! This would make picking changes from winevdm (the fork) into Wine a lot easier I think.
OpenWatcom is sometimes mentioned, but that only has win32 builds (as far as I'm aware), which makes it hard if not impossible to integrate into Wine.
You can compile OpenWatcom on Linux, or did I misunderstand that? I always thought the problem with OpenWatcom was that it's not as easily available as gcc and to avoid the dependency.
Ah, perhaps. Either way I had understood that it was a blocker to adding real tests.
The compiler is called Rosé, and it lives here:
https://gitlab.winehq.org/zfigura/rose
It is not fully featured; it's still missing a few notable pieces (in particular: unions, multiple code segments) but it is reasonably complete, and I was able to use it to compile a modified version of winetest.exe, and produce working executables for Windows 98.
Could you provide a minimal example of a working program that uses MessageBoxA or printf?
I had to fix a regression, and actually add MessageBox() to the headers, but yes. I've attached a test.c (though it really is very simple).
Compiling is a bit tricky, because rose doesn't automatically call a preprocessor (I *think* this is legal by the GPL, but it also would take extra effort to implement) nor automatically find its CRT and libraries. Here is the command I use:
cpp test.c -o test.i -I../rose/include -D_WIN16 -U__GNUC__ && ./rosecc test.i crt/start.i crt/stdlib.i crt/string.i -l../rose/lib/kernel.def -l../rose/lib/user.def -o test.exe
- NE executables, unlike both their predecessor (MZ) and successor (PE),
cannot output to a controlling console, and in general have no concept of a stdin/stdout/stderr. This does not fit well with wine tests, which are built to run with a console. There is also not much in the way of IPC available to a win16 process. They can, on the other hand, open a file and output to it.
Maybe a stupid question, but won't dos console interrupts works for console?
Certainly not a stupid question :-)
In fact I tried this for some time. It turns out that the answer is no. You can make the exact same interrupts as work in a DOS program, using the predefined standard handle values, but they just don't work. They return success, but write to a hole in the ground.
I eventually had to go back and find manuals that say that Windows programs "should not" use standard I/O.
- In order to properly test Win16 we need a contemporaneous test VM, I think
ideally 98. A modern 32-bit Windows machine (of which I think we still have some) will *run* 16-bit code, and may be usable to test *some* functionality, but I do not think the results can be trusted.
Hm, I always thought XP would be a good win16 test-target. But then again, there is no XP VM either.
It's probably better than Windows 10, but still not ideal. As far as I'm aware there are applications out there that just stopped working with NT, although this is a vague idea of mine.
[2] The idea of introducing compiler support into GCC has obvious advantages: not just the reuse of frontend and optimization code, but the dialect is something that will already be perfectly familiar to a Wine developer. However, it also has disadvantages: it would take a lot of time to become familiar with gcc, and I expect that segmented address spaces will be very hard to fit into the GCC code and probably not accepted upstream.
Since gcc is capable of generating "fake" 16bit code using -m16, is this something that could be reused? Although I don't think one could get segmentation to work without way too much effort.
I don't know if -m16 is hooked up to the compiler or just the assembler, but the short answer is no. It does not handle segmented address spaces, the only difference is it generates code that can execute in a 16-bit segment as opposed to a 32-bit one, by toggling 66 and 67 overrides everywhere. My understanding is that the hard part of adding 16-bit support to gcc is the segmented address space.
--Zeb
On Sat, 21 Oct 2023, Zeb Figura wrote: [...]
- In order to properly test Win16 we need a contemporaneous test VM, I
think ideally 98. A modern 32-bit Windows machine (of which I think we still have some) will *run* 16-bit code, and may be usable to test *some* functionality, but I do not think the results can be trusted.
The TestBot still has a Windows XP VM. I also have the bbackup for a Windows 2000 VM which I expect could be made operational pretty quickly.
But I don't think the (post-VMware) TestBot ever had Windows 9x VMs. I did have VMs on my home computer which were submitting WineTest results but those were never part of the TestBot.
I don't think I've ever tried to run win9x with QEmu and I doubt it's tested much these days. But if QEmu still supports it [1], we find suitable ISOs and licenses, then adding VMs for them should be possible [2].
One issue is that we'll get whatever is on the CD and not any of the post-release fixes because Windows Update will not work (Microsoft's servers don't support the very old Windows versions).
[1] Some forum posts seem to indicate it still worked 2 years ago.
[2] In a way I guess it's lucky that the TestBot still uses TestAgent because I doubt the QEmu guest agent would work.
On Mon, Oct 23, 2023, Francois Gouget wrote: [...]
I don't think I've ever tried to run win9x with QEmu and I doubt it's
tested much these days.
I personally tried running Windows 98 (SE) with virt-manager (which is kind of a QEMU frontend) on a modern Ryzen (Zen 2) laptop and I managed to run it but with some issues:
- Notably there's an issue on recent AMD/Intel CPUs that causes weird application crashes (the solutions for this are: disabling KVM (which slows down VM performance) or patching[1] some of the operating system files (which could be annoying with some of the updates))
- Virtualized video acceleration is non-existent (which is already a problem on Windows XP) so you either need a software driver, try to pass-through a very old graphics card (I think some people managed to do that on XP) or try using 86Box (which does do low-level emulation of graphics cards like the Voodoo line; it does have heavy performance overhead though)
[1] https://github.com/JHRobotics/patcher9x#patch-for-windows-98me-to-fix-tlb-in...
On Monday, 23 October 2023 01:47:21 CDT DodoGTA GT wrote:
On Mon, Oct 23, 2023, Francois Gouget wrote: [...]
I don't think I've ever tried to run win9x with QEmu and I doubt it's
tested much these days.
I personally tried running Windows 98 (SE) with virt-manager (which is kind of a QEMU frontend) on a modern Ryzen (Zen 2) laptop and I managed to run it but with some issues:
- Notably there's an issue on recent AMD/Intel CPUs that causes weird
application crashes (the solutions for this are: disabling KVM (which slows down VM performance) or patching[1] some of the operating system files (which could be annoying with some of the updates))
I have a 98 VM with a somewhat older CPU and I haven't encountered that, at least.
- Virtualized video acceleration is non-existent (which is already a
problem on Windows XP) so you either need a software driver, try to pass-through a very old graphics card (I think some people managed to do that on XP) or try using 86Box (which does do low-level emulation of graphics cards like the Voodoo line; it does have heavy performance overhead though)
This isn't a concern for win16 I think (well, wing.dll exists, but ddraw is a win32 api). However, I really do want real hardware with a contemporaneous GPU, for the purposes of testing ddraw. I suspect that's not a job for the TestBot, though.
On Sunday, 22 October 2023 23:06:40 CDT Francois Gouget wrote:
On Sat, 21 Oct 2023, Zeb Figura wrote: [...]
- In order to properly test Win16 we need a contemporaneous test VM, I
think ideally 98. A modern 32-bit Windows machine (of which I think we still have some) will *run* 16-bit code, and may be usable to test *some* functionality, but I do not think the results can be trusted.
The TestBot still has a Windows XP VM. I also have the bbackup for a Windows 2000 VM which I expect could be made operational pretty quickly.
I think those will already be better than nothing, at least.
But I don't think the (post-VMware) TestBot ever had Windows 9x VMs. I did have VMs on my home computer which were submitting WineTest results but those were never part of the TestBot.
Ah, interesting. I know that we used to run tests on 9x (mostly because there's a lot of 'broken on 9x' kind of comments in the code) but I did not realize that it was never part of the (current) TestBot setup.
I don't think I've ever tried to run win9x with QEmu and I doubt it's tested much these days. But if QEmu still supports it [1], we find suitable ISOs and licenses, then adding VMs for them should be possible [2].
I have a QEmu VM here that works, and I was able to get a SAMBA shared folder as well. (Does the TestBot use SAMBA, or something else?)
One issue is that we'll get whatever is on the CD and not any of the post-release fixes because Windows Update will not work (Microsoft's servers don't support the very old Windows versions).
Huh, I wasn't aware that Microsoft did OTA updates that early. Do we have an idea of how much those updates matter? Is there any other way to retrieve them?
On 23/10/2023 11:02, Zeb Figura wrote:
Huh, I wasn't aware that Microsoft did OTA updates that early. Do we
have an idea of how much those updates matter? Is there any other way to retrieve them?
There are various unofficial 'service packs' and so on, though quite what they contain I couldn't say. 'Windows Update Restored' seems to be a recent attempt at reimplementing Windows Update for older versions with, as far as I can tell, the original update files and so on:
http://windowsupdaterestored.com/
Owen
On Mon, 23 Oct 2023, Zeb Figura wrote: [...]
I have a QEmu VM here that works, and I was able to get a SAMBA shared folder as well. (Does the TestBot use SAMBA, or something else?)
The TestBot runs a very small and very basic win32 server process (TestAgentd.exe) that can be told to send, receive or run files. It's not using any fancy API so I expect it would work.
https://gitlab.winehq.org/winehq/tools/-/tree/master/testbot/src/testagentd
One issue is that we'll get whatever is on the CD and not any of the post-release fixes because Windows Update will not work (Microsoft's servers don't support the very old Windows versions).
Huh, I wasn't aware that Microsoft did OTA updates that early.
Iirc the Windows Update menu was firing up Internet Explorer and presumably it was all handled by some ActiveX module.
Do we have an idea of how much those updates matter?
I don't know.