<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>i386 &#8211; Virtually Fun</title>
	<atom:link href="https://virtuallyfun.com/category/i386/feed/" rel="self" type="application/rss+xml" />
	<link>https://virtuallyfun.com</link>
	<description>Fun with Virtualization</description>
	<lastBuildDate>Sun, 08 Feb 2026 15:04:45 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>
	<item>
		<title>Yet another GCC 1.40 *SOME ASSEBMLY REQUIRED</title>
		<link>https://virtuallyfun.com/2026/02/08/yet-another-gcc-1-40-some-assebmly-required/</link>
					<comments>https://virtuallyfun.com/2026/02/08/yet-another-gcc-1-40-some-assebmly-required/#respond</comments>
		
		<dc:creator><![CDATA[neozeed]]></dc:creator>
		<pubDate>Sun, 08 Feb 2026 13:33:41 +0000</pubDate>
				<category><![CDATA[80386]]></category>
		<category><![CDATA[assembly]]></category>
		<category><![CDATA[gcc]]></category>
		<category><![CDATA[i386]]></category>
		<category><![CDATA[Win32]]></category>
		<guid isPermaLink="false">https://virtuallyfun.com/?p=15612</guid>

					<description><![CDATA[Oh sure I&#8217;ve done this ages ago, getting GCC 1.40 to compile with old Microsoft C compilers, and then target Win32, it&#8217;s not that &#8216;special&#8217;. But I thought I&#8217;d try to get them to build with MASM so I could &#8230; <a href="https://virtuallyfun.com/2026/02/08/yet-another-gcc-1-40-some-assebmly-required/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="779" src="https://virtuallyfun.com/wp-content/uploads/2026/02/Screenshot-2026-02-07-at-7.22.17-PM-1024x779.png" alt="" class="wp-image-15613" srcset="https://virtuallyfun.com/wp-content/uploads/2026/02/Screenshot-2026-02-07-at-7.22.17-PM-1024x779.png 1024w, https://virtuallyfun.com/wp-content/uploads/2026/02/Screenshot-2026-02-07-at-7.22.17-PM-300x228.png 300w, https://virtuallyfun.com/wp-content/uploads/2026/02/Screenshot-2026-02-07-at-7.22.17-PM-768x584.png 768w, https://virtuallyfun.com/wp-content/uploads/2026/02/Screenshot-2026-02-07-at-7.22.17-PM-395x300.png 395w, https://virtuallyfun.com/wp-content/uploads/2026/02/Screenshot-2026-02-07-at-7.22.17-PM.png 1210w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">phoon</figcaption></figure>



<p class="wp-block-paragraph">Oh sure I&#8217;ve done this ages ago, getting GCC 1.40 to compile with old Microsoft C compilers, and then target Win32, it&#8217;s not that &#8216;special&#8217;.  But I thought I&#8217;d try to get them to build with MASM so I could just distribute this with an assembler.  Spelling out the joke of some assembly required.</p>



<p class="wp-block-paragraph">Although I wasn&#8217;t going to target/host OS/2 I was ideally going straight to Win32, the MASM 6.11 assembler couldn&#8217;t assemble the MSVC 1.0 / MSC/386 8.0 compiler&#8217;s assembly output, I needed to use the MASM 7 from Visual C++ 2003; namely:</p>



<pre class="wp-block-code"><code>Microsoft (R) Macro Assembler Version 7.10.3077 Copyright (C) Microsoft Corporation. All rights reserved.</code></pre>



<p class="wp-block-paragraph">MASM 6.11 was having issues with pushing OFFSET&#8217;s ie:</p>



<pre class="wp-block-code"><code>push OFFSET _obstack</code></pre>



<p class="wp-block-paragraph">when they were defined as:</p>



<pre class="wp-block-code"><code>COMM _obstack:BYTE:024H</code></pre>



<p class="wp-block-paragraph">Chat GPT to the rescue knowing that later MASM&#8217;s will just handle it just fine.  And it was right!  I know AI gets a bad rep, but surprisingly (or not when you think about what it&#8217;s been trained on), it&#8217;s got some great insight to some old things like seemingly common software tools, and old environments.</p>



<p class="wp-block-paragraph">I didn&#8217;t bother trying to use Microsoft C/386 6.0 &amp; MASM386 5.1 to see if it&#8217;ll handle CC1, as that seems to be a bit extreme. and I wanted this to run on semi modern Win32 stuff.  More so that there isn&#8217;t a 64bit SMP aware OS/2 with a modern web browser.  Kind of sad to be honese, but it&#8217;s 2026, and here we are.</p>



<p class="wp-block-paragraph">I as always stick to the <a href="https://github.com/neozeed/gas-1.38-xenix-">Xenix GAS port</a> that outputs 386 OMF objects that earlier linker&#8217;s can happily auto-convert to coff and use on Win32.  One day I feel I should ask why they were cross compiling NT/i386 from OS/2 1.21 instead of using Xenix?!  Must have been some fundamental NTOS/2 thing I suppose.</p>



<p class="wp-block-paragraph">I guess a refresher for anyone comming in out of the cold here&#8217;s a really poorly done block diagram of what goes on when a traditional (GCC) compiler runs.  Explaniation is here: <a href="https://virtuallyfun.com/2024/01/08/so-it-turns-out-gcc-could-have-been-available-on-windows-nt-the-entire-time/">so it turns out GCC could have been available on Windows NT the entire time</a>.</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="384" src="https://virtuallyfun.com/wp-content/uploads/2024/01/gcc-program-flow-1024x384.png" alt="GCC program flow" class="wp-image-13731" srcset="https://virtuallyfun.com/wp-content/uploads/2024/01/gcc-program-flow-1024x384.png 1024w, https://virtuallyfun.com/wp-content/uploads/2024/01/gcc-program-flow-300x112.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/01/gcc-program-flow-768x288.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/01/gcc-program-flow-1536x575.png 1536w, https://virtuallyfun.com/wp-content/uploads/2024/01/gcc-program-flow-500x187.png 500w, https://virtuallyfun.com/wp-content/uploads/2024/01/gcc-program-flow.png 1962w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Long story there was that the Xenix GAS emits an ancient 386 OMF format that for unknown reaons the older Microsoft Linkers happily accept and auto convert into COFF, the file format of the future (Future being 1988).  I guess for better. or worse we never got NT/ELF.  Oh and speaking of further weird, the IBM version of their LINK386 doesn&#8217;t like the Xenix 386 OMF.  Bummer.</p>



<p class="wp-block-paragraph">One thing I found out is that the MASM v7 doesn&#8217;t output COFF by default, rather it&#8217;s 386 OMF!  you need to add the /coff flag to force it to be more Win32 friendly.  Kind of unexpected behaviour.</p>



<p class="wp-block-paragraph">I tried to make this simple as, clone the repo and run &#8216;build.cmd&#8217; it&#8217;ll link up GCC and then build the test programs, and clean up after itself.</p>



<p class="wp-block-paragraph"><a href="https://github.com/neozeed/gcc140-masm" target="_blank" rel="noreferrer noopener">https://github.com/neozeed/gcc140-masm</a></p>



<p class="wp-block-paragraph">I&#8217;d tried to emit assembly for the Xenix GAS, but for some reason it&#8217;s struggling with floating point.  I&#8217;m not sure, I tried using chat gpt to debug but it get&#8217;s confused on how this whole bizzare tool chain is working.  I guess I can&#8217;t blame it.</p>



<p class="wp-block-paragraph">Sorry it&#8217;s been a while, been feeling &#8216;life&#8217; lately.  I had some i7 project as a kicker for a retro Windows 10 build thing to do but watchign the RAM crissis unfold and well life&#8230; I just got feeling like it&#8217;s so irrelevant who&#8217;d care.  That and it&#8217;s insane watching $1.11 worth of DDR3 RAM now selling for $30++ &#8230;. and more and more chip manufacturers are exiting.  So it felt like maybe go back and do more with less.  Even a low end machine can assemble this in seconds!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://virtuallyfun.com/2026/02/08/yet-another-gcc-1-40-some-assebmly-required/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>UNAUTHORIZED WINDOWS/386</title>
		<link>https://virtuallyfun.com/2025/09/06/unauthorized-windows-386/</link>
					<comments>https://virtuallyfun.com/2025/09/06/unauthorized-windows-386/#comments</comments>
		
		<dc:creator><![CDATA[neozeed]]></dc:creator>
		<pubDate>Sat, 06 Sep 2025 22:19:16 +0000</pubDate>
				<category><![CDATA[80386]]></category>
		<category><![CDATA[guest post]]></category>
		<category><![CDATA[i386]]></category>
		<category><![CDATA[Windows/386]]></category>
		<guid isPermaLink="false">https://virtuallyfun.com/?p=15399</guid>

					<description><![CDATA[I wanted to share something special, a friend of mine, Will, has been so busy working on this project and I wanted to share it here for everyone here first. This is pretty technical, but still interesting deep look into &#8230; <a href="https://virtuallyfun.com/2025/09/06/unauthorized-windows-386/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I wanted to share something special, a friend of mine, Will, has been so busy working on this project and I wanted to share it here for everyone here first.</p>



<p class="wp-block-paragraph">This is pretty technical, but still interesting deep look into one of Microsoft&#8217;s early 32bit/386 based programs that would go on to revolutionize the world, Windows/386! It brought the v86 virtual machine to normal people wrapped up in a nice GUI.</p>



<p class="wp-block-paragraph">By Will Klees (CaptainWillStarblazer)</p>



<h1 class="wp-block-heading">INTRODUCTION</h1>



<p class="wp-block-paragraph">I&#8217;m CaptainWillStarblazer, an author who has previously been featured on VirtuallyFun for my work on EmuWOW, which enabled running Win32 apps compiled for the MIPS and Alpha AXP architectures to run on x86 computers. While I was born in the 21st century, I have a keen interest in the computers of the past, particularly in the history of Microsoft. The foundations for the breakout success of Windows 3.0, 3.1, and 9x were laid with Windows/386, but until recently, the inner-workings of Windows/386 have not been well understood, and beyond the very high-level, exactly how it works have been considered an opaque black box, not ventured into with books (official or otherwise) like its successors. No longer.</p>



<h2 class="wp-block-heading">FOREWORD</h2>



<p class="wp-block-paragraph">Before I begin, I would like to acknowledge that all of my work here was informed by the research of the late, great Geoff Chappell, who has many in-depth pages on this topic as well as many others that laid the groundwork for this post. His contributions to the scene are immeasurable, and I, along with many of you, stand on the shoulders of giants like him. It is unfortunate that up to this point, Windows/386 has not faced much reverse-engineering work (especially in comparison to the better-documented Windows 3.x and 95), but for the first time, it is being examined.</p>



<h1 class="wp-block-heading"><span style="text-decoration: underline;">ARCHITECTURE OF WINDOWS/386</span></h1>



<h2 class="wp-block-heading">Windows/386 Loader (WIN386.EXE)</h2>



<p class="wp-block-paragraph">The structure of Windows/386 is broadly similar to later versions of Windows running in enhanced mode. The journey begins with WIN386.EXE, which is a standard MZ EXE. WIN386 first performs some checks to make sure that your machine can run Windows/386 (you have enough memory, the right version of DOS, you have an 80386, defending against early buggy 386 steppings, etc.), among them being whether your computer is currently executing in Virtual-8086 Mode. If you are, then that means that another piece of protected-mode software is already controlling the computer. From there, it checks if Windows/386 is already running, and if so, displays an error message. From there, it checks if the resident protected-mode software is a memory manager that it recognizes (either Compaq’s CEMM or Microsoft’s EMM386), and if so, uses the GEMMIS (Global EMM Import Specification) API to suck out all of the EMS mapping page tables from the LIMulator and then switch back into real-mode. If it doesn’t recognize the protected-mode software, it at this point throws another error message.</p>



<p class="wp-block-paragraph">This check for early buggy 386 steppings was retained by Microsoft even into Windows 8.1, surprisingly enough. The system can also check for 386 chips with bad 32-bit multiplication, though it only warns the user of potential issues, it doesn’t fail to run like if you are running a Model 1 Stepping 0 chip.</p>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image1_0.png"><img decoding="async" width="945" height="554" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image1_0.png" alt="" class="wp-image-15400" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image1_0.png 945w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image1_0-300x176.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image1_0-768x450.png 768w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image1_0-500x293.png 500w" sizes="(max-width: 945px) 100vw, 945px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image1_1.png"><img loading="lazy" decoding="async" width="702" height="151" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image1_1.png" alt="" class="wp-image-15401" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image1_1.png 702w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image1_1-300x65.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image1_1-500x108.png 500w" sizes="auto, (max-width: 702px) 100vw, 702px" /></a><figcaption class="wp-element-caption"><em>[photo of the code checking for the buggy 386]</em></figcaption></figure>



<p class="wp-block-paragraph">Finally, it begins loading the Virtual DOS Machine Manager (VDMM) into memory from the file WIN386.386. This file is not an OS/2 Linear Executable like the 386 files from later versions of Windows (that format did not yet exist), rather it is the 32-bit x.out executable format from Xenix-386 (thank you, Michal Necasek!), which makes sense as it was the only 32-bit executable format that Microsoft would have a linker for at the time (and interoperated well with Microsoft&#8217;s OMF-based tools, such as MASM). Among the features of this format is that it contains a rather-lengthy symbol table. Not only does this aid reverse-engineering, however, it’s also a key part of the loading process. The WIN386.EXE loader will populate parts of the loaded image with important data using these symbols.</p>



<h2 class="wp-block-heading">Virtual DOS Machine Manager and Virtual Device Drivers (WIN386.386)</h2>



<p class="wp-block-paragraph">WIN386.386 contains a statically-linked binary image of the VDMM itself as well of all of the virtual device drivers. Disassembling the source code of Windows/386 was an interesting exercise. On my repo, I have a partial disassembly of EGA.3EX, the WIN386.EXE loader for the EGA version of WIN386.386, which is a standard MS-DOS executable and as such easily examined by reverse-engineering tools. However, the 32-bit x.out format used by Windows/386 is not readily supported by any reverse-engineering tools that I am aware of. While it would be possible to write an Ida or Ghidra plugin, I figured the simplest solution was to convert it to a more standard executable format that could be understood; COFF. After extracting the 16-bit entry stub into a small flat binary to be disassembled on its own, the COFF file could finally be opened (in reality, tools didn’t seem to like the COFF file very much, so I had to use GNU objcopy to convert it to ELF so that tools would like it) and examined.</p>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image2.png"><img loading="lazy" decoding="async" width="865" height="523" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image2.png" alt="" class="wp-image-15402" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image2.png 865w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image2-300x181.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image2-768x464.png 768w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image2-496x300.png 496w" sizes="auto, (max-width: 865px) 100vw, 865px" /></a><figcaption class="wp-element-caption"><em>[photo of the conversion program]</em></figcaption></figure>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image3.png"><img loading="lazy" decoding="async" width="904" height="537" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image3.png" alt="" class="wp-image-15403" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image3.png 904w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image3-300x178.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image3-768x456.png 768w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image3-500x297.png 500w" sizes="auto, (max-width: 904px) 100vw, 904px" /></a><figcaption class="wp-element-caption"><em>[objdump or dumpbin examining the resulting COFF image]</em></figcaption></figure>



<p class="wp-block-paragraph">WIN386.386 starts execution in real-mode with a short stub that prepares the Global Descriptor Table, loads the page directory, switches into protected-mode, and does a far jump to the 32-bit entry point. At this point, it starts WIN86.COM (loaded by WIN386.EXE) to start a real-mode copy of Windows in the first VM, otherwise known as the &#8220;System VM&#8221;.</p>



<p class="wp-block-paragraph">Two valuable resources for examining the code of Windows/386 have turned out to be the source code for MEMM (Microsoft Expanded Memory Manager, better known by its final name EMM386) from the MS-DOS 4.0 repository, and the Windows 3.0 DDK sample VxDs. It is obvious from comparing the Windows/386 disassembly to portions of the MEMM source code that portions of MEMM, both for EMS emulation and for the V86 monitor in particular, were simply lifted wholesale into Windows/386, and code comments even make reference to this. Amusingly, MEMM was assembled using the MASM 4.00 assembler which has poor support for the 80386, so copious amounts of macros are used to add in 386 instructions. Perhaps the most interesting EMM386-related finding, however, was that parts of EMM386 were written in C. This seemed obvious given the leading underscore and __cdecl-style calling convention in several Windows/386 functions, but examining the code finds it to be true.</p>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image4_0.png"><img loading="lazy" decoding="async" width="648" height="592" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image4_0.png" alt="" class="wp-image-15404" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image4_0.png 648w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image4_0-300x274.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image4_0-328x300.png 328w" sizes="auto, (max-width: 648px) 100vw, 648px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image4_1.png"><img loading="lazy" decoding="async" width="475" height="516" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image4_1.png" alt="" class="wp-image-15405" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image4_1.png 475w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image4_1-276x300.png 276w" sizes="auto, (max-width: 475px) 100vw, 475px" /></a><figcaption class="wp-element-caption"><em>[emm386 c &amp; 32-bit corresponding asm]</em></figcaption></figure>



<p class="wp-block-paragraph">Based on my examination, it appears that if you took the EMM386 C code and compiled it for a 32-bit flat model (EMM386&#8217;s code was compiled for a 16:16 far pointer model), you&#8217;d get the assembly in Windows/386. This is interesting because Windows/386 was previously thought to be written entirely in assembly, and the Microsoft 386 C compiler was in its infancy when Windows/386 was being written. It&#8217;s not entirely unbelievable, however, since Xenix-386, the earliest known user of the compiler, came out around the same time as Windows/386.</p>



<p class="wp-block-paragraph">The other handy reference while disassembling Windows/386 has actually been the Windows 3.0 DDK. Since the VDMM contains all of the virtual device drivers statically linked into it, and many of Windows 3.0’s virtual device drivers can trace their beginnings to Windows/386, there’s often a strong correspondence. Many APIs have changed, however, including how VxDs call each other. In Windows/386, it’s just a simple call, while their status as separate modules in Windows 3.0 requires a VxDCall; a special interrupt that causes the VMM to transfer control to another VxD.</p>



<figure class="wp-block-image size-large"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_Kybd_Wait_Out.png"><img loading="lazy" decoding="async" width="1024" height="565" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_Kybd_Wait_Out-1024x565.png" alt="" class="wp-image-15406" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_Kybd_Wait_Out-1024x565.png 1024w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_Kybd_Wait_Out-300x166.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_Kybd_Wait_Out-768x424.png 768w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_Kybd_Wait_Out-500x276.png 500w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_Kybd_Wait_Out.png 1134w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Attach2.png"><img loading="lazy" decoding="async" width="1024" height="522" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Attach2-1024x522.png" alt="" class="wp-image-15407" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Attach2-1024x522.png 1024w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Attach2-300x153.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Attach2-768x392.png 768w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Attach2-500x255.png 500w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Attach2.png 1288w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Detach2.png"><img loading="lazy" decoding="async" width="1024" height="396" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Detach2-1024x396.png" alt="" class="wp-image-15408" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Detach2-1024x396.png 1024w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Detach2-300x116.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Detach2-768x297.png 768w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Detach2-500x193.png 500w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Detach2.png 1193w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Int_10.png"><img loading="lazy" decoding="async" width="693" height="1024" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Int_10-693x1024.png" alt="" class="wp-image-15409" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Int_10-693x1024.png 693w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Int_10-203x300.png 203w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Int_10-768x1134.png 768w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Int_10-1040x1536.png 1040w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Int_10-1387x2048.png 1387w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Int_10.png 1476w" sizes="auto, (max-width: 693px) 100vw, 693px" /></a></figure>



<figure class="wp-block-image size-large"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Mem_Physical.png"><img loading="lazy" decoding="async" width="1024" height="544" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Mem_Physical-1024x544.png" alt="" class="wp-image-15410" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Mem_Physical-1024x544.png 1024w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Mem_Physical-300x159.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Mem_Physical-768x408.png 768w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Mem_Physical-500x266.png 500w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Mem_Physical.png 1281w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Unmap_PShdw.png"><img loading="lazy" decoding="async" width="1024" height="610" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Unmap_PShdw-1024x610.png" alt="" class="wp-image-15411" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Unmap_PShdw-1024x610.png 1024w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Unmap_PShdw-300x179.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Unmap_PShdw-768x458.png 768w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Unmap_PShdw-500x298.png 500w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image5_VDD_Unmap_PShdw.png 1168w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption"><em>[comparing between a Windows 3.0 VxD and a Windows 2.03 VxD]</em></figcaption></figure>



<p class="wp-block-paragraph">Examination of the MapLinear function finds that the memory map for Windows/386 2.xx is essentially identical to Windows 3.0. The first 4MB is the private per-VM arena (so chosen as it allows a task-switch to be as simple as altering the first PDE in the page directory, rather than having to switch page directories), then the 4-20MB range identity-maps the first 16MB of physical memory, and the VDMM is loaded at the 20MB mark.</p>



<p class="wp-block-paragraph">As a quick example of one of the code paths in Windows/386, when Windows/386 needs to return an entry point to a client application (such as through the INT 2FH AX=1602H API), it needs some way to cause a client calling that entry point in Virtual 8086 Mode to trap into protected mode. As documented by Raymond Chen, they found that the quickest way to do this was via the invalid opcode fault, and the invalid opcode they chose for this was 63H, or ARPL. As part of a mechanism that is still in place in Windows 95, when a VM executes an ARPL instruction, it&#8217;ll trap into the VDMM, vectoring through the IDT to vm_trap06.</p>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image6.png"><img loading="lazy" decoding="async" width="820" height="598" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image6.png" alt="" class="wp-image-15412" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image6.png 820w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image6-300x219.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image6-768x560.png 768w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image6-411x300.png 411w" sizes="auto, (max-width: 820px) 100vw, 820px" /></a><figcaption class="wp-element-caption"><em>[photo of the IDT]</em></figcaption></figure>



<figure class="wp-block-image size-large"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image7.png"><img loading="lazy" decoding="async" width="1024" height="267" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image7-1024x267.png" alt="" class="wp-image-15413" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image7-1024x267.png 1024w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image7-300x78.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image7-768x200.png 768w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image7-500x130.png 500w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image7.png 1074w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption"><em>[photo of vm_trap06]</em></figcaption></figure>



<p class="wp-block-paragraph">From there, it determines if the fault came from a VM or not. If not, it executes the Windows/386 error handler, but if it did, it calls into VmFault. VmFault looks up the faulting opcode through a table and invokes the appropriate handler for it. The appropriate handler for ARPL is called Patch_Fault. From there, it determines what kind of call this is, and if you&#8217;re lucky, it&#8217;ll end up in TS_VMDA_Call, which is described in the next section.</p>



<figure class="wp-block-image size-large"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image7-1.png"><img loading="lazy" decoding="async" width="1024" height="267" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image7-1-1024x267.png" alt="" class="wp-image-15414" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image7-1-1024x267.png 1024w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image7-1-300x78.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image7-1-768x200.png 768w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image7-1-500x130.png 500w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image7-1.png 1074w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption"><em>[photo of VmFault]</em></figcaption></figure>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image8.png"><img loading="lazy" decoding="async" width="674" height="323" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image8.png" alt="" class="wp-image-15415" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image8.png 674w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image8-300x144.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image8-500x240.png 500w" sizes="auto, (max-width: 674px) 100vw, 674px" /></a><figcaption class="wp-element-caption"><em>[photo of Patch_Fault]</em></figcaption></figure>



<h2 class="wp-block-heading">The System VM &#8211; Windows 2 and WINOLDAP</h2>



<p class="wp-block-paragraph">The code running inside of the system VM is almost identical to a standard real-mode Windows 2.xx install, with one exception: WINOLDAP. Responsible for executing MS-DOS (“old”) applications, WINOLDAP is totally different in Windows/386 (and as such, not functional if you try to load WIN86.COM directly from real-mode on its own, which otherwise provides a perfectly workable real-mode Windows experience), making heavy use of 386 instructions and of the &#8220;Virtual DOS Applications&#8221; (VDA, otherwise known as VMDOSAPP) API (accessed via INT 2FH AX=1601H in Windows/386 2.03 and 2.11) which is made available exclusively to the system VM, allowing WINOLDAP to control the execution of other virtual machines.</p>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image10_0.png"><img loading="lazy" decoding="async" width="833" height="586" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image10_0.png" alt="" class="wp-image-15416" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image10_0.png 833w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image10_0-300x211.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image10_0-768x540.png 768w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image10_0-426x300.png 426w" sizes="auto, (max-width: 833px) 100vw, 833px" /></a></figure>



<figure class="wp-block-image size-large"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image10_1.png"><img loading="lazy" decoding="async" width="1024" height="540" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image10_1-1024x540.png" alt="" class="wp-image-15417" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image10_1-1024x540.png 1024w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image10_1-300x158.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image10_1-768x405.png 768w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image10_1-500x264.png 500w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image10_1.png 1085w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption"><em>[photos of the dispatch tables and routines for VDA]</em></figcaption></figure>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image11_0.png"><img loading="lazy" decoding="async" width="657" height="582" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image11_0.png" alt="" class="wp-image-15419" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image11_0.png 657w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image11_0-300x266.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image11_0-339x300.png 339w" sizes="auto, (max-width: 657px) 100vw, 657px" /></a></figure>


<div class="wp-block-image">
<figure class="aligncenter size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image11_1.png"><img loading="lazy" decoding="async" width="337" height="837" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image11_1.png" alt="" class="wp-image-15420" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image11_1.png 337w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image11_1-121x300.png 121w" sizes="auto, (max-width: 337px) 100vw, 337px" /></a><figcaption class="wp-element-caption"><em>[example app using VDA]</em></figcaption></figure>
</div>


<p class="wp-block-paragraph">While the details of this API certainly changed for Windows 3.0 and for later versions, WINOLDAP continued to work in fundamentally the same way, with the DOS application running in the System VM (intended to be Windows) being uniquely privileged to control operations in other virtual machines. Given that many people have figured out how to make Windows/386 start applications other than Windows itself (such as COMMAND.COM), this means that nothing would stop a sufficiently enterprising developer from developing a text-based MS-DOS application that leveraged this API to provide multitasking. In fact, this is likely how Raymond Chen’s “character-mode task switcher” functioned. WINOLDAP is worthy of further examination to determine exactly how it works, and perhaps to develop a multitasking MS-DOS. Obviously, this API, intended to have only Windows as a client, is totally undocumented other than by myself and Geoff Chappell, but further work could reveal its secrets.</p>



<p class="wp-block-paragraph">In addition to the VDA API, Windows/386 also provided a much more limited API to callers in other virtual machines (accessed via INT 2FH AX=1602H), that appears to still be available in Windows 3.0 and is primarily responsible for networking.</p>



<p class="wp-block-paragraph">For most of my experimentation, I actually sidestepped booting Windows altogether so that I could run my own code in the System VM. This is fairly simple; all you need to do is copy COMMAND.COM over WIN86.COM, then start WIN386, and viola! You&#8217;re running COMMAND.COM in Virtual 8086 Mode! Probably the most notable change is that if you didn&#8217;t already have any LIM EMS memory, you do now.</p>



<h2 class="wp-block-heading">LOST WINDOWS/386 DDK</h2>



<p class="wp-block-paragraph">While no DDK for Windows/386 2.xx has been located, hints have been scattered for its existence. Most notably, the Windows 3.0 386 Virtual Device Adaptation Guide provides guidance on the differences between Windows/386 2.xx and Windows 3.0, and how to port virtual display drivers from one to the other, suggesting that Microsoft did provide tools to enable third-party developers to write Windows/386 virtual device drivers. It’s not difficult to imagine what this DDK would have looked like. Likely distributed alongside the regular Windows/286 real-mode DDK, the Windows/386-specific portions would include the 32-bit capable MASM5, along with early versions of MAPSYM32, WDEB386, and the Xenix x.out ld link editor. Very likely, Microsoft provided sample code for each of the VxDs included with Windows/386 (including the CGA, EGA, and Hercules VDDs), as well as a precompiled OMF object containing the VDMM itself, and then one would link everything together.</p>



<p class="wp-block-paragraph">It bears repeating that the documentation on porting virtual device drivers from Windows/386 2.xx to Windows 3.0 was limited solely to virtual display drivers. The only other references to Windows/386 2.xx in the Virtual Device Adaptation Guide discuss the Windows/386 API callable by DOS applications running in a DOS box (many device drivers and applications, including network stacks, were Windows/386 aware). This could mean that other types of drivers could be more easily reassembled for Windows 3.0 without documentation, but I doubt it. As it stands, most of the virtual device drivers included in Windows/386 were fairly generic; the COM port, timer, PIC, keyboard, and other such devices work almost identically in every PC-compatible computer. On the other hand, the display driver is the one major component that Windows would need to interact with and that would significantly change between different types of machines. Additionally, due to the statically-linked nature of Windows/386 at this point, having more than one VxD as the variable factor could balloon into a smorgasbord of different combinations of drivers statically linked into the WIN386.386 image. As such, it stands to reason that the only driver built by third-parties (though no such driver has yet been located) is a virtual display driver. This lines up with Microsoft’s own distribution of Windows/386, as the disks include separate 386 files for each supported display (the appropriate file being copied for your machine based on your selection during setup) and a matching 3EX file that gets copied to become the WIN386.EXE loader, and display drivers (also including their own complete Windows/386 images, obviously based on customizing the EGA/VGA VDD) have been found for other display adapters as well. This is compounded by the fact that during SETUP (including for real-mode Windows), the 16-bit display driver is statically linked into the Windows kernel (in other words, you can only load a display driver during SETUP) for the &#8220;fast-boot&#8221; configuration (though this can be disabled for a &#8220;slow-boot&#8221; on debug versions, more similar to how Windows 3.0 and above boot). A lot of reading between the lines is needed here, but it does seem that the only customization Microsoft intended was for OEMs to provide their own virtual display drivers.</p>



<h2 class="wp-block-heading">BREAKING INTO WINDOWS/386</h2>



<p class="wp-block-paragraph">In absence of the Windows/386 DDK and its associated debugger, options are fairly limited as to peeking into the internals of Windows/386 while it is active. Promise was initially found in WIN386.EXE making a call to INT 68H (the WDEB386 real-mode interface, also used by the Deb386 debugger developed for EMM386 that no doubt was the immediate ancestor of WDEB386, as well as by compatible debuggers such as SoftICE) with AH=43H (D386_Identify, typically the first call made when initializing a program that uses WDEB386), no doubt trying to call out to its version of WDEB386, if present. However, the version of WDEB386 from Windows 3.1 only partially worked. While a CTRL-C could break into WDEB386 at any time, it could only trace through Virtual 8086 Mode code (always breaking at an ARPL VM-86 breakpoint), and whenever you tried to resume execution using the G command, Windows/386 would exit.</p>



<p class="wp-block-paragraph">As a result, I had to improvise my own debugger, which required me to gain the ability to execute my own 32-bit code within Windows/386, which has never before been achieved. I immediately decided to adopt a similar approach to WDEB386; leave the debugger behind in conventional memory before Windows/386 starts up, and then have it call into me, so I quickly set about writing a small TSR. The TSR hooked INT 69H with a routine called Intrude that would patch the IDT of Windows/386 (found via traversing the image symbol table) to point to my own code for interrupt vector 0 (the divide exception handler). That way, whenever a divide exception occurred, it would vector into my own code.</p>



<p class="wp-block-paragraph">The next question you may be wondering about is how I got Windows/386 to invoke an INT 69H in the first place? The answer lies in the real-mode initialization stub of WIN386.386; the part that switches into protected-mode. Examine the listing below:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<div class="wp-block-group is-vertical is-layout-flex wp-container-core-group-is-layout-4fc3f8e1 wp-block-group-is-layout-flex">
<p class="wp-block-paragraph">Enable_A20:</p>



<p class="wp-block-paragraph">01B7 803EBD00F8 CMP BYTE PTR [Computer_Type],0F8H ; Check for fast A20 support</p>



<p class="wp-block-paragraph">01BC 7707 JA Enable_A20_Slow</p>



<p class="wp-block-paragraph">01BE E492 IN AL,92H ; Fast A20 enable</p>



<p class="wp-block-paragraph">01C0 0C02 OR AL,2 ; Set bit 1 (A20 line control)</p>



<p class="wp-block-paragraph">01C2 E692 OUT 92H,AL ; Output back to port 92H</p>



<p class="wp-block-paragraph">01C4 C3 RET</p>



<p class="wp-block-paragraph">Enable_A20_Slow:</p>



<p class="wp-block-paragraph">01C5 B4DF MOV AH,0DFH</p>



<p class="wp-block-paragraph">01C7 EB12 JMP Set_A20</p>
</div>
</blockquote>



<p class="wp-block-paragraph">By the time Enable_A20 is called, which checks the computer type from the BIOS, most of the data structures needed to enter Windows/386 have already been set up, so I patched Windows/386 to simply remove Fast A20 support and always use the slow code, putting an INT 69H in the slack space. In other words, it replaces the instruction at <em>TEXT16:01B7 with an INT 69H (CD 69). Since the original instruction is 5 bytes long, the remaining three are padded with NOP (90). The instruction at </em>TEXT16:01BC is then altered to be an unconditional jump (EB) to always invoke the slow A20 line control. Since the loaded object is always at offset 400H in the file, and the offsets appear to be the same for all versions of Windows/386 on all devices, the changes are:</p>



<div class="wp-block-group is-vertical is-layout-flex wp-container-core-group-is-layout-4fc3f8e1 wp-block-group-is-layout-flex">
<p class="wp-block-paragraph">5B7: 80 -&gt; CD</p>



<p class="wp-block-paragraph">5B8: 3E -&gt; 69</p>



<p class="wp-block-paragraph">5B9: BD -&gt; 90</p>



<p class="wp-block-paragraph">5BA: 00 -&gt; 90</p>



<p class="wp-block-paragraph">5BB: F8 -&gt; 90</p>



<p class="wp-block-paragraph">5BC: 77 -&gt; EB</p>
</div>



<p class="wp-block-paragraph">The trouble at this point was that, while my program did work, it left the protected-mode code sitting in conventional memory, and part of the System VM&#8217;s inherited address space and thus subject to corruption. As a result, I wanted to move it up into extended memory, out of the reach of any pesky DOS programs. My first thought was to use XMS memory through HIMEM.SYS, which was introduced with Windows/386 2.11 to facilitate access to the HMA for Windows. Unfortunately, while this did sort of work, it turns out that Windows/386 (which if you&#8217;ll recall was initially designed before XMS or HIMEM.SYS) does not respect XMS allocations made before Windows loads, and thus considers them part of its extended memory pool (a fact I was taught by the fact that it corrupts the first two DWORDs of every 64K memory block starting after the HMA as part of its memory test). It is also important to realize that Windows/386 2.11 does not provide virtual XMS services to any client VMs (though Windows 3.0 and later versions do), except for HMA access to the System VM only (Windows/286 2.11 also used the HMA on 80286 and above systems, hence the &#8220;286&#8221; name, though it otherwise worked fine on XT-class machines, and since Windows/386 ran Windows/286 in the System VM, it made sense to also support the HMA there).</p>



<p class="wp-block-paragraph">As a result, I used the &#8220;expand-down&#8221; memory allocation method of determining the amount of installed extended memory using INT 15H AH=88H, and then hooking that interrupt to report 132K less memory than there was before, and using the last 132K of extended memory for my own purposes. Since INT 15H AH=88H can report up to 64MB of installed extended memory, while INT 15H AH=87H to copy into extended memory only supports up to 16MB, I had to write my own routines to copy into extended memory by switching into protected-mode and then back. As a result, W386DBG has to be loaded before any memory manager that places the machine into Virtual 8086 Mode, such as EMM386, or anything that allocates XMS memory (not that any such programs are likely to be used alongside Windows/386, as just as I stated earlier, the XMS memory would be corrupted).</p>



<p class="wp-block-paragraph">As you can see, if you cause a divide exception in DEBUG.COM, it&#8217;ll print out &#8220;W386DBG&#8221; in the upper-right of the screen and then hang the computer. This won&#8217;t work for a software INT 0, because software interrupts from Virtual 8086 Mode vector through the GPF handler.</p>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image12.png"><img loading="lazy" decoding="async" width="665" height="377" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image12.png" alt="" class="wp-image-15421" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image12.png 665w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image12-300x170.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image12-500x283.png 500w" sizes="auto, (max-width: 665px) 100vw, 665px" /></a><figcaption class="wp-element-caption"><em>[photo of the program launching]</em></figcaption></figure>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2025/09/Image13.png"><img loading="lazy" decoding="async" width="722" height="888" src="https://virtuallyfun.com/wp-content/uploads/2025/09/Image13.png" alt="" class="wp-image-15422" srcset="https://virtuallyfun.com/wp-content/uploads/2025/09/Image13.png 722w, https://virtuallyfun.com/wp-content/uploads/2025/09/Image13-244x300.png 244w" sizes="auto, (max-width: 722px) 100vw, 722px" /></a><figcaption class="wp-element-caption"><em>[photo of the hang with the VBox debugger showing where we hung]</em></figcaption></figure>



<p class="wp-block-paragraph">Note that while we lack any debug version of the VDMM (along with any symbols that it may contain or debug messages it may output), the VDMM itself does as stated earlier have a considerable symbol table, and we have debug versions of Windows 2 as part of its DDK, which were meant to be used with SYMDEB and include symbols, so at least we can have full debugging capabilities for the 16-bit components of Windows, simply by loading debug Windows 2 into the System VM, as no doubt one was intended to do when developing device drivers for Windows/386. Obviously, W386DBG is not yet a functional debugger, but it has gained the ability to grab control from Windows/386, which is perhaps the most important part.</p>



<h2 class="wp-block-heading">INTO THE FUTURE WITH WINDOWS VERSION 3.0</h2>



<p class="wp-block-paragraph">Lately, I have become interested in turning my attention to the Windows 3.0 version 14 debug release that shipped to ISVs in early 1989. As one would expect, it shows many similarities to Windows 2.xx, but is already well on the way to becoming the Windows 3.0 that we know.</p>



<p class="wp-block-paragraph">Notably, the WIN386.386 file is now gone, having been merged into WIN386.EXE as with the final version of Windows 3.0, meaning that the same DOS executable both loads the VMM and contains it. However, the VMM itself (pointed to by the e_lfanew field in the MZ header) is not an OS/2 2.0 Cruiser Linear Executable like the final version (or, more properly, the W3 format which contains multiple LE VxDs within it), but rather another bespoke format with a “W386” signature that I have not yet torn into yet. All of the VxDs are still statically linked at this point, but the symbol file is showing movement toward the VMM we know from Windows 3.0.</p>



<p class="wp-block-paragraph">I haven’t disassembled all of the real-mode entry portion of WIN386 yet (this will allow me to fully understand the file format), but an interesting piece of code new to this build checks to make sure not only that the DOS major version is at least 3 (3 being the minimum DOS version) but also less than 10, as 10 is the major DOS version reported by OS/2 1.x’s 3xBox, making Windows/386 3.0.14 OS/2-aware (and avoidant).</p>



<p class="wp-block-paragraph">One piece of Windows 3.0-related history that was recently discovered was the manual for Murray Sargent’s Scroll-Screen-Tracer debugger. The debugger is far too rich in features to begin to go over them, but among its incredible DOS-extending features include support for debugging applications in Virtual 8086 Mode (a la SoftICE), debugging Windows, and debugging regular MS-DOS applications running in the 80286’s Protected Mode, much as was described in “Saving Windows from the OS/2 Bulldozer”.</p>



<p class="wp-block-paragraph">Interestingly, the DOS extender provided by WIN386, along with PKERNEL.EXE (the protected-mode Windows kernel) seem to have more in common with the 80286 DOS extender, DOSX.EXE, from Windows 3.0, along with the 80286 standard mode kernel, KRNL286.EXE, than they do with the enhanced mode counterparts.</p>



<p class="wp-block-paragraph">For example, like in the final version of Windows 3.0, DOSX (in this case, WIN386) switches into protected-mode before loading PKERNEL/KRNL286, giving it the unique distinction of being an MZ executable that starts in protected-mode, using a stub to start executing the NE portion of the file. By contrast, in Windows 3.1 (and 3.0 enhanced mode), the DOS extender switches back into real / Virtual 8086 Mode before loading the kernel, which then uses DPMI to switch into protected-mode.</p>



<p class="wp-block-paragraph">Along with translation for DOS API services, according to Michal Necasek of the <a href="https://os2museum.com/wp">OS/2 Museum</a>, WIN386 appears to provide some sort of selector management interface via INT 31H that could be considered a sort of proto-DPMI. Disassembling both WIN386 and PKERNEL promises to be an interesting exercise. Not much is known about the early history of DPMI, but the first sign of it outside of Microsoft appears to date to Fall 1989:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">I will never forget how startled I was when I encountered the DOS-Protected Mode Interface (DPMI) in its primordial form for the first time. I was sitting in a Microsoft OS/2 2.0 ISV seminar in the Fall of 1989, with my mind only about half-engaged during an uninspiring session about OS/2 2.0&#8217;s Multiple Virtual DOS Machines (MVDMs), when the speaker mentioned in passing that OS/2 2.0 would support a new interface for the execution of DOS Extender applications. This casual remark focused my mind remarkably&#8230;</p>
</blockquote>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">After the speaker finished, I went up to him and asked for more information, explaining that his mystery interface was about to have a severe impact on a book project near and dear to my heart. In a couple of hours, the Microsoftie returned with a thick document entitled &#8220;DOS Protected Mode Interface Specification, Version 0.04&#8221; still warm from the Xerox machine and generously garnished with &#8220;CONFIDENTIAL&#8221; warning messages. I suspect I made a most amusing spectacle, as I flipped through the pages with my eyes bulging out and my jaw dropping to the floor. The document I had been handed was nothing less than the functional specification of a protected-mode version of MS-DOS!</p>



<p class="wp-block-paragraph">Microsoft originally defined the DPMI in two layers: a set of low-level functions for interrupt management, mode switching, and extended memory management; and a higher-level interface that provided access to MS-DOS, ROM BIOS, and mouse driver functionality via protected-mode execution of Int 21H, Int 10H, Int 33H, and so on. The higher-level DPMI functions were implemented, of course, in terms of the lower-level DPMI functions and the extant real-mode DOS and ROM BIOS interface.</p>
</blockquote>



<p class="wp-block-paragraph"><em>Ray Duncan, Extending DOS, 2d ed., 1992, pp. 433-438</em></p>



<p class="wp-block-paragraph">Obviously, by this point, Microsoft, who was still heavily invested in OS/2, planned to implement DPMI into OS/2 2.0, though they would not do so for about a year afterwards. Desiring crossover with the protected-mode DOS apps that would run on Windows (most crucially, Windows itself) was no doubt a desire for the OS/2 development team. I was surprised to learn that DPMI was already by this point mature enough to have even a preliminary specification released. Moreover, Microsoft went on to, at the behest of DOS Extender vendors, such as Phar Lap and Rational Systems, excise from the DPMI specification all of the higher-level DOS Extender components, and &#8220;DPMI 0.9&#8221; was born, containing only the low-level building blocks of a DOS Extender. As Andrew Schulman went on to say, the DOS Extender portions of DPMI ended up being split off into their own document:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Microsoft has an internal document (&#8220;MS-DOS API Extensions for DPMI Hosts,&#8221; October 31, 1990) that devotes about 30 pages to the Windows 3.0 DOS extenders&#8230; For example, the 1990 document discusses the 32-bit DOS extender provided by DOSMGR. The DOS file read and write calls (INT 21h functions 3Fh and 40h) have the count register (ECX) extended to 32-bits, allowing 32-bit programs to perform DOS file I/O of more than 64K at a time.</p>
</blockquote>



<p class="wp-block-paragraph"><em>Andrew Schulman, Unauthorized Windows 95, 1994, pp. 151-52</em></p>



<p class="wp-block-paragraph">On the <a href="https://www.pcjs.org/">PCjs website</a>, <a href="https://www.pcjs.org/documents/specs/dpmi/">Version 0.04 from March 1991 of the MS-DOS API Extensions for DPMI </a>Hosts can be found, and it is obviously quite a preliminary document. What it seems is that DPMI was designed simply to expose the Windows DOS Extender (used by the Windows kernel) to other DOS protected-mode software. DPMI sits on the AH=16H Windows/386 part of the INT 2FH multiplex (W386_Int_Multiplex), with the &#8220;Get Protected Mode Switch Entry Point&#8221; API from DPMI even being documented as part of INT2FAPI.INC from the Windows 3.0 DDK as W386_Get_PM_Switch_Addr. The &#8220;Get Selector to Base of LDT&#8221; API from the MS-DOS API Extensions document is even part of INT2FAPI.INC as W386_Get_LDT_Base_Sel. DPMI was defined as an interface for protected-mode DOS software to interface with the <em>Windows</em> (and OS/2) DOS Extenders, and ultimately a subset of the Windows DOS Extender API got standardized and duplicated by other vendors; in effect, DPMI hosts implement a genericized version of the Windows DOS Extender.</p>



<p class="wp-block-paragraph">If you&#8217;re interesting in looking at my code and seeing future developments in the disassembly and W386DBG, check it out at <a href="https://github.com/BHTY/WIN386" target="_blank" rel="noreferrer noopener">https://github.com/BHTY/WIN386</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://virtuallyfun.com/2025/09/06/unauthorized-windows-386/feed/</wfw:commentRss>
			<slash:comments>14</slash:comments>
		
		
			</item>
		<item>
		<title>Microsoft Word 6.0 for PowerPC NT</title>
		<link>https://virtuallyfun.com/2025/08/15/microsoft-word-6-0-for-powerpc-nt/</link>
					<comments>https://virtuallyfun.com/2025/08/15/microsoft-word-6-0-for-powerpc-nt/#comments</comments>
		
		<dc:creator><![CDATA[tenox]]></dc:creator>
		<pubDate>Fri, 15 Aug 2025 07:24:31 +0000</pubDate>
				<category><![CDATA[DEC Alpha]]></category>
		<category><![CDATA[i386]]></category>
		<category><![CDATA[Microsoft Office]]></category>
		<category><![CDATA[microsoft windows]]></category>
		<category><![CDATA[microsoft word]]></category>
		<category><![CDATA[MIPS]]></category>
		<category><![CDATA[powerpc]]></category>
		<category><![CDATA[Windows NT 3.51]]></category>
		<category><![CDATA[Windows NT 4.0]]></category>
		<guid isPermaLink="false">https://virtuallyfun.com/?p=15331</guid>

					<description><![CDATA[(This is a guest post by Antoni Sawicki aka Tenox) It appears that up until just now we did not have archived copy of MS Word 6.0 for PPC. There were copies floating for Alpha and MIPS, for example https://archive.org/details/ms-word60-nt. &#8230; <a href="https://virtuallyfun.com/2025/08/15/microsoft-word-6-0-for-powerpc-nt/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>(This is a guest post by Antoni Sawicki aka Tenox)</em></p>



<p class="wp-block-paragraph">It appears that up until just now we did not have archived copy of MS Word 6.0 for PPC. There were copies floating for Alpha and MIPS, for example <a href="https://archive.org/details/ms-word60-nt">https://archive.org/details/ms-word60-nt</a>. However PPC version was nowhere to be found&#8230;</p>



<p class="wp-block-paragraph">Until Term24 pointed me to this eBay auction:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="987" height="1017" src="https://virtuallyfun.com/wp-content/uploads/2025/08/office.png" alt="" class="wp-image-15332" srcset="https://virtuallyfun.com/wp-content/uploads/2025/08/office.png 987w, https://virtuallyfun.com/wp-content/uploads/2025/08/office-291x300.png 291w, https://virtuallyfun.com/wp-content/uploads/2025/08/office-768x791.png 768w" sizes="auto, (max-width: 987px) 100vw, 987px" /></figure>



<p class="wp-block-paragraph"> Since it clearly said PowerPC on the box I got it&#8230; and here it is:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="819" src="https://virtuallyfun.com/wp-content/uploads/2025/08/ntword1-1024x819.png" alt="" class="wp-image-15333" srcset="https://virtuallyfun.com/wp-content/uploads/2025/08/ntword1-1024x819.png 1024w, https://virtuallyfun.com/wp-content/uploads/2025/08/ntword1-300x240.png 300w, https://virtuallyfun.com/wp-content/uploads/2025/08/ntword1-768x614.png 768w, https://virtuallyfun.com/wp-content/uploads/2025/08/ntword1-375x300.png 375w, https://virtuallyfun.com/wp-content/uploads/2025/08/ntword1.png 1280w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">MS Word 6.0 on Windows NT 4.0 PowerPC / PPC</figcaption></figure>



<p class="wp-block-paragraph">Now thanks to Rairii you can enjoy it on a <a href="https://github.com/Wack0/maciNTosh">PowerMac</a> or <a href="https://github.com/Wack0/entii-for-workcubes">WII</a>!</p>



<p class="wp-block-paragraph">Download <a href="http://tenox.pdp-11.ru/os/winnt/Apps/multicpu/ntword60.iso.lz">ISO</a> or <a href="http://tenox.pdp-11.ru/os/winnt/Apps/multicpu/ntword60.rar">RAR</a></p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://virtuallyfun.com/2025/08/15/microsoft-word-6-0-for-powerpc-nt/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Porting Sarien to OS/2 Presentation Manager</title>
		<link>https://virtuallyfun.com/2024/02/23/porting-sarien-to-os-2-presentation-manager/</link>
					<comments>https://virtuallyfun.com/2024/02/23/porting-sarien-to-os-2-presentation-manager/#comments</comments>
		
		<dc:creator><![CDATA[neozeed]]></dc:creator>
		<pubDate>Fri, 23 Feb 2024 08:27:42 +0000</pubDate>
				<category><![CDATA[80386]]></category>
		<category><![CDATA[i386]]></category>
		<category><![CDATA[OS/2]]></category>
		<category><![CDATA[OS/2 2.0]]></category>
		<category><![CDATA[source code]]></category>
		<guid isPermaLink="false">https://virtuallyfun.com/?p=13998</guid>

					<description><![CDATA[Originally with all the buildup of compilers &#38; GCC ports to OS/2, I had a small goal of getting Sarien running on OS/2. I did have it running on both a 286 &#38; 386 DOS Extender, so the code should &#8230; <a href="https://virtuallyfun.com/2024/02/23/porting-sarien-to-os-2-presentation-manager/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Originally with all the buildup of compilers &amp; GCC ports to OS/2, I had a small goal of getting <a href="https://sourceforge.net/projects/sarien/" target="_blank" rel="noreferrer noopener">Sarien</a> running on OS/2.  I did have it running on both a <a href="https://virtuallyfun.com/2024/01/29/phar-laps-286-dos-extender-why-nobody-used-it-for-games/" target="_blank" rel="noreferrer noopener">286</a> &amp; <a href="https://virtuallyfun.com/2024/02/01/apparently-talking-about-dos-extenders-is-too-hot-for-twitter-aka-phar-lap-386/" target="_blank" rel="noreferrer noopener">386 DOS Extender</a>, so the code should work fine, right?  </p>



<p class="wp-block-paragraph">To recap, years ago I had done a <a href="https://sourceforge.net/projects/quakewordos2/">QuakeWorld</a> port to OS/2 using the full screen VIO mode, a legacy hangover from 16bit OS/2.  It works GREAT on the released 2.00 GA version.  I went through the motion of getting the thunking from 32bit mode to 16bit mode, to find out that it doesn&#8217;t exist in the betas!</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="738" height="197" src="/wp-content/uploads/2024/02/no-vio.png" alt="No VIO for you!" class="wp-image-13991" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/no-vio.png 738w, https://virtuallyfun.com/wp-content/uploads/2024/02/no-vio-300x80.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/no-vio-500x133.png 500w" sizes="auto, (max-width: 738px) 100vw, 738px" /><figcaption class="wp-element-caption">No VIO access from 32bit</figcaption></figure>



<p class="wp-block-paragraph">So that meant I was going to have to break down and do something with Presentation Manager.</p>



<p class="wp-block-paragraph">So the first thing I needed was a program I could basically uplift into what I needed, and I found it through <a href="https://github.com/OS2World/DEV-SAMPLES-C-PM-FastGPI" target="_blank" rel="noreferrer noopener">FastGPI</a>.</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/fastgpi.gif" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="480" height="350" src="/wp-content/uploads/2024/02/fastgpi.gif" alt="" class="wp-image-13999"/></a><figcaption class="wp-element-caption">Donald Graft&#8217;s FastGPI</figcaption></figure>



<p class="wp-block-paragraph">While it was originally built with GCC, I had rebuilt it using Visual C++ 2003 for the math, and the Windows NT 1991 compiler for the front-end.  As you can see it works just fine.  While I&#8217;m not a graphical programmer by any stretch, the source did have some promise in that it creates a bitmap in memory, alters it a runtime, and blits (fast binary copy) it to the Display window.  Just what I need!</p>



<pre class="wp-block-code"><code>  <a href="https://github.com/OS2World/DEV-SAMPLES-C-PM-FastGPI/blob/master/FASTGPI.C#L304C1-L313C4" target="_blank" rel="noreferrer noopener">for</a> (y = 0; y &lt; NUM_MASSES_Y; y++)
  {
    for (x = 0; x &lt; NUM_MASSES_X; x++)
    {
      disp_val = ((int) current&#91;x]&#91;y] + 16);
      if (disp_val &gt; 32) disp_val = 32;
      else if (disp_val &lt; 0) disp_val = 0;
      Bitmap&#91;y*NUM_MASSES_X+x] = RGBmap&#91;disp_val];
    }
  }</code></pre>



<p class="wp-block-paragraph">It goes through the X/Y coordinate plane of the calculated values, and stores them as an RGB mapping into the bitmap.  Seems simple enough right?</p>



<pre class="wp-block-code"><code>  <a href="https://github.com/OS2World/DEV-SAMPLES-C-PM-FastGPI/blob/master/FASTGPI.C#L314C1-L322C32" target="_blank" rel="noreferrer noopener">DosRequestMutexSem</a>(hmtxLock, SEM_INDEFINITE_WAIT);

  /* This is the key to the speed. Instead of doing a GPI call to set the
     color and a GPI call to set the pixel for EACH pixel, we get by
     with only two GPI calls. */
  GpiSetBitmapBits(hpsMemory, 0L, (LONG) (NUM_MASSES_Y-2), &amp;Bitmap&#91;0], pbmi);
  GpiBitBlt(hps, hpsMemory, 3L, aptl, ROP_SRCCOPY, BBO_AND);

  DosReleaseMutexSem(hmtxLock);</code></pre>



<p class="wp-block-paragraph">It then locks the screen memory, and then sets up the copy &amp; uses the magical GpiBitBlt to copy it to the video memory, then releases the lock.  This all looks like something I can totally use!</p>



<p class="wp-block-paragraph">I then have it call the old &#8216;main&#8217; procedure form Sarien <a href="https://github.com/neozeed/sarienPM/blob/220f9424c9a2f4443c6a28acb581bcea3e99b1fb/nullvid.c#L289" target="_blank" rel="noreferrer noopener">as a thread</a>, and have it source the image from the Sarien temporary screen buffer</p>



<pre class="wp-block-code"><code><a href="https://github.com/neozeed/sarienPM/blob/220f9424c9a2f4443c6a28acb581bcea3e99b1fb/nullvid.c#L137C7-L137C59" target="_blank" rel="noreferrer noopener">disp_val</a> = ((int) screen_buffer&#91;y*NUM_MASSES_X+x] );</code></pre>



<p class="wp-block-paragraph">Which all looks simple enough!</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/sarien-rending-wrong-coordinates.png" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="487" height="380" src="/wp-content/uploads/2024/02/sarien-rending-wrong-coordinates.png" alt="" class="wp-image-14001" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/sarien-rending-wrong-coordinates.png 487w, https://virtuallyfun.com/wp-content/uploads/2024/02/sarien-rending-wrong-coordinates-300x234.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/sarien-rending-wrong-coordinates-384x300.png 384w" sizes="auto, (max-width: 487px) 100vw, 487px" /></a><figcaption class="wp-element-caption">Y/X instead of X/Y!</figcaption></figure>



<p class="wp-block-paragraph">And WOW it did something!  I of course, have no keyboard, so can&#8217;t hit enter, and I screwed up the coordinates.  I <a href="https://github.com/neozeed/sarienPM/blob/510150be510351123927d7d1dee5ccd7a4d0e276/text.c#L298" target="_blank" rel="noreferrer noopener">turned off the keyboard read</a>, flipped the X/Y and was greeted with this!</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/sarien-upsidedown.gif" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="480" height="350" src="/wp-content/uploads/2024/02/sarien-upsidedown.gif" alt="" class="wp-image-14002"/></a><figcaption class="wp-element-caption">Welcome to OS/2 where the memory is the total opposite of what you expect.</figcaption></figure>



<p class="wp-block-paragraph">And it&#8217;s backwards. And upside down.  But it clearly is rendering into FastGPI&#8217;s gray palette!  I have to admit I was really shocked it was running!  At this point there is no timer, so it runs at full speed (I&#8217;m using <a href="https://archive.org/details/qemu08_os2_200" target="_blank" rel="noreferrer noopener">Qemu 0.80</a> which is very fast) and even if there was keyboard input it&#8217;d be totally unplayable in this reversed/reversed state.</p>



<p class="wp-block-paragraph">The first thing to do is to flip the display.  I tried messing with how the bitmap was stored, but it had no effect.  Instead, I had to think about how to draw it backwards in RAM.</p>



<pre class="wp-block-code"><code>  {
    <a href="https://github.com/neozeed/sarienPM/blob/05128a9beb9d7226b2d28ba9246d876b45cdce25/nullvid.c#L135" target="_blank" rel="noreferrer noopener">for</a> (x = 0; x &lt; NUM_MASSES_X; x++)
    {
      disp_val = ((int) screen_buffer&#91;y*NUM_MASSES_X+x] );	//+ 16);
      if (disp_val &gt; 32) disp_val = 32;
      else if (disp_val &lt; 0) disp_val = 0;
      Bitmap&#91;((NUM_MASSES_Y-y)*(NUM_MASSES_X))-(NUM_MASSES_X-x)] = RGBmap&#91;disp_val];
    }
  }</code></pre>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/sarien-running-in-the-correct-orientation.png" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="488" height="313" src="/wp-content/uploads/2024/02/sarien-running-in-the-correct-orientation.png" alt="" class="wp-image-14003" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/sarien-running-in-the-correct-orientation.png 488w, https://virtuallyfun.com/wp-content/uploads/2024/02/sarien-running-in-the-correct-orientation-300x192.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/sarien-running-in-the-correct-orientation-468x300.png 468w" sizes="auto, (max-width: 488px) 100vw, 488px" /></a><figcaption class="wp-element-caption">Running in the correct orientation</figcaption></figure>



<p class="wp-block-paragraph">Now comes the next fun part, colour.</p>



<p class="wp-block-paragraph">I had made the decision that since I want to target as many of the OS/2 2.0 betas as possible they will be running at best in 16 colour mode, so I&#8217;ll stick to the CGA 4 colour modes.  So the first thing I need is to find out what the RGB values CGA can display.</p>



<p class="wp-block-paragraph">This handy image is from the <a href="https://www.youtube.com/@The8BitGuy">The 8-Bit Guy&#8217;s</a> video &#8220;<em><a href="https://www.youtube.com/watch?v=niKblgZupOc&amp;t=211s" target="_blank" rel="noreferrer noopener">CGA Graphics &#8211; Not as bad as you thought!</a></em>&#8221; but here are the four possible sets:</p>



<figure class="wp-block-image size-full"><a href="https://www.reddit.com/r/PixelArt/comments/7llned/tool_for_reference_and_inspiration_purposes_a/" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="788" height="440" src="/wp-content/uploads/2024/02/cga-graphics-colours.png" alt="" class="wp-image-14005" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/cga-graphics-colours.png 788w, https://virtuallyfun.com/wp-content/uploads/2024/02/cga-graphics-colours-300x168.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/cga-graphics-colours-768x429.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/02/cga-graphics-colours-500x279.png 500w" sizes="auto, (max-width: 788px) 100vw, 788px" /></a><figcaption class="wp-element-caption">All the possible CGA choices</figcaption></figure>



<p class="wp-block-paragraph">And of course I got super lucky with finding this image:</p>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/02/CGA-colours-in-RGB.png" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="1024" height="183" src="/wp-content/uploads/2024/02/CGA-colours-in-RGB-1024x183.png" alt="" class="wp-image-14006" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/CGA-colours-in-RGB-1024x183.png 1024w, https://virtuallyfun.com/wp-content/uploads/2024/02/CGA-colours-in-RGB-300x54.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/CGA-colours-in-RGB-768x138.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/02/CGA-colours-in-RGB-500x90.png 500w, https://virtuallyfun.com/wp-content/uploads/2024/02/CGA-colours-in-RGB.png 1267w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">So now I could just manually populate the OS/2 palette with the appropriate CGA mapping, just like how it worked in MS-DOS:</p>



<p class="wp-block-paragraph">First define the colours:</p>



<pre class="wp-block-code"><code><a href="https://github.com/neozeed/sarienPM/blob/b543bf63b346065eaeef8c70613f4b600c615dae/nullvid.c#L48" target="_blank" rel="noreferrer noopener">#define</a> CGA_00 0x000000
#define CGA_01 0x0000AA
#define CGA_02 0x00AA00
#define CGA_03 0x00AAAA
#define CGA_04 0xAA0000
#define CGA_05 0xAA00AA
#define CGA_06 0xAA5500
#define CGA_07 0xAAAAAA
#define CGA_08 0x555555
#define CGA_09 0x5555FF
#define CGA_10 0x55FF55
#define CGA_11 0x55FFFF
#define CGA_12 0xFF5555
#define CGA_13 0xFF55FF
#define CGA_14 0xFFFF55
#define CGA_15 0xFFFFFF</code></pre>



<p class="wp-block-paragraph">Then map the 16 colours onto the CGA 4 colours:</p>



<pre class="wp-block-code"><code><a href="https://github.com/neozeed/sarienPM/blob/b543bf63b346065eaeef8c70613f4b600c615dae/nullvid.c#L315" target="_blank" rel="noreferrer noopener">OS2palette</a>&#91;0]=CGA_00;
OS2palette&#91;1]=CGA_11;
OS2palette&#91;2]=CGA_11;
OS2palette&#91;3]=CGA_11;
OS2palette&#91;4]=CGA_13;
OS2palette&#91;5]=CGA_13;
OS2palette&#91;6]=CGA_13;
OS2palette&#91;7]=CGA_15;
OS2palette&#91;8]=CGA_00;
OS2palette&#91;9]=CGA_11;
OS2palette&#91;10]=CGA_11;
OS2palette&#91;11]=CGA_11;
OS2palette&#91;12]=CGA_13;
OS2palette&#91;13]=CGA_13;
OS2palette&#91;14]=CGA_13;
OS2palette&#91;15]=CGA_15;</code></pre>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/sarienpm-cga.gif" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="480" height="350" src="/wp-content/uploads/2024/02/sarienpm-cga.gif" alt="" class="wp-image-14007"/></a><figcaption class="wp-element-caption">CGA on PM!</figcaption></figure>



<p class="wp-block-paragraph">So now it&#8217;s looking right but there is no timer so on modern machines via emulation it runs at warp speed.  And that&#8217;s where OS/2 shows its origins is that it&#8217;s timer ticks about every 32ms, so having a high resolution timer is basically out of the question.  There may have been options later one, but those most definitively will not be an option for early betas.  I thought I could do a simple thread that counts and sleeps, as hooking events and alarms again suffer from the 32ms tick resolution problem so maybe a sleeping thread is good enough.</p>



<pre class="wp-block-code"><code><a href="https://github.com/neozeed/sarienPM/commit/ee1d0a0f4005829988bd0cda45f2fd1da238f5da#diff-04eb7ebfe907f64a72da508ac89ec2385ecbd0bb9064a27d17f230f18f473a5dR114" target="_blank" rel="noreferrer noopener">static</a> void Timer(){
for(;;){
	DosSleep(20);
	clock_ticks++;
	}
}
</code></pre>



<p class="wp-block-paragraph">And it crashed.  Turns out that I wasn&#8217;t doing the threads correctly and was blowing their stack.  And somehow the linker definition file from FastGPI kept sneaking back in, lowering the stack as well.</p>



<p class="wp-block-paragraph">Eventually <a href="https://github.com/neozeed/sarienPM/commit/78f7773e448734c1f62d830b31a7ff2bfcd31316">I got it sorted out</a>.</p>



<p class="wp-block-paragraph">The next big challenge came of course from the keyboard.  And I really struggled here as finding solid documentation on how to do this is not easy to come by.  Both Bing/google want to suggest articles about OS/2 and why it failed (hint it&#8217;s the PS/2 model 60), but nothing much on actually being useful about it.</p>



<p class="wp-block-paragraph">Eventually through a lot of trial and error, well a lot of errors I had worked uppon this:</p>



<pre class="wp-block-code"><code>    case WM_CHAR:
      if (SHORT1FROMMP(parm1) &amp; KC_KEYUP)
        break;
pm_keypress=1;
      switch (SHORT1FROMMP(parm1))
      {
      	case VK_LEFT:
	key_from=KEY_LEFT;
	break;
	case VK_RIGHT:
	key_from=KEY_RIGHT;
	break;
	case VK_UP:
	key_from=KEY_UP;
	break;
	case VK_DOWN:
	key_from=KEY_DOWN;
	break;

	case KC_VIRTUALKEY:
	default:
	key_from=SHORT1FROMMP(parm2);
	break;
      } </code></pre>



<p class="wp-block-paragraph">I had cheated and just introduced 2 new variables, <a href="https://github.com/neozeed/sarienPM/blob/a778c90b293fbfacf0b55ad57ead7aab39ece06b/nullvid.c#L92C1-L93C24" target="_blank" rel="noreferrer noopener">key_from, pm_keypress</a> to signal a key had been pressed and which key it was.  I had issues mapping certain keys so it was easier to just manually map the VK_ mapping from OS/2 into the KEY_ for Sarien.  So it triggers only on single key down events, and handles only one at a time.  So for fast typers this sucks, but I didn&#8217;t want to introduce more mutexes, more locking and queues or DIY circular buffers.  I&#8217;m at the KISS stage still.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><a href="/wp-content/uploads/2024/02/sarien-incomplete-keyboard.png" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="268" height="36" src="/wp-content/uploads/2024/02/sarien-incomplete-keyboard.png" alt="" class="wp-image-14008"/></a></figure>
</div>


<p class="wp-block-paragraph">I&#8217;m not sure why it was dropping letters, I would hit &#8216;d&#8217; all I wanted and it never showed up.  I then recompiled the entire thing and with the arrow keys now mapped I could actually move!</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/first-steps-in-sarien.png" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="532" height="396" src="/wp-content/uploads/2024/02/first-steps-in-sarien.png" alt="" class="wp-image-14009" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/first-steps-in-sarien.png 532w, https://virtuallyfun.com/wp-content/uploads/2024/02/first-steps-in-sarien-300x223.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/first-steps-in-sarien-403x300.png 403w" sizes="auto, (max-width: 532px) 100vw, 532px" /></a><figcaption class="wp-element-caption">Roger walks for the first time!</figcaption></figure>



<p class="wp-block-paragraph">And just like that, Roger Wilco now walks.</p>



<p class="wp-block-paragraph">From there I added the savegame fixes I did for the 286/386 versions, along with trying to not paint every frame with a simple frame skip and&#8230;</p>



<figure class="wp-block-video"><video height="720" style="aspect-ratio: 1280 / 720;" width="1280" controls src="/wp-content/uploads/2024/02/IMG_1148.mp4"></video><figcaption class="wp-element-caption">Sarien for OS/2 running at 16Mhz</figcaption></figure>



<p class="wp-block-paragraph">And it&#8217;s basically unplayable on my PS/2 model 80. Even with the 32bit XGA-2 video card.</p>



<p class="wp-block-paragraph">I had to give it a shot under 86Box, to try the CGA/EGA versions:</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/Sarien-on-CGA-OS2.png" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="1006" height="905" src="/wp-content/uploads/2024/02/Sarien-on-CGA-OS2.png" alt="" class="wp-image-14012" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/Sarien-on-CGA-OS2.png 1006w, https://virtuallyfun.com/wp-content/uploads/2024/02/Sarien-on-CGA-OS2-300x270.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/Sarien-on-CGA-OS2-768x691.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/02/Sarien-on-CGA-OS2-333x300.png 333w" sizes="auto, (max-width: 1006px) 100vw, 1006px" /></a><figcaption class="wp-element-caption">CGA</figcaption></figure>



<p class="wp-block-paragraph">It&#8217;s weird how the image distorts!  Although the black and white mapping seems to work fine.</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/Sarien-on-EGA-OS2.png" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="693" height="436" src="/wp-content/uploads/2024/02/Sarien-on-EGA-OS2.png" alt="" class="wp-image-14013" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/Sarien-on-EGA-OS2.png 693w, https://virtuallyfun.com/wp-content/uploads/2024/02/Sarien-on-EGA-OS2-300x189.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/Sarien-on-EGA-OS2-477x300.png 477w" sizes="auto, (max-width: 693px) 100vw, 693px" /></a><figcaption class="wp-element-caption">Sarien on EGA</figcaption></figure>



<p class="wp-block-paragraph">I should also point out that the CGA/EGA versions are running on OS/2 2.0 Beta 6.123, which currently is the oldest beta I can get a-hold of.  So at the least I did reach my goal of having a 32bit version for early OS/2.</p>



<p class="wp-block-paragraph">I would imagine it running okay on any type of Pentium system, however.  So, what would the advantage of this, vs just running the original game in a dos box?  Well, it is a native 32bit app.  This is the future that was being sold to us back in 1990. I&#8217;m sure the native assembly that Sierra used was far more efficient and would have made more sense to just be a full screened 16bit VIO application.</p>



<p class="wp-block-paragraph">So how long did it take to get from there to here?  Shockingly not that much time, <em>— </em>02/20/2024 6:02 PM for running FastGPI, to <em>— </em>02/20/2024 10:56 PM For the first image being displayed in Presentation Manager, and finally <em>— </em>02/21/2024 10:39 PM to when I was first able to walk.  As you can see, that is NOT a lot of time.  Granted I have a substantially faster machine today than what I&#8217;d have in 1990 (I didn&#8217;t get a 286 until late 91? early 92?), compiling Sarien on the PS/2 takes 30-40 minutes and that&#8217;s with the ultra-fast BlueSCSI, compared to even using <a href="http://takeda-toshiya.my.coocan.jp/msdos/" target="_blank" rel="noreferrer noopener">MS-DOS Player</a> I can get a build in about a minute without even compiling in parallel.</p>



<p class="wp-block-paragraph">I&#8217;ve put the source over on github: <a href="https://github.com/neozeed/sarienPM">neozeed/sarienPM: Sarien for OS/2 (github.com)</a></p>



<p class="wp-block-paragraph">I think the best way to distribute this is in object form, so I&#8217;ve created <a href="https://github.com/neozeed/sarienPM/releases/tag/v0_0.2" target="_blank" rel="noreferrer noopener">both a zip &amp; disk image containing the source &amp; objects</a>, so you can link natively on your machine, just copy the contents of the floppy somewhere and just run &#8216;build.cmd&#8217; which will invoke the system linker, LINK386 to do it&#8217;s job.  I have put both the libc &amp; os2386 libraries on the disk so it should just work about everywhere.  Or it did for me!</p>



<p class="wp-block-paragraph">So that&#8217;s my quick story over the last few days working on &amp; off on this simple port of Sarien to OS/2 Presentation Manager.  As always, I want to give <a href="https://www.patreon.com/virtuallyfun" target="_blank" rel="noreferrer noopener">thanks to my Patrons</a>!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://virtuallyfun.com/2024/02/23/porting-sarien-to-os-2-presentation-manager/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
		<item>
		<title>Thunking for fun &#038; a lack of profit</title>
		<link>https://virtuallyfun.com/2024/02/19/thunking-for-fun-a-lack-of-profit/</link>
					<comments>https://virtuallyfun.com/2024/02/19/thunking-for-fun-a-lack-of-profit/#respond</comments>
		
		<dc:creator><![CDATA[neozeed]]></dc:creator>
		<pubDate>Mon, 19 Feb 2024 00:35:16 +0000</pubDate>
				<category><![CDATA[80386]]></category>
		<category><![CDATA[assembly]]></category>
		<category><![CDATA[gcc]]></category>
		<category><![CDATA[i386]]></category>
		<category><![CDATA[OS/2]]></category>
		<category><![CDATA[OS/2 2.0]]></category>
		<guid isPermaLink="false">https://virtuallyfun.com/?p=13988</guid>

					<description><![CDATA[So, with a renewed interest in OS/2 betas, I&#8217;d been getting stuff into the direction of doing some full screen video. I&#8217;d copied and pasted stuff before and gotten QuakeWorld running, and I was looking forward to this challenge. The &#8230; <a href="https://virtuallyfun.com/2024/02/19/thunking-for-fun-a-lack-of-profit/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">So, with a renewed interest in OS/2 betas, I&#8217;d been getting stuff into the direction of doing some full screen video.  I&#8217;d copied and pasted stuff before and gotten QuakeWorld running, and I was looking forward to this challenge.  The whole thing hinges on the VIO calls in OS/2 like VioScrLock, VioGetPhysBuf, VioScrUnLock etc etc.  I found a nifty sample program <a href="https://jeffpar.github.io/kbarchive/kb/059/Q59837/" target="_blank" rel="noreferrer noopener">Q59837</a> which shows how to map into the MDA card&#8217;s text RAM and clear it.</p>



<p class="wp-block-paragraph">It&#8217;s a 16bit program, but first I got it to run on EMX with just a few minor changes, like removing far pointers.  Great.  But I wanted to build it with my <a href="https://virtuallyfun.com/2024/02/11/targeting-os-2-with-visual-studio-2003/" target="_blank" rel="noreferrer noopener">cl386 experiments</a> and that went off the edge.  First there are some very slick macros, and Microsoft C just can&#8217;t deal with them.  Fine I&#8217;ll use <a href="https://virtuallyfun.com/2024/02/10/porting-gcc-to-32bit-os-2/" target="_blank" rel="noreferrer noopener">GCC</a>.  Then I had to get emximpl working so I could build an import library for VIO calls.  I exported the assembly from GCC, and mangled it enough to where I could link it with the old Microsoft linker, and things were looking good!  I could clear the video buffer on OS/2 2.00 GA.</p>



<p class="wp-block-paragraph">Now why was it working? What is a THUNK?  Well it turns out in the early OS/2 2.0 development, they were going to cut loose all the funky text mode video, keyboard &amp; mouse support and go all in on the graphical Presentation Manager.</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/605-busy-desktop.png" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="797" height="593" src="/wp-content/uploads/2024/02/605-busy-desktop.png" alt="" class="wp-image-13992" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/605-busy-desktop.png 797w, https://virtuallyfun.com/wp-content/uploads/2024/02/605-busy-desktop-300x223.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/605-busy-desktop-768x571.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/02/605-busy-desktop-403x300.png 403w" sizes="auto, (max-width: 797px) 100vw, 797px" /></a><figcaption class="wp-element-caption">Presentation Manager from OS/2 6.605</figcaption></figure>



<p class="wp-block-paragraph">Instead, they were going to leave that old stuff in the past, and 16bit only for keeping some backwards compatibility.  And the only way a 32bit program can use those old 16bit API&#8217;s for video/keyboard/mouse (etc) is to call from 32bit mode into 16bit mode, then copy that data out of 16bit mode into 32bit mode.  This round trip is called thunking, and well this sets up where it all goes wrong. </p>



<p class="wp-block-paragraph">Then I tried one of the earlier PM looking betas <a href="https://archive.org/details/os2-2.0-6.605" target="_blank" rel="noreferrer noopener">6.605</a>, and quickly it crashed!</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="887" height="292" src="/wp-content/uploads/2024/02/SYS_2070.png" alt="" class="wp-image-13989" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/SYS_2070.png 887w, https://virtuallyfun.com/wp-content/uploads/2024/02/SYS_2070-300x99.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/SYS_2070-768x253.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/02/SYS_2070-500x165.png 500w" sizes="auto, (max-width: 887px) 100vw, 887px" /><figcaption class="wp-element-caption">SYS2070:</figcaption></figure>



<p class="wp-block-paragraph">Well this was weird.  Obviously, I wanted to display help</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="895" height="362" src="/wp-content/uploads/2024/02/SYS_2070_2.png" alt="" class="wp-image-13990" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/SYS_2070_2.png 895w, https://virtuallyfun.com/wp-content/uploads/2024/02/SYS_2070_2-300x121.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/SYS_2070_2-768x311.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/02/SYS_2070_2-500x202.png 500w" sizes="auto, (max-width: 895px) 100vw, 895px" /><figcaption class="wp-element-caption">Explanation:</figcaption></figure>



<p class="wp-block-paragraph">This ended up being a long winded way of saying that there is missing calls from DOSCALL1.DLL.  Looking through all the EMX thunking code, I came to the <a href="https://github.com/neozeed/Q59837-mono/blob/main/thunk0.asm#L12" target="_blank" rel="noreferrer noopener">low level assembly</a>, that actually implemented the thunking.</p>



<pre class="wp-block-code"><code>EXTRN   DosFlatToSel:PROC
EXTRN   DosSelToFlat:PROC</code></pre>



<p class="wp-block-paragraph">After looking at the doscalls import library, sure enough they just don&#8217;t exist.  I did the most unspeakable thing and looked at the online help for guidance:</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/no-vio.png" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="738" height="197" src="/wp-content/uploads/2024/02/no-vio.png" alt="" class="wp-image-13991" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/no-vio.png 738w, https://virtuallyfun.com/wp-content/uploads/2024/02/no-vio-300x80.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/no-vio-500x133.png 500w" sizes="auto, (max-width: 738px) 100vw, 738px" /></a><figcaption class="wp-element-caption">No VIO</figcaption></figure>



<p class="wp-block-paragraph">So it turns out that in the early beta phase, there was no support for any of the 16bit IO from 32bit mode.  There was no thunking at all.  You were actually expected to use Presentation Manager.</p>



<p class="wp-block-paragraph">YUCK</p>



<p class="wp-block-paragraph">For anyone crazy enough to care, I uploaded this onto github <a href="https://github.com/neozeed/Q59837-mono/" target="_blank" rel="noreferrer noopener">Q59837-mono</a></p>



<p class="wp-block-paragraph">It did work on the GA however so I guess I&#8217;m still on track there.  </p>
]]></content:encoded>
					
					<wfw:commentRss>https://virtuallyfun.com/2024/02/19/thunking-for-fun-a-lack-of-profit/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>New version of the MS-DOS Player</title>
		<link>https://virtuallyfun.com/2024/02/16/new-version-of-the-ms-dos-player/</link>
					<comments>https://virtuallyfun.com/2024/02/16/new-version-of-the-ms-dos-player/#comments</comments>
		
		<dc:creator><![CDATA[neozeed]]></dc:creator>
		<pubDate>Fri, 16 Feb 2024 10:05:00 +0000</pubDate>
				<category><![CDATA[80286]]></category>
		<category><![CDATA[80386]]></category>
		<category><![CDATA[i386]]></category>
		<category><![CDATA[MS-DOS]]></category>
		<guid isPermaLink="false">https://virtuallyfun.com/?p=13960</guid>

					<description><![CDATA[And it&#8217;s a big update on takeda-toshiya.my.coocan.jp! From&#160;cracyc&#160;and&#160;roytam&#8217;s&#160;fork, I have incorporated a correction.These include file access using FCB and fixing exceptions around the FPU of the MAME version of the i386 core.In addition, the DAA/DAS/AAA/AAS/AAM/AAD instructions of the MAME version &#8230; <a href="https://virtuallyfun.com/2024/02/16/new-version-of-the-ms-dos-player/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">And it&#8217;s a big update on <a href="http://takeda-toshiya.my.coocan.jp/msdos/" target="_blank" rel="noreferrer noopener">takeda-toshiya.my.coocan.jp</a>!</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">From&nbsp;<a href="https://github.com/cracyc/msdos-player">cracyc</a>&nbsp;and&nbsp;<a href="https://github.com/roytam1/msdos-player">roytam&#8217;s</a>&nbsp;fork, I have incorporated a correction.<br>These include file access using FCB and fixing exceptions around the FPU of the MAME version of the i386 core.<br>In addition, the DAA/DAS/AAA/AAS/AAM/AAD instructions of the MAME version of the i386 core have been modified based on the DOSBox implementation.<br>With the Pentium 4 version, the testi386.exe is the same as the real thing.</p>



<p class="wp-block-paragraph">The I386 core of NP21/W has been updated to equivalent to ver0.86 rev92 beta2.<br>Also, fixed the build time warning so that it does not appear.</p>



<p class="wp-block-paragraph">Improved checking when accessing environment variables, referencing incorrect environment tables.<br>Recent builds have resolved an issue that prevented testi386.exe from working.<br>Improved the efficiency of memory access handling.<br>Basic memory, extended memory, and reserved areas (such as VRAM) can be accessed in that order with a small number of conditional branches.<br>The processing speed may be slightly increased.</p>
<cite><a href="http://takeda-toshiya.my.coocan.jp/msdos/">MS-DOS Player for Win32-x64 Mystery WIP Page (coocan.jp)</a></cite></blockquote>



<p class="wp-block-paragraph">Takeda has been very busy indeed!</p>



<p class="wp-block-paragraph">I don&#8217;t want to complain or anything, I&#8217;m very thankful for the tool. It&#8217;s just so amazing.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="395" height="152" src="/wp-content/uploads/2024/02/msdos-player-console-size-change-crash.png" alt="" class="wp-image-13961" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/msdos-player-console-size-change-crash.png 395w, https://virtuallyfun.com/wp-content/uploads/2024/02/msdos-player-console-size-change-crash-300x115.png 300w" sizes="auto, (max-width: 395px) 100vw, 395px" /></figure>
</div>


<p class="wp-block-paragraph"> but on my Windows 10 install I have so many issues relating to the font/screen changes, that I just made an incredibly lame fork, and commented out those changes, <a href="https://github.com/neozeed/msdos-player_" target="_blank" rel="noreferrer noopener">msdos-player_</a>.  I stumbled onto the issue by accident by redirecting stdout/stderr, and compiling stuff ran fine, but as soon as it started to mess with the console it&#8217;d just crash.</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/building-TREK-using-msdos-player-as-the-magic-glue.png" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="979" height="512" src="/wp-content/uploads/2024/02/building-TREK-using-msdos-player-as-the-magic-glue.png" alt="" class="wp-image-13962" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/building-TREK-using-msdos-player-as-the-magic-glue.png 979w, https://virtuallyfun.com/wp-content/uploads/2024/02/building-TREK-using-msdos-player-as-the-magic-glue-300x157.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/building-TREK-using-msdos-player-as-the-magic-glue-768x402.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/02/building-TREK-using-msdos-player-as-the-magic-glue-500x261.png 500w" sizes="auto, (max-width: 979px) 100vw, 979px" /></a><figcaption class="wp-element-caption">No console changes, no crashes.</figcaption></figure>



<p class="wp-block-paragraph">OK so you can run some basic stuff like compilers, but what about ORACLE?!</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/oracle-5-on-msdos-player.png" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="979" height="512" src="/wp-content/uploads/2024/02/oracle-5-on-msdos-player.png" alt="" class="wp-image-13968" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/oracle-5-on-msdos-player.png 979w, https://virtuallyfun.com/wp-content/uploads/2024/02/oracle-5-on-msdos-player-300x157.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/oracle-5-on-msdos-player-768x402.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/02/oracle-5-on-msdos-player-500x261.png 500w" sizes="auto, (max-width: 979px) 100vw, 979px" /></a><figcaption class="wp-element-caption">Oracle 5!</figcaption></figure>



<p class="wp-block-paragraph">I did have to subst a drive, as I didn&#8217;t feel like dealing with paths and stuff, I had extracted it from <a href="https://archive.org/details/oracle-51c-qemu" target="_blank" rel="noreferrer noopener">oracle-51c-qemu</a>, and modified the autoexec &amp; config.ora and yeah, using the 386 or better emulation it just worked!  Sadly there is no network part of the install, although there is a SDK so I guess there ought to be a way to proxy queries.</p>



<p class="wp-block-paragraph">OK, but how about something even more complicated?!  <strong><span style="text-decoration: underline;">NETWARE</span></strong>!</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="642" height="432" src="/wp-content/uploads/2024/02/netware-on-msdos-player.png" alt="" class="wp-image-13970" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/netware-on-msdos-player.png 642w, https://virtuallyfun.com/wp-content/uploads/2024/02/netware-on-msdos-player-300x202.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/netware-on-msdos-player-446x300.png 446w" sizes="auto, (max-width: 642px) 100vw, 642px" /><figcaption class="wp-element-caption">Netware 3.12 on MS-DOS Player</figcaption></figure>



<p class="wp-block-paragraph">Obviously there is no ISA MFM/IDE disks in MS-DOS Player, but the server loaded!</p>



<p class="wp-block-paragraph">Needless to say this update is just <strong><em>GREAT</em></strong>!</p>



<p class="wp-block-paragraph"> I&#8217;d say try the one hosted on Takeda&#8217;s site!  It&#8217;ll almost certainly work fine for you.  Otherwise I guess try mine.  Or not.</p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://virtuallyfun.com/2024/02/16/new-version-of-the-ms-dos-player/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Totally unfair comparison of Microsoft C</title>
		<link>https://virtuallyfun.com/2024/02/05/totally-unfair-comparison-of-microsoft-c/</link>
					<comments>https://virtuallyfun.com/2024/02/05/totally-unfair-comparison-of-microsoft-c/#respond</comments>
		
		<dc:creator><![CDATA[neozeed]]></dc:creator>
		<pubDate>Mon, 05 Feb 2024 03:15:48 +0000</pubDate>
				<category><![CDATA[80386]]></category>
		<category><![CDATA[assembly]]></category>
		<category><![CDATA[i386]]></category>
		<category><![CDATA[microsoft]]></category>
		<category><![CDATA[OS/2]]></category>
		<category><![CDATA[OS/2 2.0]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Win32]]></category>
		<guid isPermaLink="false">https://virtuallyfun.com/?p=13896</guid>

					<description><![CDATA[Because I hate myself, I tried to get the Microsoft OS/2 Beta 2 SDK&#8217;s C compiler building simple stuff for text mode NT. Because, why not?! Since the object files won&#8217;t link, we have to go in with assembly. And &#8230; <a href="https://virtuallyfun.com/2024/02/05/totally-unfair-comparison-of-microsoft-c/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Because I hate myself, I tried to get the Microsoft OS/2 Beta 2 SDK&#8217;s C compiler building simple stuff for text mode NT.  Because, why not?!</p>



<p class="wp-block-paragraph">Since the object files won&#8217;t link, we have to go in with assembly.  And that of course doesn&#8217;t directly assemble, but it just needs a little hand holding:</p>



<pre class="wp-block-code"><code>Microsoft (R) Program Maintenance Utility   Version 1.40
Copyright (c) Microsoft Corp 1988-93. All rights reserved.

        cl386 /Ih /Ox /Zi /c /Fadhyrst.a dhyrst.c
Microsoft (R) Microsoft 386 C Compiler. Version 1.00.075
Copyright (c) Microsoft Corp 1984-1989. All rights reserved.

dhyrst.c
        wsl sed -e 's/FLAT://g' dhyrst.a &gt; dhyrst.a1
        wsl sed -e "s/DQ\t&#91;0-9a-f]*r/&amp;XMMMMMMX/g" dhyrst.a1  | wsl sed -e "s/rXMMMMMMX/H/g" &gt; dhyrst.asm
        ml /c dhyrst.asm
Microsoft (R) Macro Assembler Version 6.11
Copyright (C) Microsoft Corp 1981-1993.  All rights reserved.

 Assembling: dhyrst.asm
        del dhyrst.a dhyrst.a1 dhyrst.asm
        link -debug:full -out:dhyrst.exe dhyrst.obj libc.lib
Microsoft (R) 32-Bit Executable Linker Version 1.00
Copyright (C) Microsoft Corp 1992-93. All rights reserved.
</code></pre>



<p class="wp-block-paragraph">I use sed to remove the FLAT: directives which makes everything upset.  Also there is some weird confusion on how to pad float constants and encode them.</p>



<pre class="wp-block-code"><code>CONST   SEGMENT  DWORD USE32 PUBLIC 'CONST'
$T20001         DQ      0040f51800r    ;        86400.00000000000
CONST      ENDS</code></pre>



<p class="wp-block-paragraph">MASM 6.11 is very update with this.  I just padded it with more zeros, but it just hung.  I suspect DQ isn&#8217;t the right size?  I&#8217;m not 386 MASM junkie.  I&#8217;m at least getting the assembler to shut-up but it doesn&#8217;t work right. I&#8217;ll have to look more into it.</p>



<p class="wp-block-paragraph">Xenix 386 also includes an earlier version of Microsoft C / 386, and it formats the float like this:</p>



<pre class="wp-block-code"><code>CONST   SEGMENT  DWORD USE32 PUBLIC 'CONST'
$T20000         DQ      0040f51800H    ;        86400.00000000000
CONST      ENDS</code></pre>



<p class="wp-block-paragraph">So I had thought maybe if I replace the &#8216;r&#8217; with a &#8216;H&#8217; that might be enough?  The only annoying thing about the Xenix compiler is that it was K&amp;R so I spent a few minutes porting phoon to K&amp;R, dumped the assembly and came up with this sed string to find the pattern, mark it, and replace it (Im not that good at this stuff)</p>



<pre class="wp-block-code"><code>wsl sed -e "s/DQ\t&#91;0-9a-f]<em>r/&amp;XMMMMMMX/g" $</em>.a1 \
| wsl sed -e "s/rXMMMMMMX/H/g" > $*.asm</code></pre>



<p class="wp-block-paragraph">While it compiles with no issues, and runs, it just hangs.  I tried the transplanted Xenix assembly and it just hangs as well.  Clearly there is something to do with how to use floats.</p>



<p class="wp-block-paragraph">I then looked at whetstone, and after building it noticed this is the output compiling with Visual C++ 8.0</p>



<pre class="wp-block-code"><code>      0       0       0  1.0000e+000 -1.0000e+000 -1.0000e+000 -1.0000e+000
  12000   14000   12000 -1.3190e-001 -1.8218e-001 -4.3145e-001 -4.8173e-001
  14000   12000   12000  2.2103e-002 -2.7271e-002 -3.7914e-002 -8.7290e-002
 345000       1       1  1.0000e+000 -1.0000e+000 -1.0000e+000 -1.0000e+000
 210000       1       2  6.0000e+000  6.0000e+000 -3.7914e-002 -8.7290e-002
  32000       1       2  5.0000e-001  5.0000e-001  5.0000e-001  5.0000e-001
 899000       1       2  1.0000e+000  1.0000e+000  9.9994e-001  9.9994e-001
 616000       1       2  3.0000e+000  2.0000e+000  3.0000e+000 -8.7290e-002
      0       2       3  1.0000e+000 -1.0000e+000 -1.0000e+000 -1.0000e+000
  93000       2       3  7.5000e-001  7.5000e-001  7.5000e-001  7.5000e-001</code></pre>



<p class="wp-block-paragraph">However this is the output from C/386:</p>



<pre class="wp-block-code"><code>      0       0       0  5.2998e-315  1.5910e-314  1.5910e-314  1.5910e-314
  12000   14000   12000  0.0000e+000  0.0000e+000  0.0000e+000  0.0000e+000
  14000   12000   12000  0.0000e+000  0.0000e+000  0.0000e+000  0.0000e+000
 345000       1       1  5.2998e-315  1.5910e-314  1.5910e-314  1.5910e-314
 210000       1       2  6.0000e+000  6.0000e+000  0.0000e+000  0.0000e+000
  32000       1       2  5.2946e-315  5.2946e-315  5.2946e-315  5.2946e-315
 899000       1       2  5.2998e-315  5.2998e-315  0.0000e+000  0.0000e+000
 616000       1       2  5.3076e-315  5.3050e-315  5.3076e-315  0.0000e+000
      0       2       3  5.2998e-315  1.5910e-314  1.5910e-314  1.5910e-314
  93000       2       3  5.2972e-315  5.2972e-315  5.2972e-315  5.2972e-315</code></pre>



<p class="wp-block-paragraph">Great they look nothing alike. So something it totally broken.  I guess the real question is, does it even work on OS/2?</p>



<p class="wp-block-paragraph">Since I should post the NMAKE Makefile so I can remember how it can do custom steps so I can edit the intermediary files.  Isn&#8217;t C fun?!</p>



<pre class="wp-block-code"><code>INC = /Ih
OPT = /Ox
DEBUG = /Zi
CC = cl386

OBJ = dhyrst.obj

.c.obj:
	$(CC) $(INC) $(OPT) $(DEBUG) /c /Fa$*.a $*.c
	wsl sed -e 's/FLAT://g' $*.a &gt; $*.a1
	wsl sed -e "s/DQ\t&#91;0-9a-f]*r/&amp;XMMMMMMX/g" $*.a1 \
	| wsl sed -e "s/rXMMMMMMX/H/g" &gt; $*.asm
	ml /c $*.asm
	del $*.a $*.a1 $*.asm

dhyrst.exe: $(OBJ)
        link -debug:full -out:dhyrst.exe $(OBJ) libc.lib

clean:
        del $(OBJ)
        del dhyrst.exe
        del *.asm *.a *.a1</code></pre>



<p class="wp-block-paragraph">As you can see, I&#8217;m using /Ox or maximum speed!  So how does it compare?</p>



<pre class="wp-block-code"><code>Dhrystone(1.1) time for 180000000 passes = 20
This machine benchmarks at 9000000 dhrystones/second</code></pre>



<p class="wp-block-paragraph">And for the heck of it, how does Visual C++ 1.0&#8217;s performance compare?</p>



<pre class="wp-block-code"><code>Dhrystone(1.1) time for 180000000 passes = 7<br>This machine benchmarks at 25714285 dhrystones/second</code></pre>



<p class="wp-block-paragraph">That&#8217;s right the 1989 compiler is 35% the speed of the 1993 compiler. wow.  Also it turns out that MASM 6.11 actually can (mostly) assemble the output of this ancient compiler.  It&#8217;s nice when something kind of work.  I can also add that the Infocom &#8217;87 interpreter works as well. </p>



<p class="wp-block-paragraph">YAY!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://virtuallyfun.com/2024/02/05/totally-unfair-comparison-of-microsoft-c/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Apparently talking about DOS Extenders is too hot for Twitter: AKA Phar Lap 386</title>
		<link>https://virtuallyfun.com/2024/02/01/apparently-talking-about-dos-extenders-is-too-hot-for-twitter-aka-phar-lap-386/</link>
					<comments>https://virtuallyfun.com/2024/02/01/apparently-talking-about-dos-extenders-is-too-hot-for-twitter-aka-phar-lap-386/#comments</comments>
		
		<dc:creator><![CDATA[neozeed]]></dc:creator>
		<pubDate>Thu, 01 Feb 2024 19:15:17 +0000</pubDate>
				<category><![CDATA[80386]]></category>
		<category><![CDATA[dos extenders]]></category>
		<category><![CDATA[games]]></category>
		<category><![CDATA[i386]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[random updates]]></category>
		<category><![CDATA[Watcom C++]]></category>
		<guid isPermaLink="false">https://virtuallyfun.com/?p=13859</guid>

					<description><![CDATA[I had a small twitter account, and I tried not to get dragged into anything that would just be basically wasting my time. Just stay focused and on topic. FINE. I just wanted to see if anyone ever saw it, &#8230; <a href="https://virtuallyfun.com/2024/02/01/apparently-talking-about-dos-extenders-is-too-hot-for-twitter-aka-phar-lap-386/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I had a small twitter account, and I tried not to get dragged into anything that would just be basically wasting my time. Just stay focused and on topic. <em>FINE</em>.  I just wanted to see if anyone ever saw it, if it was even worth the effort of doing WIP&#8217;s as I didn&#8217;t want to make it super annoying.</p>



<figure class="wp-block-image size-full"><a href="https://twitter.com/virtuallyfun" target="_blank" rel="noreferrer noopener"><img loading="lazy" decoding="async" width="786" height="537" src="/wp-content/uploads/2024/02/twitter-profile.png" alt="" class="wp-image-13860" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-profile.png 786w, https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-profile-300x205.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-profile-768x525.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-profile-439x300.png 439w" sizes="auto, (max-width: 786px) 100vw, 786px" /></a></figure>



<p class="wp-block-paragraph">I logged on to post a fun update that I&#8217;d finally gotten a Phar Lap 386 version 4.1 app to do something halfway useful, the sairen AGI interpreter up and running in the most basic sense.</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/twitter-flagged.png"><img loading="lazy" decoding="async" width="738" height="336" src="/wp-content/uploads/2024/02/twitter-flagged.png" alt="" class="wp-image-13861" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-flagged.png 738w, https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-flagged-300x137.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-flagged-500x228.png 500w" sizes="auto, (max-width: 738px) 100vw, 738px" /></a><figcaption class="wp-element-caption">Talking about DOS Extenders is spammy and manipulation!</figcaption></figure>



<p class="wp-block-paragraph">I don&#8217;t get what triggered it, but oh well there was a &#8216;have a review&#8217; and yeah that was fine. Great.  So I&#8217;m unlocked so I go ahead and post with the forbidden topic, as I&#8217;m clearly dumb, and forgetting that Twitter is for hate mobs &amp; posting pictures of food, and cat pictures.</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/twitter-last-post.png"><img loading="lazy" decoding="async" width="743" height="471" src="/wp-content/uploads/2024/02/twitter-last-post.png" alt="" class="wp-image-13862" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-last-post.png 743w, https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-last-post-300x190.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-last-post-473x300.png 473w" sizes="auto, (max-width: 743px) 100vw, 743px" /></a><figcaption class="wp-element-caption">The Sairen AGI interpreter built with Watcom 386/7.0 &amp; Phar Lap 386 4.1   </figcaption></figure>



<p class="wp-block-paragraph">So yes, that was a line too far, and now that&#8217;s it.</p>



<p class="wp-block-paragraph">Now some of you may think, if you buy &#8216;the plan&#8217; you&#8217;ll no doubt be exempt from the heavy hands of Twitter</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="339" height="151" src="/wp-content/uploads/2024/02/Screenshot-2024-02-01-192733.png" alt="" class="wp-image-13881" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/Screenshot-2024-02-01-192733.png 339w, https://virtuallyfun.com/wp-content/uploads/2024/02/Screenshot-2024-02-01-192733-300x134.png 300w" sizes="auto, (max-width: 339px) 100vw, 339px" /><figcaption class="wp-element-caption">3 squids a month</figcaption></figure>
</div>


<p class="wp-block-paragraph">But I already was and had been for a while.</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/twitter-your-account-is-suspended.png"><img loading="lazy" decoding="async" width="695" height="201" src="/wp-content/uploads/2024/02/twitter-your-account-is-suspended.png" alt="" class="wp-image-13863" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-your-account-is-suspended.png 695w, https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-your-account-is-suspended-300x87.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-your-account-is-suspended-500x145.png 500w" sizes="auto, (max-width: 695px) 100vw, 695px" /></a><figcaption class="wp-element-caption">Your account is suspended</figcaption></figure>



<p class="wp-block-paragraph">So that&#8217;s the end of that.  I guess it&#8217;s all too confusing for a boomer like me.</p>



<figure class="wp-block-image size-full"><a href="/wp-content/uploads/2024/02/twitter-cancel-plan-1.png"><img loading="lazy" decoding="async" width="912" height="786" src="/wp-content/uploads/2024/02/twitter-cancel-plan-1.png" alt="" class="wp-image-13882" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-cancel-plan-1.png 912w, https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-cancel-plan-1-300x259.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-cancel-plan-1-768x662.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/02/twitter-cancel-plan-1-348x300.png 348w" sizes="auto, (max-width: 912px) 100vw, 912px" /></a><figcaption class="wp-element-caption">Cancel me, cancel you</figcaption></figure>



<p class="wp-block-paragraph">So needless to say I cancelled Twitter as well.  Kind of sneaky they didn&#8217;t auto-cancel taking money.</p>



<p class="wp-block-paragraph">So yeah, with that out of the way, let&#8217;s continue into DOS Extender land. I added just enough 386 magic, onto <a href="https://github.com/neozeed/sarien286" target="_blank" rel="noreferrer noopener">github: neozeed/sarien286</a>.  Yes I see now it really was a poorly named repo.  Such is life.</p>



<p class="wp-block-paragraph">There is 3 main things for porting old programs where they take care of all the logic, it&#8217;s going to be File I/O, Screen I/O, and timers.  Luckily this time it was easier than I recalled.</p>



<p class="wp-block-paragraph">Over on usenet (<a href="https://groups.google.com/g/comp.lang.asm.x86/c/CMcYE9qTN2Y/m/FUpxQ6Ibxd4J" target="_blank" rel="noreferrer noopener">google groups link</a>) Chris Giese shared this great summary on direct memory access from various methods:</p>



<pre class="wp-block-code"><code>/* 32-bit Watcom C with CauseWay DOS extender */
int main(void) {
char *screen = (char *)0xA0000;
initMode13();
*screen = 1;
return 0;
}

/* 32-bit Watcom C with DOS/4GW extender
(*** This code is untested ***) */
int main(void) {
char *screen = (char *)0xA0000;
initMode13();
*screen = 1;
return 0;
}

/* 32-bit Watcom C with PharLap DOS extender
(*** This code is untested ***) */
#include &lt;dos.h&gt; /* MK_FP() */
#define PHARLAP_CONVMEM_SEL 0x34
int main(void) {
char far *screen = (char far *)MK_FP(PHARLAP_CONVMEM_SEL, 0xA0000);
initMode13();
*screen = 1;
return 0;
}

/* 16-bit Watcom C (real mode) */
#include &lt;dos.h&gt; /* MK_FP() */
int main(void) {
char far *screen = (char far *)MK_FP(0xA000, 0);
initMode13();
*screen = 1;
return 0;
}</code></pre>



<p class="wp-block-paragraph">It is missing the Phar Lap 286 method:</p>



<pre class="wp-block-code"><code>/* Get PM pointer to text screen */
  DosMapRealSeg(0xb800,4000,&amp;rseg);
  textptr=MAKEP(rseg,0);</code></pre>



<p class="wp-block-paragraph">But it&#8217;s very useful to have around as documentation is scarce.</p>



<p class="wp-block-paragraph">Which brings me to this (again?)</p>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/02/Pharlap-386-Programmers-guide-to-DPMI-and-windows.jpg"><img loading="lazy" decoding="async" width="852" height="1024" src="/wp-content/uploads/2024/02/Pharlap-386-Programmers-guide-to-DPMI-and-windows-852x1024.jpg" alt="" class="wp-image-13864" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/Pharlap-386-Programmers-guide-to-DPMI-and-windows-852x1024.jpg 852w, https://virtuallyfun.com/wp-content/uploads/2024/02/Pharlap-386-Programmers-guide-to-DPMI-and-windows-249x300.jpg 249w, https://virtuallyfun.com/wp-content/uploads/2024/02/Pharlap-386-Programmers-guide-to-DPMI-and-windows-768x923.jpg 768w, https://virtuallyfun.com/wp-content/uploads/2024/02/Pharlap-386-Programmers-guide-to-DPMI-and-windows-1277x1536.jpg 1277w, https://virtuallyfun.com/wp-content/uploads/2024/02/Pharlap-386-Programmers-guide-to-DPMI-and-windows.jpg 1324w" sizes="auto, (max-width: 852px) 100vw, 852px" /></a><figcaption class="wp-element-caption">Phar Lap 386|Dos-Extender 4.1</figcaption></figure>



<p class="wp-block-paragraph">Years ago, I had managed to score a documentation set, and a CD-ROM with a burnt installed copy of the extender.  I didn&#8217;t know if it was complete, but of course these things are so incredibly rare I jumped on the chance to get it!</p>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/02/pharlap-4.1-receipt.png"><img loading="lazy" decoding="async" width="1024" height="457" src="/wp-content/uploads/2024/02/pharlap-4.1-receipt-1024x457.png" alt="" class="wp-image-13889" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/pharlap-4.1-receipt-1024x457.png 1024w, https://virtuallyfun.com/wp-content/uploads/2024/02/pharlap-4.1-receipt-300x134.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/pharlap-4.1-receipt-768x343.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/02/pharlap-4.1-receipt-500x223.png 500w, https://virtuallyfun.com/wp-content/uploads/2024/02/pharlap-4.1-receipt.png 1362w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">2011!</figcaption></figure>



<p class="wp-block-paragraph">Unfortunately, I didn&#8217;t feel right breaking the books apart, and scanning them, then add in some bad life choices on my part, and I ended up losing the books.  Fast forward <em>*years*</em> later and Foone <a href="https://archive.org/details/phar-lap-386-dox-extender-4.1-sdk" target="_blank" rel="noreferrer noopener">uploaded a document set on archive.org</a>.  GREAT!  As far as I can tell the only difference <a href="https://archive.org/details/various-dos-extenders-attempt2" target="_blank" rel="noreferrer noopener">in what I had</a> is that I&#8217;ve got a different serial number.  Thankfully I was smart enough to at lest email myself a copy of the CD-ROM contents!  And this whole thing did inspire me to gut and upload the <a href="https://archive.org/details/tnt-dos-extender-6" target="_blank" rel="noreferrer noopener">Phar Lap TNT 6.0</a> that I had also managed to acquire.</p>



<p class="wp-block-paragraph">Although unlocking the video RAM wasn&#8217;t too bad, once I knew what to do, the other thing is to hook the clock for a timer.  ISR&#8217;s are always hell, but at least this is a very simple one:</p>



<pre class="wp-block-code"><code>void (__interrupt __far *prev_int_irq0)();
void __interrupt __far timer_rtn();
int clock_ticks;
#define IRQ0 0x08
void main()
  {
   clock_ticks=0;
   //get prior IRQ routine
   prev_int_irq0 = _dos_getvect( IRQ0 );
   //hook in new protected mode ISR
   _dos_setvect( IRQ0, timer_rtn );

/* do something interesting */
   //restore prior ISR
   _dos_setvect( IRQ0, prev_int_irq0 );
  }

void __interrupt __far timer_rtn()
  {
    ++clock_ticks;
    //call prior ISR
    _chain_intr( prev_int_irq0 );
  }</code></pre>



<p class="wp-block-paragraph">The methodology is almost always the same, as always, it&#8217;s the particular incantation. </p>



<p class="wp-block-paragraph">So yeah, it&#8217;s super simple, but the 8086/80286 calling down to DOS/BIOS from protected mode via the int86 just had to be changed to int386, and some of the register structs being redefined.  I&#8217;m not sure why but the video/isr code compiled with version 7 of Watcom, but crashes.  I think its more drift in the headers, as the findfirst/findnext/assert calls are lacking from Watcom 7, so I just cheated and linked with Watcom 10.  This led to another strange thing where the stdio _iob structure was undefined.  In Watcom 10 it became __iob, so I just updated the 7 headers, and that actually worked.  I had to include some of the findfirst/next structures into the <a href="https://github.com/neozeed/sarien286/blob/main/fileglob.c#L21" target="_blank" rel="noreferrer noopener">fileglob.c</a> file but it now builds and links fine.</p>



<p class="wp-block-paragraph">Another thing to do differently when using Watcom 7, is that it doesn&#8217;t include a linker, rather you need to use 386LINK.  Generating the response file, as there is so many objects didn&#8217;t turn out too hard once I realized that by default everything is treated as an object.</p>



<p class="wp-block-paragraph">Another fun thing is that you can tell the linker to use the program &#8216;stub386.exe&#8217; so that it will run &#8216;run386&#8217; on it&#8217;s own, making your program feel more standalone.  From the documentation:</p>



<pre class="wp-block-code"><code>386 | LINK has the ability to bind the stub loader program, STUB386.EXE, to 
the front of an application .EXP file. The resulting .EXE file can be run by 
typing the file name, just like a real mode DOS program. The stub loader 
program searches the execution PATH for RUN386.EXE (the 

386 | DOS-Extender executable) and loads it; 386 | DOS-Extender then loads 
the application .EXP file following the stub loader in the bound .EXE file. 


To autobind STUB386.EXE to an application .EXP file and create a bound 
executable, specify STUB386.EXE as one of the input object files on the 
command line.

</code></pre>



<p class="wp-block-paragraph">So that means I can just use the following as my linker response file.</p>



<pre class="wp-block-code"><code>agi.obj,agi_v2.obj,agi_v3.obj,checks.obj,cli.obj,console.obj,cycle.obj
daudio.obj,fileglob.obj,font.obj,getopt.obj,getopt1.obj,global.obj
graphics.obj,id.obj,inv.obj,keyboard.obj,logic.obj,lzw.obj,main.obj
menu.obj,motion.obj,pharcga3.obj,objects.obj,op_cmd.obj,op_dbg.obj
op_test.obj,patches.obj,path.obj,picture.obj,rand.obj,savegame.obj
silent.obj,sound.obj,sprite.obj,text.obj,view.obj
words.obj,picview.obj stub386.exe
-exe 386.exe
-lib \wat10\lib386\dos\clib3s.lib \wat10\lib386\math387s.lib
-lib \wat10\lib386\dos\emu387.lib</code></pre>



<p class="wp-block-paragraph">It really was that simple.  I have to say it&#8217;s almost shocking how well this went.</p>



<p class="wp-block-paragraph">So, this brings me back, full circle to where it started, me getting banned for posting this:</p>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/02/attempt-to-capture-it-again.png"><img loading="lazy" decoding="async" width="1024" height="511" src="/wp-content/uploads/2024/02/attempt-to-capture-it-again-1024x511.png" alt="" class="wp-image-13876" srcset="https://virtuallyfun.com/wp-content/uploads/2024/02/attempt-to-capture-it-again-1024x511.png 1024w, https://virtuallyfun.com/wp-content/uploads/2024/02/attempt-to-capture-it-again-300x150.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/02/attempt-to-capture-it-again-768x383.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/02/attempt-to-capture-it-again-500x250.png 500w, https://virtuallyfun.com/wp-content/uploads/2024/02/attempt-to-capture-it-again.png 1452w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">32bit!</figcaption></figure>



<p class="wp-block-paragraph">I thought it was exciting!</p>



<p class="wp-block-paragraph">For anyone who feels like trying it, <a href="https://github.com/neozeed/sarien286/releases/tag/v0.1" target="_blank" rel="noreferrer noopener">I prepped a 5 1/4&#8243; floppy disk image</a>.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><a href="/wp-content/uploads/2024/02/sar386.gif"><img loading="lazy" decoding="async" width="800" height="248" src="/wp-content/uploads/2024/02/sar386.gif" alt="" class="wp-image-13872"/></a><figcaption class="wp-element-caption">running on 86box, 386DX-40 CGA graphics</figcaption></figure>
</div>


<p class="wp-block-paragraph">One interesting observation is that the 386 extender is actually smaller than the 286 one.  And being able to compile with full optimisations it is significantly faster.</p>



<figure class="wp-block-video"><video height="248" style="aspect-ratio: 880 / 248;" width="880" controls src="/wp-content/uploads/2024/02/386sar2-240.mp4"></video><figcaption class="wp-element-caption">16bit on the left, 32bit on the right.</figcaption></figure>



<p class="wp-block-paragraph">I ran both the prior 16bit protected mode version (on the left), and 32bit version (on the right), on the same IBM PS/2 80386DX 16Mhz machine.  You can see how the 32bit version is significantly faster!. </p>



<p class="wp-block-paragraph">I really should profile the code, and have it load all the resources into RAM, it does seem to be loading and unloading stuff, which considering were in protected mode, we should use all ram, or push the VMM386 subsystem to page, and not do direct file swapping, like it&#8217;s the 1970s.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://virtuallyfun.com/2024/02/01/apparently-talking-about-dos-extenders-is-too-hot-for-twitter-aka-phar-lap-386/feed/</wfw:commentRss>
			<slash:comments>8</slash:comments>
		
		
			</item>
		<item>
		<title>The Rise of Unix. The Seeds of its Fall. / A Chronicle of the Unix Wars</title>
		<link>https://virtuallyfun.com/2024/01/05/the-rise-of-unix-the-seeds-of-its-fall-a-chronicle-of-the-unix-wars/</link>
					<comments>https://virtuallyfun.com/2024/01/05/the-rise-of-unix-the-seeds-of-its-fall-a-chronicle-of-the-unix-wars/#comments</comments>
		
		<dc:creator><![CDATA[neozeed]]></dc:creator>
		<pubDate>Fri, 05 Jan 2024 09:42:29 +0000</pubDate>
				<category><![CDATA[32v]]></category>
		<category><![CDATA[386BSD]]></category>
		<category><![CDATA[4 BSD]]></category>
		<category><![CDATA[4.2 BSD]]></category>
		<category><![CDATA[4.3 BSD]]></category>
		<category><![CDATA[4.3 BSD RENO]]></category>
		<category><![CDATA[80386]]></category>
		<category><![CDATA[AT&T Unix]]></category>
		<category><![CDATA[BSD]]></category>
		<category><![CDATA[i386]]></category>
		<category><![CDATA[SIMH]]></category>
		<category><![CDATA[unix]]></category>
		<category><![CDATA[videos]]></category>
		<category><![CDATA[virtual networking]]></category>
		<category><![CDATA[Win32]]></category>
		<guid isPermaLink="false">https://virtuallyfun.com/?p=13695</guid>

					<description><![CDATA[It&#8217;s not mine, rather it&#8217;s Asianometry&#8216;s. It&#8217;s a nice overview of the rise of Unix. I&#8217;d recommend checking it out, it&#8217;s pretty good. And of course, as I&#8217;m referenced! And part 2: A Chronicle of the Unix Wars Years ago &#8230; <a href="https://virtuallyfun.com/2024/01/05/the-rise-of-unix-the-seeds-of-its-fall-a-chronicle-of-the-unix-wars/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">It&#8217;s not mine, rather it&#8217;s <a href="https://www.youtube.com/@Asianometry">Asianometry</a>&#8216;s.  It&#8217;s a nice overview of the rise of Unix.  I&#8217;d recommend checking it out, it&#8217;s pretty good.  And of course, as I&#8217;m referenced!<a href="https://www.youtube.com/@Asianometry"></a></p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="The Rise of Unix. The Seeds of its Fall." width="584" height="329" src="https://www.youtube.com/embed/HADp3emVABg?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div><figcaption class="wp-element-caption">The Rise of Unix. The Seeds of its Fall.</figcaption></figure>



<p class="wp-block-paragraph">And part 2: A Chronicle of the Unix Wars</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="A Chronicle of the Unix Wars" width="584" height="329" src="https://www.youtube.com/embed/Ffh3DRFzRL0?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div><figcaption class="wp-element-caption"><a href="https://www.youtube.com/watch?v=Ffh3DRFzRL0">A Chronicle of the Unix Wars (youtube.com)</a></figcaption></figure>



<p class="wp-block-paragraph">Years ago I had tried to make these old OS&#8217;s accessible to the masses with a simple windows installer where you could click &amp; run these ancient artifacts.  Say 4.2BSD.</p>



<p class="wp-block-paragraph"><a href="https://sourceforge.net/projects/bsd42/files/4BSD%20under%20Windows/v0.3%20Beta%201/BSD4.2-install-0.3.exe/download">Download BSD4.2-install-0.3.exe (Ancient UNIX/BSD emulation on Windows) (sourceforge.net)</a></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="649" src="https://virtuallyfun.com/wp-content/uploads/2024/01/install-4.2BSD-on-windows-1024x649.png" alt="" class="wp-image-13696" srcset="https://virtuallyfun.com/wp-content/uploads/2024/01/install-4.2BSD-on-windows-1024x649.png 1024w, https://virtuallyfun.com/wp-content/uploads/2024/01/install-4.2BSD-on-windows-300x190.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/01/install-4.2BSD-on-windows-768x487.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/01/install-4.2BSD-on-windows-473x300.png 473w, https://virtuallyfun.com/wp-content/uploads/2024/01/install-4.2BSD-on-windows.png 1305w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Installing should be pretty straight forward, I just put the license as a click through and accept defaults.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="622" src="https://virtuallyfun.com/wp-content/uploads/2024/01/booted-into-4.2BSD-1024x622.png" alt="" class="wp-image-13697" srcset="https://virtuallyfun.com/wp-content/uploads/2024/01/booted-into-4.2BSD-1024x622.png 1024w, https://virtuallyfun.com/wp-content/uploads/2024/01/booted-into-4.2BSD-300x182.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/01/booted-into-4.2BSD-768x466.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/01/booted-into-4.2BSD-494x300.png 494w, https://virtuallyfun.com/wp-content/uploads/2024/01/booted-into-4.2BSD.png 1031w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Starting BSD via &#8216;RUN BSD42&#8217; and the emulator will fire up, and being up a console program (Tera Term) giving you the console access.  Windows will probably warn you that it requested network access.  This will allow you to access the VAX over the network, including being able to telnet into the VAX via &#8216;Attach a PTY&#8217; which will spawn another Tera Term, prompting you to login.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="822" height="427" src="https://virtuallyfun.com/wp-content/uploads/2024/01/attach-a-ptty.png" alt="" class="wp-image-13698" srcset="https://virtuallyfun.com/wp-content/uploads/2024/01/attach-a-ptty.png 822w, https://virtuallyfun.com/wp-content/uploads/2024/01/attach-a-ptty-300x156.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/01/attach-a-ptty-768x399.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/01/attach-a-ptty-500x260.png 500w" sizes="auto, (max-width: 822px) 100vw, 822px" /><figcaption class="wp-element-caption">telnettting into the VAX</figcaption></figure>



<p class="wp-block-paragraph">You can login as root, there is no password, and now you are up and running your virtual VAX with 4.2BSD!</p>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2024/01/4.2BSD-items.png"><img loading="lazy" decoding="async" width="748" height="652" src="https://virtuallyfun.com/wp-content/uploads/2024/01/4.2BSD-items.png" alt="" class="wp-image-13699" srcset="https://virtuallyfun.com/wp-content/uploads/2024/01/4.2BSD-items.png 748w, https://virtuallyfun.com/wp-content/uploads/2024/01/4.2BSD-items-300x261.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/01/4.2BSD-items-344x300.png 344w" sizes="auto, (max-width: 748px) 100vw, 748px" /></a><figcaption class="wp-element-caption">All the items</figcaption></figure>



<p class="wp-block-paragraph">I converted many of the old documents into PDF&#8217;s so you may want to start with the Beginners guide to Unix.  I thought this was a great way to bring a complex system to the masses, but I&#8217;m not sure if I succeded.</p>



<figure class="wp-block-image size-large"><a href="https://virtuallyfun.com/wp-content/uploads/2024/01/4.2BSD-download-stats.png"><img loading="lazy" decoding="async" width="1024" height="488" src="https://virtuallyfun.com/wp-content/uploads/2024/01/4.2BSD-download-stats-1024x488.png" alt="" class="wp-image-13700" srcset="https://virtuallyfun.com/wp-content/uploads/2024/01/4.2BSD-download-stats-1024x488.png 1024w, https://virtuallyfun.com/wp-content/uploads/2024/01/4.2BSD-download-stats-300x143.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/01/4.2BSD-download-stats-768x366.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/01/4.2BSD-download-stats-500x238.png 500w, https://virtuallyfun.com/wp-content/uploads/2024/01/4.2BSD-download-stats.png 1171w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">776 downloads</figcaption></figure>



<p class="wp-block-paragraph">As it sits now, since 2007 it&#8217;s had 776 downloads.  I&#8217;d never really gotten any feedback so I&#8217;d hoped it got at least a few people launched into the bewildering world of ancient Unix.  Of course I tried to make many more packages but I&#8217;d been unsure if any of them went anywhere.  It&#8217;s why I found these videos so interesting as at least the image artifacts got used for something!</p>



<p class="wp-block-paragraph">But in the off hand, maybe this can encourage some Unix curious into a larger world.</p>



<p class="wp-block-paragraph">Other downloads in the same scope are:</p>



<ul class="wp-block-list">
<li><a href="https://sourceforge.net/projects/bsd42/files/4BSD%20under%20Windows/v0.3%20Beta%201/Research-unixv1-0.3.exe/download">Research-unixv1</a></li>



<li><a href="https://sourceforge.net/projects/bsd42/files/4BSD%20under%20Windows/v0.3%20Beta%201/unix32v-0.3.exe/download">unix32v</a></li>



<li><a href="https://sourceforge.net/projects/bsd42/files/4BSD%20under%20Windows/v0.3%20Beta%201/BSD4.3-install-0.3.exe/download">BSD4.3</a></li>



<li><a href="https://sourceforge.net/projects/bsd42/files/4BSD%20under%20Windows/v0.4/4.3BSD-Uwisc-install-0.4.exe/download">4.3BSD-Uwisc</a></li>



<li><a href="https://sourceforge.net/projects/bsd42/files/4BSD%20under%20Windows/v0.3%20Beta%201/BSD4.3-Reno-installer-0.3.exe/download">BSD4.3-Reno</a></li>



<li><a href="https://sourceforge.net/projects/bsd42/files/4BSD%20under%20Windows/v0.4/386BSD-0.1.exe/download">386BSD-0.1</a></li>
</ul>



<p class="wp-block-paragraph">Enjoy!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://virtuallyfun.com/2024/01/05/the-rise-of-unix-the-seeds-of-its-fall-a-chronicle-of-the-unix-wars/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Win32Emu / DIY WOW</title>
		<link>https://virtuallyfun.com/2024/01/04/win323mu-diy-wow/</link>
					<comments>https://virtuallyfun.com/2024/01/04/win323mu-diy-wow/#comments</comments>
		
		<dc:creator><![CDATA[neozeed]]></dc:creator>
		<pubDate>Thu, 04 Jan 2024 00:10:22 +0000</pubDate>
				<category><![CDATA[guest post]]></category>
		<category><![CDATA[i386]]></category>
		<category><![CDATA[MIPS]]></category>
		<category><![CDATA[syscall emulation]]></category>
		<category><![CDATA[Win32]]></category>
		<category><![CDATA[Windows NT 4.0]]></category>
		<guid isPermaLink="false">https://virtuallyfun.com/?p=13684</guid>

					<description><![CDATA[This is a guest post by CaptainWillStarblazer When the AXP64 build tools for Windows 2000 were discovered back in May 2023, there was a crucial problem. Not only was it difficult to test the compiled applications since you needed an &#8230; <a href="https://virtuallyfun.com/2024/01/04/win323mu-diy-wow/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">This is a guest post by <a href="https://github.com/BHTY">CaptainWillStarblazer</a></p>



<p class="wp-block-paragraph">When the <a href="https://virtuallyfun.com/2023/05/05/hiding-in-plain-sight-the-64bit-dec-alpha-c-compiler/">AXP64 build tools for Windows 2000</a> were discovered back in May 2023, there was a crucial problem. Not only was it difficult to test the compiled applications since you needed an exotic and rare DEC Alpha machine running a leaked version of Windows, it was also difficult to even compile the programs, since you needed the same DEC Alpha machine to run the compiler; there was no cross-compiler.</p>



<p class="wp-block-paragraph">As a result, I began writing a program conceptually similar to WOW64 on Itanium (or WX86, or FX-32), only in reverse, to allow RISC Win32 programs to run on x86.</p>



<p class="wp-block-paragraph">The PE/COFF file format is surprisingly simple once you get the hang of it, so loading a basic Win32 EXE that I assembled with NASM&nbsp;&nbsp;was pretty simple – just map the appropriate sections to the appropriate areas, fix up import tables, and start executing.</p>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2024/01/image001.png"><img loading="lazy" decoding="async" width="965" height="508" src="https://virtuallyfun.com/wp-content/uploads/2024/01/image001.png" alt="" class="wp-image-13673" srcset="https://virtuallyfun.com/wp-content/uploads/2024/01/image001.png 965w, https://virtuallyfun.com/wp-content/uploads/2024/01/image001-300x158.png 300w, https://virtuallyfun.com/wp-content/uploads/2024/01/image001-768x404.png 768w, https://virtuallyfun.com/wp-content/uploads/2024/01/image001-500x263.png 500w" sizes="auto, (max-width: 965px) 100vw, 965px" /></a></figure>



<p class="wp-block-paragraph">To start, I wrote a basic 386 emulator core. To complement it, I wrote my own set of Windows NT system DLLs (USER32, KERNEL32, GDI32) that execute inside of the emulator and then use an interrupt to signal a system call&nbsp;&nbsp;which is trapped by the emulator and thunked up to execute the API call on the host.</p>



<p class="wp-block-paragraph">For example, up above, you can see that the emulated app calls MessageBoxA inside of the emulated USER32, which puts 0 in EAX (the API call number for MessageBoxA) and then does the syscall interrupt (int 0x80 in my case), which causes the emulator to grab the arguments off of the stack and call MessageBoxA.</p>



<p class="wp-block-paragraph">To ease communication between the host’s Win32 environment and the emulated Win32 environment, I ran the emulated CPU inside of the host’s memory space, which means that to run applications written for a 32-bit version of Windows NT, you need a 32-bit version of win32emu (or a 64-bit version with /LARGEADDRESSAWARE:NO passed to the linker) to avoid pointer truncation issues, to prevent Windows from mapping memory addresses inaccessible by the emulated CPU.</p>



<p class="wp-block-paragraph">To get “real” apps working, a lot of single-stepping through the CRT was required, but eventually I did get Reversi – one of the basic Win32 SDK samples – to work, albeit with some bugs at first. Calling a window procedure essentially requires a thunk in reverse, so I inserted a thunk window procedure on the host side that calls the emulated window procedure and returns the result.</p>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2024/01/image012.jpg"><img loading="lazy" decoding="async" width="465" height="388" src="https://virtuallyfun.com/wp-content/uploads/2024/01/image012.jpg" alt="" class="wp-image-13669" srcset="https://virtuallyfun.com/wp-content/uploads/2024/01/image012.jpg 465w, https://virtuallyfun.com/wp-content/uploads/2024/01/image012-300x250.jpg 300w, https://virtuallyfun.com/wp-content/uploads/2024/01/image012-360x300.jpg 360w" sizes="auto, (max-width: 465px) 100vw, 465px" /></a><figcaption class="wp-element-caption">It&#8217;s amazing, it&#8217;s reversi!</figcaption></figure>



<p class="wp-block-paragraph">After this, I got to work on getting more complicated applications to work. Several failed due to lack of floating-point support, some failed due to unsupported DLLs, but I was able to get FreeCell and WinMine to work (with some bugs) after adding SHELL32. I was able to run the real SHELL32.DLL from Windows NT 3.51 under this environment.</p>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2024/01/image013.jpg"><img loading="lazy" decoding="async" width="624" height="325" src="https://virtuallyfun.com/wp-content/uploads/2024/01/image013.jpg" alt="" class="wp-image-13670" srcset="https://virtuallyfun.com/wp-content/uploads/2024/01/image013.jpg 624w, https://virtuallyfun.com/wp-content/uploads/2024/01/image013-300x156.jpg 300w, https://virtuallyfun.com/wp-content/uploads/2024/01/image013-500x260.jpg 500w" sizes="auto, (max-width: 624px) 100vw, 624px" /></a><figcaption class="wp-element-caption">Freecell</figcaption></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="623" height="338" src="https://virtuallyfun.com/wp-content/uploads/2024/01/image014.jpg" alt="" class="wp-image-13671" srcset="https://virtuallyfun.com/wp-content/uploads/2024/01/image014.jpg 623w, https://virtuallyfun.com/wp-content/uploads/2024/01/image014-300x163.jpg 300w, https://virtuallyfun.com/wp-content/uploads/2024/01/image014-500x271.jpg 500w" sizes="auto, (max-width: 623px) 100vw, 623px" /><figcaption class="wp-element-caption">Minesweeper</figcaption></figure>



<p class="wp-block-paragraph">One might wonder why I put all this work into running x86 programs on x86, but the reason is that there’s the most information about, and I’m most proficient with, Windows on the 386. Not only does Windows on other CPUs use other CPUs, but also there’s different calling conventions and a lot of other stuff I didn’t want to mess with at first. But this was at least a proof-of-concept to build a framework where I could swap the CPU core for an emulator for MIPS or PPC or Alpha or whatever I wanted and get stuff running.</p>



<p class="wp-block-paragraph">Astute readers might be wondering why I didn’t take the approach taken by WOW64. For those who don’t know, most system DLLs on WOW64 are the same as those in 32-bit Windows, the only ones that are different are ones with system call stubs that call down to the kernel (NTDLL, GDI32, and USER32, the first of which calls to NTOSKRNL and the latter two calling to WIN32K.SYS). WOW64 instead calls a function with a system call dispatch number, which does essentially the same thing. The reason for this is that the system call numbers are undocumented and change between versions of Windows. WOW64, being an integrated component of Windows, can stay up to date. If I took this approach, I’d either have to stay locked to one emulated set of DLLs (i.e. from NT 4.0) and use their system call numbers on the emulated side, or write my own emulated DLLs and stick to a fixed set of numbers, but either way I’d somehow have to map them to whatever syscall numbers are being used on the host.</p>



<p class="wp-block-paragraph">As I went on, I should probably also mention that what I said earlier about loading Win32 apps being easy was wrong. Loading a PE image is pretty straightforward, but once you get into populating the TEB and PEB (many of whose fields are undocumented), it quickly gets gnarly, and my PEB emulation is incomplete.</p>



<p class="wp-block-paragraph">Adding MIPS support wasn’t too much of a hassle, since the MIPS ISA (ignoring delay slots, which gave me no shortage of trouble) is pretty clean and writing&nbsp;&nbsp;an emulator wasn’t difficult. The VirtuallyFun Discord pointed me to Embedded Visual C++ 4.0, which was invaluable to me during development, since it included a MIPS assembler and disassembler, which I haven’t seen elsewhere. After writing a set of MIPS thunk DLLs and doing some more debugging, I finally got Reversi working.</p>



<p class="wp-block-paragraph">There’s still some DLL relocation/rebasing issues, but Reversi is finally working in this homebrewed WOW!</p>



<figure class="wp-block-image size-full"><a href="https://virtuallyfun.com/wp-content/uploads/2024/01/image015.gif"><img loading="lazy" decoding="async" width="624" height="326" src="https://virtuallyfun.com/wp-content/uploads/2024/01/image015.gif" alt="" class="wp-image-13672"/></a></figure>



<p class="wp-block-paragraph">I’d encourage someone to write a CPU module for the DEC Alpha AXP (or even PowerPC if anyone for some reason wants that). The API isn’t too complicated, and the i386 emulator is available for reference to see how the CPU emulator interfaces with the Win32 thunking side. An Alpha backend for the thunk compiler can definitely be written without too much trouble. Obviously, the AXP presents the challenge that fewer people are familiar with its instruction set than MIPS or 386, but this approach does free one from having to emulate all of the intricate hardware connections in actual Alpha applications while still running applications designed for it, and I’ve heard the Alpha is actually quite nice and clean. MAME’s Digital Alpha core could be a good place to start, but it’ll need some adaptation to work in this codebase. Remember that while being a 64-bit CPU with 64-bit registers and operations, the Alpha still runs Windows with 32-bit pointers, so it should run in a 32-bit address space (i.e. pass /LARGEADDRESSAWARE:NO to the linker).</p>



<p class="wp-block-paragraph">Theoretically, recompiling the application to support the full address space should enable emulation of AXP64 applications, since the Alpha’s 64-bit pointers will allow it to address the host’s 64-bit address space, but I’m not sure if my emulator is totally 64-bit clean, or if the AXP64’s calling convention is materially different from that on the AXP32 in such a way that would require substantial changes. In either case, most of the code should still be transferable.</p>



<p class="wp-block-paragraph">I also want to get more “useful” applications running, like development tools (i.e. the MSVC command line utilities &#8211; CL, MAKE, LINK, etc.) and CMD. Most of that probably involves implementing more thunks and potentially fixing CPU bugs.</p>



<p class="wp-block-paragraph">This project is obviously still in a quite early stage, but I’m hoping to see it grow and become something useful for those in the hobby.</p>



<p class="wp-block-paragraph">For those who want to play along at home, you can download the <a href="https://github.com/BHTY/Win32Emu/releases/download/alpha/w32emu.zip">binary snapshot here: w32emu.zip</a></p>



<p class="wp-block-paragraph">A more complete version of the writeup is available here:&nbsp;<a href="https://bhty.github.io/og/win32emu_VirtuallyFun_Post.htm">https://bhty.github.io/og/win32emu_VirtuallyFun_Post.htm</a>&nbsp;and you can find the project here&nbsp;<a href="https://github.com/BHTY/Win32Emu/">https://github.com/BHTY/Win32Emu/</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://virtuallyfun.com/2024/01/04/win323mu-diy-wow/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
	</channel>
</rss>
