An actual look at Microsoft OS/2 2.0

Years ago, feeling nostalgic, I had written a quick throw away thing about the old article from PC Magazine, 29th of May, 1990, detailing the coming future of Operating Systems, Microsoft OS/2 2.0. 14 year old me was blown away!

614KB Free! And Flight Simulator 4 in a window

This release marks the last time that Microsoft would release an OS/2 beta to developers, instead with the runaway success of Windows 3.0, Microsoft would remove resources from the constrained OS/2, and refocus both on Windows 3.1, and Windows NT.

Thanks to one of my Patrons – Brian Ledbetter, the much-sought Microsoft OS/2 2.0 Pre-Release 2 is now available! So obviously the first thing to do was to re-create the original magical screenshot.

One thing of note is that thanks to some of the metadata left at the end of the disks we know when this disk set was made:

$FTIME = Wed Jun 22 09:00:56 1988
$DTIME = Tue Aug 15 07:48:10 1989
$PCTIME = Thu Apr 27 11:51:54 1989
$FREV = Wed May 31 09:17:24 1989
$DUP TIME = Fri Jul 13 16:02:27 1990

Given that the PC Magazine issue was published in May of 1990, it showcased version 6.43, shipped to devs early January of 1990, and timestamped 20/12/1989. I would speculate that it’s the Pre-Release 1.

The OS/2 Software Development Kit

This Pre-Release 2 set was made in July with the files being timestamped 01/06/1990, so physical releases every 6 months? I guess that makes sense when you look at how many disks have to be duplicated, boxed up and sent out. It’s one big win for digital downloads, or how Windows 10/11 can background download updates, or even entire OS updates (that are more like new installs) today. Mailing big heavy boxes must have sucked. And dealing with lost/damaged disks. Also as you can see on the box, it only contains 5 1/4″ disks, they didn’t even ship dual media.

Maybe the large box is a reaction to the first Pre-Release’s 16 disks & a few photocopied sheets mere 10oz. Maybe people were displeased that they didn’t get much printed ‘bang’ for their $2,600 – the price of the 2.0 SDK.

The disks were dumped with Kyroflux, and on several of the disks there is extra trailing information on the disks revealing data from when they were manufactured:

$TRACEBACK (tm) Ver 1.04
$OPER = operator
$STATION = 1
$STN LIST = 1 3 5 7 11 13 15 17 19
$WORKORDER = -1
$SYSTEM = 7
$PRODUCT = z:/product/110098449.p
$PTIME = ???
$FORMAT = /format/fmt12.f
$FTIME = Wed Jun 22 09:00:56 1988
$DRIVE = /drive/3xhd96sdsmt.d
$DTIME = Tue Aug 15 07:48:10 1989
$MODULE = /config/3xhdSDSmt.s
$MTIME = ???
$WINDOW MARGIN = 87.5%
$RETRY SETTINGS = 3,2,25
$FUNCTION = write/verify
$PRECOMP = /precomp/3xhdSDS.t
$PCTIME = Thu Apr 27 11:51:54 1989
$FREV = Wed May 31 09:17:24 1989
$DRIVESN =
$LOADERSN = 525-100-70
$DFCSN = 3402 SDSFC
$USTRING =
$TSTRING = TraceBack (tm)   (c) 1989 Trace Products All Rights Reserved.
$DUP TIME = Fri Jul 13 16:02:27 1990
$DISK NUMBER =  22 of 45
$SN = NONE

That’s right, this disk (Install 1) was manufactured on Friday the 13th!

Running strings against the DOSKRNL reveals this string:

MS DOS Version 4.00 (C)Copyright 1988 Microsoft CorpLicensed Material - Property of Microsoft

Not only is it a new OS/2, but a new MS-DOS! Neat!

 APPEND.EXE
 ASSIGN.COM
 COMMAND.COM
 EDLIN.COM
 GRAFTABL.COM
 JOIN.EXE
 SETCOM40.EXE
 SUBST.EXE

This is *NOT* a comprehensive version of MS-DOS 4.0. Then again anything to do with disks, you should be using OS/2. It’s more so commands needed for working inside the virtual MS-DOS environment. And yes, it doesn’t include any basic.

There is built in support for EMS, and there is an XMS driver, but it’s not activated by default. I didn’t bother trying Windows 3.0, but I did install Word for Windows, which has a runtime version of Windows 2.11

Windows 2.11 Runtime on OS/2

Trying to run the windows executable directly gives a weird error:

SYS0195: The operating system cannot run %1.

I went ahead and installed WLO, or the Windows Libraries for OS/2, and some things do run, and many more hang the system. I think its an issue in PM, and CAD (Control+Alt+Delete) does reboot the system.

WLO on Microsoft OS/2

It’s a shame Microsoft couldn’t get Windows as the UI to OS/2, it certainly would have had a far more viable lifetime. I’ve ranted about it before but IBM’s insistance of supporting the 286, releasing a $6,000 286 in 1987 basically ensured early OS/2 was facing the wrong direction technically, and by ignoring the existing Windows stack, it just delayed OS/2 being useful from the get-go.

Anyways…..

And running strings against the OS2KRNL reveals:

Copyright 1986 IBM Corp.
Internal revision 6.78, 90/05/09

And to further muddle the waters:

@(#)ldrste.c    13.125 90/05/09
@(#)ldrfixup.c  13.43 90/05/09
@(#)ldrsubr.c   13.116 90/05/09
@(#)pgset.c     13.64 90/05/01
@(#)selmgrc.c 13.76 90/05/01
@(#)vmalias.c   13.48  90/05/01
@(#)vmalloc.c   13.71 90/05/01
@(#)vmapi.c          13.50 90/05/07
@(#)vmfree.c    13.89 90/05/01
@(#)vminfo.c         13.33 90/05/01
@(#)vminit.c    13.60 90/05/01
@(#)vmshared.c 13.41 90/05/01
@(#)selkh.c 13.14 90/05/01
@(#)tklibi.c 13.42 90/05/09
@(#)inidin2.asm 1.86 90/04/27
@(#)selinit.asm 13.51 90/05/09
@(#)ldrinita.asm        13.47 90/05/09
@(#)selwrk.asm 13.51 90/05/07
@(#)vdmaa.asm         13.54 90/04/27
@(#)trap.asm    1.82 90/05/04
@(#)trap286.asm 13.43 90/05/04

If you were ever wondering what the names of the source was, here is the .c & assembly:

dbgee.c
dbger.c
dbgwp.c
dem.c
dyndto.c
dyndtr.c
em86.c
except.c
ldrgc.c
ldrinit.c
ldrmte.c
pgage.c
pgalloc.c
pgfault.c
pgframe.c
pginit.c
pgmap.c
selini.c
semalloc.c
seminout.c
semtools.c
semverif.c
semwrkr.c
smalloc.c
smsft.c
tkinit.c
tksleep.c
tkthrd.c
vdmapi.c
vdmctrl.c
vdmm.c
vdmmasrt.c
vdmmcrt.c
vdmmem.c
vdmmheap.c
vdmmisc.c
vdmpage.c
vdmprop.c
vdmtime.c
vmbmp32.c
vmdevhlp.c
vmkrh.c
vmksh.c
vmlocate.c
vmlock.c
vmob.c
----
demfile2.asm
demioc2.asm
demnls.asm
dhrouter.asm
dynci.asm
dyndtra.asm
em86io.asm
em86misc.asm
fsinfo.asm
gshare.asm
int.asm
kmodea.asm
ldrrsrc.asm
ldrrun.asm
monhigh.asm
npx.asm
pageio.asm
pga.asm
selmap.asm
selmgra.asm
selseg.asm
sftio.asm
sicg.asm
sig.asm
tkexit1.asm
tkmisc.asm
tkwksem.asm
vdhserv.asm
vmmisc.asm
vmname.asm

Neat!

I would imagine a lot of the v86 mode virtual device drivers came from Windows/386. But it looks like these were all written in C? Running strings against all the virtual device drivers reveals all C? I got zero hits for .asm

emm.c
emm1.c
emm2.c
emmctrl.c
vbios.c
vcmos.c
vcmosio.c
vdma.c
vdsk.c
vdskint.c
vdskio.c
vkbd.c
vkbdint.c
vkbdio.c
vkbdreq.c
vmbound.c
vmdevrq.c
vmevent.c
vmhook.c
vminit.c
vmlpen.c
vmmisc.c
vmpos.c
vmptr.c
vmrate.c
vmreset.c
vmstate.c
vmuser.c
vpic.c
vtd.c
vtdint.c
vtdio.c
vtdreq.c
xmm.c
xmmctrl.c

It’s not like any of this is ever going to see the light of day, but it’s all interesting, at least to me.

Let’s install!

Installing Microsoft OS/2 2.0 Beta on VMware

I’ll have to update where I had found this, if it was the electronic documentation, or the one time I got to go through the printed documentation that the Microsoft version was adding True Type Fonts. Sadly I can’t find any evidence in the binaries.

OS/2 System Monospace Fonts
OS/2 Courier Fonts, (c) Copyright 1988 Microsoft Corp., Portions Copyright 1985 Bitstream, Inc.
OS/2 Helvetica Fonts, (c) Copyright 1988 Microsoft Corp., Portions Copyright 1985 Bitstream, Inc.
OS/2 Times Roman Fonts, (c) Copyright 1988 Microsoft Corp., Portions Copyright 1985 Bitstream, Inc.

  "PM_Fonts"           "SYSMONO"            "C:\OS2\DLL\SYSMONO.FON"
  "PM_Fonts"           "COURIER"            "C:\OS2\DLL\COURIER.FON"
  "PM_Fonts"           "HELV"               "C:\OS2\DLL\HELV.FON"
  "PM_Fonts"           "TIMES"              "C:\OS2\DLL\TIMES.FON"

Well, that’s sad.

No VIO for you!
No VIO access from 32bit

As I had touched on earlier, These early OS/2’s have no user accessible way to call the legacy 16bit OS/2 API’s. At best you have simple text mode stuff, anything graphical, you need to port to Presentation Manager.

I was able to take the GCC port I did to OS/2 and re-link the objects ,and I was correct, it ran without any changes! I had compiled it using the December 1991 Windows NT Pre-Release’s CL386 compiler. So far so good.

I tried to use the 1991 compiler to build Sarien, and it instantly crashes. I also tried building everything but the Presentation Manager with GCC, and again instant crash. I was able to use the OS/2 2.1 v1.2 DDK, and get a working EXE, even using /Ox (maximum optimisations!). Clearly there is something fundamentally missing or I’m missing something fundamental.

While there is a HPFS installable filesystem, there is no CD-ROM IFS. Running strings against HPFS reveals this much when looking for C. There was no hits for .asm

execioh.c: calling strat2 with PIOH=%p
execioh.c: returned from strat2 with PIOH=%p
qdiskop.c: entered, ioh=%p lsnStrt=%lu csec=%u pbData=%p
unlckio.c:entered, pioh=%p
unlckio.c:retheaping lock handle %p

Even more strange, is that HPFS for OS/2 was still 16bit. I had hoped that even though this is a beta, that there would be a 32bit version of the filesystem. Sadly that kind of feature was reserved for Lan Server installs.

HPFS.IFS: MS-DOS executable, NE for OS/2 1.x (DLL or font)

Could you imagine shipping a 32bit filesystem to home/low/middle tier users today? Speaking of, let’s check the rest of the C:\OS2 binaries:

ANSI.EXE:     MS-DOS executable, NE for OS/2 1.x (EXE)
ATTRIB.EXE:   MS-DOS executable, NE for OS/2 1.x (EXE)
BACKUP.EXE:   MS-DOS executable, NE for OS/2 1.x (EXE)
CACHE.EXE:    MS-DOS executable, NE for OS/2 1.x (EXE)
CMD.EXE:      MS-DOS executable, NE for OS/2 1.x (EXE)
CREATEDD.EXE: MS-DOS executable, NE for OS/2 1.x (EXE)
E.EXE:        MS-DOS executable, NE for OS/2 1.x (EXE)
EAUTIL.EXE:   MS-DOS executable, NE for OS/2 1.x (EXE)
FDISKPM.EXE:  MS-DOS executable, NE for OS/2 1.x (EXE)
FIND.EXE:     MS-DOS executable, NE for OS/2 1.x (EXE)
HELPMSG.EXE:  MS-DOS executable, NE for OS/2 1.x (EXE)
MAKEINI.EXE:  MS-DOS executable, NE for OS/2 1.x (EXE)
MOVESPL.EXE:  MS-DOS executable, NE for OS/2 1.x (EXE)
PATCH.EXE:    MS-DOS executable, NE for OS/2 1.x (EXE)
PICICHG.EXE:  MS-DOS executable, NE for OS/2 1.x (EXE)
PICPRINT.EXE: MS-DOS executable, NE for OS/2 1.x (EXE)
PICSHOW.EXE:  MS-DOS executable, NE for OS/2 1.x (EXE)
PMCPL.EXE:    MS-DOS executable, LE executable
PMEXEC.EXE:   MS-DOS executable, LE executable
PMFILE.EXE:   MS-DOS executable, LE executable
PMSHELL.EXE:  MS-DOS executable, NE for OS/2 1.x (EXE)
PMSPOOL.EXE:  MS-DOS executable, LE executable
PSTAT.EXE:    MS-DOS executable, NE for OS/2 1.x (EXE)
REPLACE.EXE:  MS-DOS executable, NE for OS/2 1.x (EXE)
RESTORE.EXE:  MS-DOS executable, NE for OS/2 1.x (EXE)
SORT.EXE:     MS-DOS executable, NE for OS/2 1.x (EXE)
SPOOL.EXE:    MS-DOS executable, NE for OS/2 1.x (EXE)
SYSLOG.EXE:   MS-DOS executable, NE for OS/2 1.x (EXE)
TRACE.EXE:    MS-DOS executable, LE executable
TRACEFMT.EXE: MS-DOS executable, NE for OS/2 1.x (EXE)
UNPACK.EXE:   MS-DOS executable, NE for OS/2 1.x (EXE)
VIEW.EXE:     MS-DOS executable, NE for OS/2 1.x (EXE)
VIEWDOC.EXE:  MS-DOS executable, NE for OS/2 1.x (EXE)
XCOPY.EXE:    MS-DOS executable, NE for OS/2 1.x (EXE)

The vast majority of them are 16bit. The 32bit stuff is in the defunct LE format. This is why nothing from the GA (General Availability) versions will ever run on these betas, and why I was trying to make stuff available as linkable objects. And yes, my Sarien port is LE:

SARIEN.EXE: MS-DOS executable, LE executable

There is a LAN client disk set, so I guess you were expected to just go across the LAN.

The SDK & Toolkit for this beta have been around for a substantial time. The big difference is that we now have binary compatibility so we can run ALL the examples, namely the Open Dialog demo.

Open Dialog

We take this kind of thing for granted today, common controls, but back in the early 1990’s this was a surprisingly lacking from many UI’s of the time. Since these beta DLL’s use a different format, this won’t run on the later betas, let alone the release. So, this is for those looking for secret hidden stuff.

Is it usable though? Well if your workload is OS/2 applications, ABSOLUTELY. If you want to do cute stuff on MS-DOS.. It’s all YMMV, but traditional apps seem to behave pretty well.

It’s a shame for some reason that overall, these early OS/2 2.0 betas were not all that wide spread, as they are just so interesting! And compared to the GA version of OS/2 2.0 these ancient versions with the 1.x Presentation Manager do feel a lot faster. Sometimes I miss the Workplace Shell, Other times I miss the old terrible Desktop Manager with its incredible simplification.

For those just wanting to mess with the Operating System, it really is a developer’s release so it’s pretty spartan. Sadly there is no XGA drivers in these early betas, there is 8514/a support but I had no luck with it. I suspect it’s probably something I had done wrong. I should also point out, if you are using 86Box, and are using a 486DX/Pentium be sure to enable the softfloat option.

FPU passthru gives major issues with MS-DOS under OS/2

Maybe a math co-processor really was a hidden requirement of these early OS/2 betas? So, perhaps more confirmation that buying an 80387 was NOT a waste of money. I should also add that when trying to compile PHOON, I did have to use /FPi87 or inline 8087 instructions, otherwise instant crash. I had thought it was a mixed FPU mode crashing the linking of GCC+MSC code but I tried a few combinations, none of them worked.

Once more again, I want to thank my Patrons for making this possible, and a big thanks to Brian Ledbetter for being so kind to preserve this incredibly rare, and historically significant software kit.

I’ve made my VMware image available, and 86box.

Everyone has a theory on why OS/2 failed, and here is mine: The PS/2 Model 60

Don’t get me wrong, it’s a very 1980’s awesome machine. Aesthetically. But practically? No way, it’s a legit white elephant. And it killed OS/2 before it even became a thing. I know what about the JDA, and IBM interference? What about the poor choice of the 80286 processor? What about DOS Extenders? YES it’s all there, Half an Operating System, for Half a computer, the real reason OS/2 failed, and it’s wrapped up in a 20 x 8 x 18 inches package weighing in at 40 pounds.

Behold the IBM PS/2 model 60.

The PS/2 model 60 from the OS/2 1.0 brochure

The base model PS/2 60 with the 44Mb hard disk was priced at an eye watering $5,925 in 1987. And to be clear that is with only has ONE megabyte of RAM which is nowhere near enough to even boot OS/2. Realistically, you would need the additional memory card, and another 4MB of RAM, raising the price far higher, as stated in the requirements for the sales demonstration of OS/2.

The realistic OS/2 requirements, 5MB of RAM!

The 77Mb disk system would set you back $6,295, again not counting the needed memory upgrades.

It’s BIG, loud, expensive, and more importantly obsolete on day one.

Going back, to the original success of the IBM PC and it’s open architecture lead to the one big issue, which is that it was trivial for people to clone, as they published everything you’d want to know in their technical reference manuals. The one thing that was copywrite was the BIOS. However as I’m sure everyone heard the story of how Columbia Data Products released the MPC 1600, which set the gold standard on reverse engineering, but opened the floodgates to bigger players like Compaq, and ushered in the clone revolution.

IBM was obviously not happy with this. IBM always looked to hardware for money, and IBM build quality, and of course that lead us to the PS/2. There is no way they could have developed this in the space of a year, which again if it took 2-3 years to bring them to market, it would explain so many of the missteps of the Model 30 which both had an ISA bus, and had either an 8086 or 80286 processor. This may have been okay for 1985, but they were far too old & slow for 1987. Many people have cited that part of the PS/2 revolution was the new bus on the model 60/80 Microchannel which unlike ISA had to be licensed from IBM, but of course it didn’t catch on, instead it gave confidence to the industry to not only set out on their own 386 machines, but then their own 32bit bus EISA. Yet another reason the 8086/80286 machines should never had existed.

$5,795 MSRP for the IBM AT – InfoWorld 3 Dec 1984

Looking back to December of 1984 we can see the MSRP for the 6Mhz IBM AT was $5,795, the AT model 099 included a whopping 20MB hard disk, a single high density 1.2MB 5 1/4″ floppy drive, and 512kb of RAM. Now jump forward a few years, and every clone manufacturer has benefited from economies of scale as the commodity parts increase of demand and sourcing has only led to lower prices. Except for IBM. While the Model 60 does have twice the RAM going up to a base configuration of 1 megabyte, and a 44MB hard disk, the price is $6,995 or a 20% price increase!

What lead to this massive stagnation from 1985 to 1987? I’m sure it has almost everything to do with Don Estridge’s untimely death in 1985. I can’t imagine IBM releasing an XT years later with the same design language as the new ‘powerful’ machines, no doubt just fooling consumers into thinking they are ready for the 1990’s when instead, it’s a product more akin to 1982.

IBM PS/2 models at a glance – InfoWorld 6 Apr 1987

From Infoworld 1988:

On the one hand, IBM has shipped nearly 2 million PS/2s in the year since the machines were introduced. The Model 50 is currently the best-selling microcomputer in the industry a position it has held since November 1987, according to market research firm Store-board Inc. What makes these figures even more significant, say analysts, is that many of the alleged benefits of the PS/2 have yet to be fully exploited.

InfoWorld 4 Apr 1988

Although there was certainly an initial corporate interest in the PS/2’s IBM did not keep up with faster Intel CPUs quick enough and failed to keep up interest in the base models, leading to significant price cuts in the spring of 1988.

Drastic price cuts – InfoWorld 18 Apr 1988

Time and time again you’ll hear how there was no software poised to take charge of these 286/386 models, and there was no compelling reason to do so. And it’s why it was such a big mistake to not have allowed Microsoft to being GDI to OS/2 along with it’s working drivers & applications to have shortened development time to get them to market. By shipping these expensive premium machines without OS/2 (normal users don’t change operating systems), and the double slap insult being that none of these machines are capable out of the box of running *any* version of OS/2 it’s not hard to see why it failed.

Okay so the PS/2 was too expensive!

Actually, it was too cheap! They should have not bothered with the new look XTs it only created branding confusion, and really all 286/386 equipped models should have been able to run OS/2, with no upgrades needed. I can’t imagine anyone would be happy after spending six plus thousand on a new machine to only find out that to run the OS of the future, you need to spend a few more thousand.

Windows was irrelevant in 1987!

There is no doubt that being able to run Windows applications natively on OS/2 would have only helped it tremendously, as OS/2 would be the ‘professional’ version of Windows. Although OS/2 did achieve this through paravirtualization, having GDI/USER native to OS/2 would have consumed far less ram as you wouldn’t need to load two windowing environments at once!

While Balance of Power may not have been the #1 chart topper, it was one of the first commercial games for Windows (Maybe it was the first?), showing that instead of developing UI code & drivers, that even a run-time platform was a viable choice.

v86 mode was too difficult and it delayed OS/2 2.0 for years!

What if I told you that there is FOOTBALL & PIGSKIN? Granted they are text mode, but they absolutely incorporate v86 mode into what is basically OS/2 1.0. In 1987. Why was there no OS2/386? Yeah. IBM.

Instead, all the 1.x versions of OS/2 had a SINGLE MS-DOS box, or penalty box, even the 386 has the single DOS session limitation. So if your work flow was stuck to a single DOS session what compelling reason would there be to upgrade to OS/2? NONE. Speaking of 1987 however there was Windows/386 towards the end of the year.

Windows/386, is the friendliest glance into today’s future (Think of it as a graphical hypervisor, like VMware/KVM). Windows was the one environment where Microsoft didn’t need IBM’s permission to do anything, or adhere to any other standards, Microsoft added v86 support into Windows, and it brought mainframe power to the average user, by allowing them to create virtual machines running their own isolated MS-DOS applications, and even allowing copy/paste of data from between them, and into new Windows applications. While Windows 2 was a shadow of what would become the Windows 3.0 juggernaut of 1990, it was quickly headed in the right direction.

What is it with the 386 anyways?

And why were they so adverse to the 386? the 1st gen Model 80 motherboard feels more like a begrudging reaction to Compaq rather than what it should have been by the time they released the 3rd – 25Mhz version, with onboard cache controller & ram. Beyond v86 mode, there was the large memory space, and 32bit registers making it possible to port minicomputer (and even mainframe) programs to the PC. Was this desktop future too scary for IBM? Did they really thing that by refusing to adopt the 386 that they could somehow influence the rest of the market to not being 32bit computing to the masses? Even in the early 80’s there was the Definicon, a NS32016 cpu board you could plug into your IBM PC and unleash a programmable 32bit processor with upwards of 2MB of RAM. If IBM was not going to make a 32bit computer, others would find a way, utilizing the ever-increasing supply of open PC hardware.

As far as I can tell IBM didn’t even permit Windows/386 or any version of Windows to be bundled or shipped with the PS/2’s further alienating them from the growing market of software. And of course, by not increasing the RAM the pre-loaded operating system was still PC-DOS, not OS/2. It really shakes confidence when IBM won’t even preload their jointly developed Operating System of the future.

Then along came Windows.

While Windows 3.0 was fine enough running in 16bit protected mode on both the 286 & 386, having the ability to launch v86 machines, and take advantage of hardware paging of the 386 on Windows 3.0. At least you were 2/3rds of the chip’s capabilities, unlike OS/2 1.x where you used none.

There is money in those developer hills!

Time and time again, this has been one of the industry’s biggest failings. Just as IBM charged a fortune for SDK’s and DDKs all it did was raise the bar so high very few people paid for them, strangling the supply of apps & drivers.

InfoWorld 6 Apr 1987

While the PS/2’s were very expandable, it seems outside of collectors, very few are. Which again speaks to why it was so important to get that initial pre-loaded configuration right. And you control that with the pre-load, just as Apple forced the wedge by first loading OS X onto machines, then making it the default. At best with Warp IBM pre-loaded it on many devices, but users were oblivious that it was even there. It was more than once I’d seen someone buy a retail copy of Warp, to run this OS/2 thing to only find out their ThinkPad already had a copy.

$3,000 a bargain!

The prices to get started with technical information, the toolkit and a compiler may seem expensive, but compared to the infamous $3,000 SDK & seminars.

As Steve would say – “Developers” – ViciousAloisius

Instead, developers should have been given copies for free, or even back then, on the MSPL. While the Microsoft Programmer’s Library is an invaluable resource, the lack of tools is just odd. Why even have slack space on those early CD-ROMs?

No doubt all the painful lessons were learned from OS/2 for Windows. Just as Windows NT ended up being everything NTOS/2 3.0 was going to be.

So yeah, really it was the PS/2 Model 60?

Bringing out a super expensive 16bit machine in 1987, holding Microsoft back in every technical way possible, along with all the poor choices revolving around IBM’s fear of the 386, and the 32bit future doomed OS/2 before it even began.

At best the 8086/80286 machines should have been cheap machines for MS-DOS present, but again the outlier is the PS/2 Model 60. Far too expensive with no real compelling reason to buy one – Don’t get me wrong I love mine! But it’s incredibly impractical.

If anything, once more again, OS/2 1.x should never been a thing, it performs terribly on 286’sand the single 3xdos session is just painful. With its heavy requirements, it always should have been targeting the 386, and the brave future of 1987 onwards, not 1984, and certainly not the PS/2 model 60, which never should have existed.

Hamstringing OS/2 to the $6,995 PS/2 model 60 in 1987 doomed it all from the start. It never stood a chance.

Porting Sarien to OS/2 Presentation Manager

Originally with all the buildup of compilers & 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 & 386 DOS Extender, so the code should work fine, right?

To recap, years ago I had done a QuakeWorld 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’t exist in the betas!

No VIO for you!
No VIO access from 32bit

So that meant I was going to have to break down and do something with Presentation Manager.

So the first thing I needed was a program I could basically uplift into what I needed, and I found it through FastGPI.

Donald Graft’s FastGPI

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’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!

  for (y = 0; y < NUM_MASSES_Y; y++)
  {
    for (x = 0; x < NUM_MASSES_X; x++)
    {
      disp_val = ((int) current[x][y] + 16);
      if (disp_val > 32) disp_val = 32;
      else if (disp_val < 0) disp_val = 0;
      Bitmap[y*NUM_MASSES_X+x] = RGBmap[disp_val];
    }
  }

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?

  DosRequestMutexSem(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), &Bitmap[0], pbmi);
  GpiBitBlt(hps, hpsMemory, 3L, aptl, ROP_SRCCOPY, BBO_AND);

  DosReleaseMutexSem(hmtxLock);

It then locks the screen memory, and then sets up the copy & uses the magical GpiBitBlt to copy it to the video memory, then releases the lock. This all looks like something I can totally use!

I then have it call the old ‘main’ procedure form Sarien as a thread, and have it source the image from the Sarien temporary screen buffer

disp_val = ((int) screen_buffer[y*NUM_MASSES_X+x] );

Which all looks simple enough!

Y/X instead of X/Y!

And WOW it did something! I of course, have no keyboard, so can’t hit enter, and I screwed up the coordinates. I turned off the keyboard read, flipped the X/Y and was greeted with this!

Welcome to OS/2 where the memory is the total opposite of what you expect.

And it’s backwards. And upside down. But it clearly is rendering into FastGPI’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’m using Qemu 0.80 which is very fast) and even if there was keyboard input it’d be totally unplayable in this reversed/reversed state.

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.

  {
    for (x = 0; x < NUM_MASSES_X; x++)
    {
      disp_val = ((int) screen_buffer[y*NUM_MASSES_X+x] );	//+ 16);
      if (disp_val > 32) disp_val = 32;
      else if (disp_val < 0) disp_val = 0;
      Bitmap[((NUM_MASSES_Y-y)*(NUM_MASSES_X))-(NUM_MASSES_X-x)] = RGBmap[disp_val];
    }
  }
Running in the correct orientation

Now comes the next fun part, colour.

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’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.

This handy image is from the The 8-Bit Guy’s video “CGA Graphics – Not as bad as you thought!” but here are the four possible sets:

All the possible CGA choices

And of course I got super lucky with finding this image:

So now I could just manually populate the OS/2 palette with the appropriate CGA mapping, just like how it worked in MS-DOS:

First define the colours:

#define 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

Then map the 16 colours onto the CGA 4 colours:

OS2palette[0]=CGA_00;
OS2palette[1]=CGA_11;
OS2palette[2]=CGA_11;
OS2palette[3]=CGA_11;
OS2palette[4]=CGA_13;
OS2palette[5]=CGA_13;
OS2palette[6]=CGA_13;
OS2palette[7]=CGA_15;
OS2palette[8]=CGA_00;
OS2palette[9]=CGA_11;
OS2palette[10]=CGA_11;
OS2palette[11]=CGA_11;
OS2palette[12]=CGA_13;
OS2palette[13]=CGA_13;
OS2palette[14]=CGA_13;
OS2palette[15]=CGA_15;
CGA on PM!

So now it’s looking right but there is no timer so on modern machines via emulation it runs at warp speed. And that’s where OS/2 shows its origins is that it’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.

static void Timer(){
for(;;){
	DosSleep(20);
	clock_ticks++;
	}
}

And it crashed. Turns out that I wasn’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.

Eventually I got it sorted out.

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’s the PS/2 model 60), but nothing much on actually being useful about it.

Eventually through a lot of trial and error, well a lot of errors I had worked uppon this:

    case WM_CHAR:
      if (SHORT1FROMMP(parm1) & 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;
      } 

I had cheated and just introduced 2 new variables, key_from, pm_keypress 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’t want to introduce more mutexes, more locking and queues or DIY circular buffers. I’m at the KISS stage still.

I’m not sure why it was dropping letters, I would hit ‘d’ 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!

Roger walks for the first time!

And just like that, Roger Wilco now walks.

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…

Sarien for OS/2 running at 16Mhz

And it’s basically unplayable on my PS/2 model 80. Even with the 32bit XGA-2 video card.

I had to give it a shot under 86Box, to try the CGA/EGA versions:

CGA

It’s weird how the image distorts! Although the black and white mapping seems to work fine.

Sarien on EGA

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.

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’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.

So how long did it take to get from there to here? Shockingly not that much time, 02/20/2024 6:02 PM for running FastGPI, to 02/20/2024 10:56 PM For the first image being displayed in Presentation Manager, and finally 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’d have in 1990 (I didn’t get a 286 until late 91? early 92?), compiling Sarien on the PS/2 takes 30-40 minutes and that’s with the ultra-fast BlueSCSI, compared to even using MS-DOS Player I can get a build in about a minute without even compiling in parallel.

I’ve put the source over on github: neozeed/sarienPM: Sarien for OS/2 (github.com)

I think the best way to distribute this is in object form, so I’ve created both a zip & disk image containing the source & objects, so you can link natively on your machine, just copy the contents of the floppy somewhere and just run ‘build.cmd’ which will invoke the system linker, LINK386 to do it’s job. I have put both the libc & os2386 libraries on the disk so it should just work about everywhere. Or it did for me!

So that’s my quick story over the last few days working on & off on this simple port of Sarien to OS/2 Presentation Manager. As always, I want to give thanks to my Patrons!

Thunking for fun & a lack of profit

So, with a renewed interest in OS/2 betas, I’d been getting stuff into the direction of doing some full screen video. I’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 Q59837 which shows how to map into the MDA card’s text RAM and clear it.

It’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 cl386 experiments and that went off the edge. First there are some very slick macros, and Microsoft C just can’t deal with them. Fine I’ll use GCC. 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.

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 & mouse support and go all in on the graphical Presentation Manager.

Presentation Manager from OS/2 6.605

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’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.

Then I tried one of the earlier PM looking betas 6.605, and quickly it crashed!

SYS2070:

Well this was weird. Obviously, I wanted to display help

Explanation:

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 low level assembly, that actually implemented the thunking.

EXTRN   DosFlatToSel:PROC
EXTRN   DosSelToFlat:PROC

After looking at the doscalls import library, sure enough they just don’t exist. I did the most unspeakable thing and looked at the online help for guidance:

No VIO

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.

YUCK

For anyone crazy enough to care, I uploaded this onto github Q59837-mono

It did work on the GA however so I guess I’m still on track there.

Announcing EmuWoW Beta 1 (AXP Preview1)

Freecell & Winver

This is a guest post by CaptainWillStarblazer

Hello, everyone. This is a continuation of my previous blogpost on EmuWoW (formerly win32emu) found here, but to summarize, I’m the 18-year-old developer behind a project that allows running applications compiled for the MIPS/Alpha version of Windows NT on standard x86 PCs through emulation, but without requiring a full system emulator. Since that last post, the project has made some substantial strides.

Since then, I’ve adapted the MIPS emulator from MAME, which is both more accurate and faster than my own (writing my own was a fun exercise but to the end of running applications, borrowing an emulator was a better decision). This alone enabled WinMine to function, which can be seen below.

Winmine for MIPS!

Around the same time, another VirtuallyFun member named x86matthew entered the scene. His prior credits include a similar project, for Win16. He was inspired by the initial win32emu blog post, created his own similar project called WoWMIPS, which quickly started running a few simple apps, such as WinMine, Solitaire, and Notepad. Be sure to check out WoWMIPS – MIPS Emulator for Windows, Part 1: Introduction, and parts 2,3,4,5,6!

This had actually been what I was hoping for from the beginning; I always saw win32emu as a proof of concept for a smarter person (either myself in the future or someone else altogether) to come back later and do it better, and this is a massive undertaking for a single individual. What makes x86matthew’s WoWMIPS so incredible is its clean design. For one, there’s no thunk DLLs required. When an application tries to import a DLL, the host x86 DLL is first loaded, and then any attempts to get the address of an exported procedure from it are then redirected to an auto-generated stub of MIPS code which invokes the emulator to call the function. In other words, the thunk DLLs are generated at load time. Additionally, there’s no window procedure thunks required either. Instead, MIPS code pages are marked as non-executable, causing an access violation when Windows attempts to call them. Using an exception handler implemented via Windows XP’s Vectored Exception Handling feature, one can detect this and then invoke the emulator to execute the callback. Storing the CPU state in thread-local-storage allowed proper support for multithreading. I duplicated these design choices into EmuWoW, and the results largely speak for themselves. Unlike WoWMIPS (at time of writing), EmuWoW is still capable of loading MIPS DLLs (and will prefer to do so if possible), however.

Various MIPS Windows NT applications running

To aid the process of fixing faults in the emulator, I hacked up a quick, minimal debugger into EmuWoW. First of all, there’s a “crash screen” which will indicate the type of error and dump registers and the current instruction if there’s a fault, and a running disassembly can be printed as you go, but most crucially, there’s a limited degree of interactive debugging functionality.

The built in debugger to EmuWow

The main capabilities contained herein are dumping registers and memory to the screen, disassembling regions of memory, listing loaded modules, getting import entry points, setting breakpoints, and single-stepping, along with printing functions. It’s no gdb (especially for the lack of PDB symbol support), but it’s something.

MIPS is all well and good, however, but we can already emulate Windows NT for MIPS. MIPS is a fairly clean, simple architecture, often used for teaching, and short of weirdness like delay slots, is dead simple to emulate. And it fits the bill for what I’m trying to do here – a RISC architecture Microsoft abandoned, fixed-length 32-bit instructions, the works. However, adding support for the DEC Alpha AXP will finally get this project to where it was intended to be from the beginning, and I hope for it to eventually be able to run the Visual C++ compiler toolchain under EmuWoW. Being able to compile (and even test!) Alpha apps on readily available modern PCs will be a game-changer, and I intentionally wrote EmuWoW to be CPU-agnostic, so adding rudimentary support for the Alpha wasn’t difficult. Like with MIPS, I lifted the emulator from MAME. This admittedly did pose some challenges, due to MAME’s use of C++ features such as

  • Classes (which I had to substitute for passing pointers to structs)
  • Templates (which I had to substitute for macros)
  • Function-style casts (which I had to change into C-style casts)

There was a lot of weirdness in how Alpha function calls, but it was my misunderstanding of the calling convention, and when to consider values to be 32-bit vs 64-bit posed a modest issue, but I got it to the point where some very simple DEC Alpha programs started to run, though many of them have various issues.

Various Dec Alpha Windows NT applications running

This is the first time this has ever been possible; emulation of AXP NT programs on standard PCs has just become possible now. I’m hoping to see EmuWoW continue to evolve, and I welcome contributions, whether that be improving support for the CPUs I already have, adding support for another (such as PowerPC) or anything else. To take a look at the code, go to github.com/bhty/emuwow and to download EmuWoW and try it out for yourself, click here.

New version of the MS-DOS Player

And it’s a big update on takeda-toshiya.my.coocan.jp!

From cracyc and roytam’s 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 of the i386 core have been modified based on the DOSBox implementation.
With the Pentium 4 version, the testi386.exe is the same as the real thing.

The I386 core of NP21/W has been updated to equivalent to ver0.86 rev92 beta2.
Also, fixed the build time warning so that it does not appear.

Improved checking when accessing environment variables, referencing incorrect environment tables.
Recent builds have resolved an issue that prevented testi386.exe from working.
Improved the efficiency of memory access handling.
Basic memory, extended memory, and reserved areas (such as VRAM) can be accessed in that order with a small number of conditional branches.
The processing speed may be slightly increased.

MS-DOS Player for Win32-x64 Mystery WIP Page (coocan.jp)

Takeda has been very busy indeed!

I don’t want to complain or anything, I’m very thankful for the tool. It’s just so amazing.

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, msdos-player_. 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’d just crash.

No console changes, no crashes.

OK so you can run some basic stuff like compilers, but what about ORACLE?!

Oracle 5!

I did have to subst a drive, as I didn’t feel like dealing with paths and stuff, I had extracted it from oracle-51c-qemu, and modified the autoexec & 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.

OK, but how about something even more complicated?! NETWARE!

Netware 3.12 on MS-DOS Player

Obviously there is no ISA MFM/IDE disks in MS-DOS Player, but the server loaded!

Needless to say this update is just GREAT!

I’d say try the one hosted on Takeda’s site! It’ll almost certainly work fine for you. Otherwise I guess try mine. Or not.

Getting Graylog onto the internet

A while back I had made a small post about getting Graylog running on Windows. It was fun, as it’s just JAVA so you know it should be portable, and other than some weird disk access thing it does seem to run fine.

Of course, the next step is to create a dashboard to replace what I used on wp-statistics, as it was crashing taking up 100% of my CPU, and exceeding PHP’s 12GB of RAM per process limit. You know things are messed up when I’m replacing you with not one, but 2 Java apps! (Graylog & Opensearch).

magical dashboard

It’s by no means perfect, but the guide How to se -up graylog geoip configuration, is all around great to have. The rest of it is me learning how to do aggregate searches, and simple lists, to see latest hits, 404’s and count the pages and build a graph.

Again, this is all good, now for the real question, how to get this onto the Internet?!

The firs thing to do is enable cors.. It’s for being on the internet!

http_enable_cors = true

Next enable the external URI name

http_external_uri = https://dash.board.com/

And now the changes I had to make in my haproxy config

frontend http-in
        acl host_graylog hdr(host) -i dash.board.com
        http-request set-uri %[path,regsub(/api/api,/api)] if host_graylog
        use_backend graylog if host_graylog

backend graylog
        option forwardfor
        http-request add-header X-Forwarded-Host %[req.hdr(host)]

        acl bad_ct path_end .js
        http-response set-header Content-Type application/javascript if bad_ct

        http-request set-header X-Graylog-Server-URL http://192.168.33.5:9000
        server graylog 192.168.23.33:9000 maxconn 20 check

I kind of wish I saved the logs while going crazy but YES for some reason it’ll try to reference itself as /api/api. I don’t know why, so I had to do some uri regex to fix that. Neat!

Next for some reason Graylog responds that all .js (javascript) files are actually text. Chrome doesn’t allow that to work, so yes you need to set the content type header to “application/javascript” for Chrome to be happy.

I had wasted over an hour with this and couldn’t get it working. So, I walked away for a few hours, and it suddenly was working. I think Cloudflare was doing some caching against it.

This is probably too terse to be really useful, and I lost all the pages I was reading about setting stuff in haproxy as I was doing that incognito. Oops. I picked this config out of fragments from five other people’s stuff. There is other considerations to host it on a subdirectory of a public site, but I just wanted to K.I.S.S.

Targeting OS/2 with Visual Studio 2003

Sydney’s idea of what Visual C++ for OS/2 should look like

No, it’s not a typo.

This is a long-winded post, but the short version is that I found a working combination to get the C compiler from Visual Studio 2003 targeting OS/2.

Once I’d learned how C compilers are a collection of programs working in concert, I’d always wanted to force Microsoft C to work in that fashion, however it is born to be a compiler that integrates everything but linking. There has been a “/Fa” or output assembly option, but I’ve never gotten it to do anything useful. I’m not that much into assembly but it seemed insurmountable.

But for some reason this time things were different.

This time I used:

Microsoft (R) Macro Assembler Version 6.11

After the great divorce and the rise of Windows NT, Microsoft had shifted from the OMF format to COFF. However somewhere buried in their old tools it still supports it, namely MASM. For example, if I try to run LINK386 (the OS/2 Linker) against output from Visual C++ 2003 I get his

abandon.obj :  fatal error L1101: invalid object module
 Object file offset: 1  Record type: 4c

However if I output to assembly and then have MASM assemble that, and try the linker, I’m bombarded with errors like this:

warp.obj(warp.asm) :  error L2025: __real@4059000000000000 : symbol defined more than once
warp.obj(warp.asm) :  error L2029: '__ftol2' : unresolved external

If I was smart I’d have given up, there is pages and pages of this stuff. But I’m not smart, so instead I decided to something different, and use SED, the stream editor, and try to patch out the errors.

The ftol2 call is for newer CPU’s and any OS/2 library won’t have it. But instead of binary editing symbols we can replace the ftol2 with ftol with this simple line:

 sed -e 's/_ftol2/_ftol/g'

For some reason Visual C++ likes to make all it’s reals “public” meaning there can only be one, but yet there is so many. Why not comment them all out?

sed -e 's/PUBLIC\t__real@/;PUBLIC\t__real@/g'

And there are various other annoying things, but again they can be all patched out. Just as the older Windows 1991 Pre-release compilers also have weird syntax that MASM doesn’t understand.

astro.asm(59): error A2138: invalid data initializer

which goes into how Microsoft C used to initialize floating point constants:

CONST   SEGMENT  DWORD USE32 PUBLIC 'CONST'
$T20000         DQ      0a0ce51293ee845c8r    ; 1.157407407407407E-05
$T20001         DQ      0bffffd3441429ec5r    ; 2440587.499999667
CONST      ENDS

while I found that the C compiler in Xenix 386 initialises them like this:

$T20000         DQ      0a0ce51293ee845c8h    ; 1.157407407407407E-05
$T20001         DQ      0bffffd3441429ec5h    ; 2440587.499999667

This one was a little hard for me as I’m not a sed expert, but I did figure out how to mark the section, and then to replace it

sed -e "s/DQ\t[0-9a-f]r/&XMMMMMMX/g" $.a1 |  sed -e "s/rXMMMMMMX/H/g"

And so on. At the moment my ‘mangle’ script is now this:

.c.obj:
        $(CC) $(INC) $(OPT) $(DEBUG) /c /Fa$*.a $*.c
        wsl sed -e 's/FLAT://g' $*.a > $*.a1
        wsl sed -e "s/DQ\t[0-9a-f]*r/&XMMMMMMX/g" $*.a1 \
        | wsl sed -e "s/rXMMMMMMX/H/g" \
        | wsl sed -e 's/call \t\[/call DWORD PTR\[/g' \
        | wsl sed -e 's/PUBLIC\t__real@/;PUBLIC\t__real@/g' \
        | wsl sed -e 's/_ftol2/_ftol/g' > $*.asm
        ml /c $*.asm
        del $*.a $*.a1 $*.asm

This allows me to plug it into a Makefile, so I only have to edit it in one place.

Not surprisingly, this allows the LINK from Visual C++ 1.0 to link the MASM generated object files and get a native Win32 executable. Even from the oldest compiler I have from the Microsoft OS/2 2.00 Beta 2 SDK from 1989!

But now that we have the C compilers being able to output to something we can edit and force into a Win32, there is a few more things and suddenly:

        C:\cl386-research\bin.10.6030\cl386 /u /w /G3 /O  /c /Faphoon.a phoon.c
C:\cl386-research\bin.10.6030\CL386.EXE: warning: invoking C:\cl386-research\bin.10.6030\CL.EXE
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.6030 for 80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.

phoon.c
        wsl sed -e 's/FLAT://g' phoon.a > phoon.a1
        wsl sed -e "s/DQ\t[0-9a-f]*r/&XMMMMMMX/g" phoon.a1  | wsl sed -e "s/rXMMMMMMX/H/g"  | wsl sed -e 's/call \t\[/call DWORD PTR\[/g'  | wsl sed -e 's/PUBLIC\t__real@/;PUBLIC\t__real@/g'  | wsl sed -e 's/_ftol2/_ftol/g' > phoon.asm
        ml /c phoon.asm
Microsoft (R) Macro Assembler Version 6.11
Copyright (C) Microsoft Corp 1981-1993.  All rights reserved.

 Assembling: phoon.asm
        del phoon.a phoon.a1 phoon.asm
        msdos286 run286 C:\cl386-research\bin\ddk12\LINK386.EXE @phoon.lnk

Operating System/2 Linear Executable Linker
Version 2.01.012 Nov 02 1993
Copyright (C) IBM Corporation 1988-1993.
Copyright (C) Microsoft Corp. 1988-1993.
 All rights reserved.

Object Modules [.obj]: astro.obj date_p.obj phoon.obj
Run File [astro.exe]: phoon2 /NOE /NOI /NOD:OLDNAMES
List File [nul.map]: nul.map
Libraries [.lib]: ..\..\lib2\libc.lib +
Libraries [.lib]: ..\..\lib2\os2386.lib
Definitions File [nul.def]: nul.def;
LINK386 :  warning L4071: application type not specified; assuming WINDOWCOMPAT

I know it’s a bit of a word salad, but the key thing here is that using Visual C++ 2003’s compiler (version 13.10.6030), and outputting to assembly that we can edit, we can then use MASM to build objects that surprisingly LINK386 version 2.01.012 will link with. I suspect this has to do with device drivers, and probably the majority of the OS/2 operating system.

Anways, we’ve done the incredible, using the same object files, we made both a Win32 application, and an OS/2 application!

phoon-13.10.6030.exe: PE32 executable (console) Intel 80386, for MS Windows
phoon2.exe: MS-DOS executable, LX for OS/2 (console) i80386
Phoon compiled by Visual C++ 2003 on OS/2 2.00

Incidentally Happy CNY!

Obviously, this is VERY cool stuff.

I know the next question is do we have to rely on a 16bit linker? How about Watcom?

C:\cl386-research\proj\trek>wlink @trek.wlk
WATCOM Linker Version 10.0
Copyright by WATCOM International Corp. 1985, 1994. All rights reserved.
WATCOM is a trademark of WATCOM International Corp.
loading object files
searching libraries
Warning(1008): cannot open LIBC.lib : No such file or directory
Warning(1008): cannot open OLDNAMES.lib : No such file or directory
creating an OS/2 32-bit executable

Ignore the warnings and YES we can Link from something much newer & 32bit! In this example I linked the old TREK game, also built with Visual C++ 2003. The response file looks lke:

SYS os2v2
NAME trek2w
FILE abandon.obj,attack.obj,autover.obj,capture.obj,cgetc.obj,checkcond.obj
FILE check_out.obj,compkl.obj,computer.obj,damage.obj,damaged.obj,dcrept.obj
FILE destruct.obj,dock.obj,dumpgame.obj,dumpme.obj,dumpssradio.obj,events.obj
FILE externs.obj,getcodi.obj,getpar.obj,help.obj,impulse.obj,initquad.obj
FILE kill.obj,klmove.obj,lose.obj,lrscan.obj,main.OBJ,move.obj
FILE nova.obj,nullsleep.obj,out.obj,phaser.obj,play.obj,ram.obj
FILE ranf.obj,rest.obj,schedule.obj,score.obj,setup.obj,setwarp.obj
FILE shield.obj,snova.obj,srscan.obj,systemname.obj,torped.obj,utility.obj
FILE visual.obj,warp.obj,win.obj
LIBR ..\..\lib2\LIBC.LIB
LIBR ..\..\lib2\OS2386.LIB

It’s probably needing additional stack space, maybe some other stuff, or resources, maybe how to flag it’s windowing compatible.

TREK built by Visual C++ 2003, and Linked using Watcom C/C++ 10.0

How do I get started, if I dare?! First download and unpack cl386-research-v2. Ideally on the root of your C: drive, because why not?

run the ‘env’ command to set your environment up. Its pretty complicated but in the proj directly there is currently:

*NOTE that I do use SED scripts, I have it set to use Linux in the WSL package.
I tried some Win32 sed but it didn’t work. So you need WSL or a working sed!

you can then go into each directory and run

make os2

and it’ll compile populate a floppy and launch the emulator

Its all good fun.

Read the Makefiles to configure a compiler, how to run it, and if you need to mangle the assembly. The 32bit new stuff needs to be mangled, the older stuff almost always works with just compile.

# Version 6.00.054      1989
# https://archive.org/details/os-2-cd-rom_202401
PLATFORM = ddksrc

In this case it’ll select the platform from the ‘ddksdk’ release. The next is if the compiler is OS/2 based or native win32. Basically 73g / windows 95 & below are native Win32.

In the above example we comment out the dos extended cross

# dos exteded cross
CC =  $(EMU) $(DOSX) $(CL386ROOT)$(PLATFORM)\cl386
# native CC
# CC =  $(CL386ROOT)$(PLATFORM)\cl386

Next is the mangle strategy. In this case it’s an ancient OS/2 (like) compile so
try un commenting the ‘just compile’ line

# must include ONLY ONE strategey..
# for OS/2 it must have been assembled my MASM 6.11

include ..\-justcompile.mak
#include ..\-mangleassembly.mak
#include ..\-plainassembly.mak

save the makefile, and run

nmake os2

You can just close the emulator as after each run it’ll unpack a hard disk image, so nothing will be lost. or saved. It’s just for testing. You may need to periodically clean the floppy drive, as that is the only way to transfer stuff in and out of the VM.

What versions of CL386 have I found? Well, it’s quite a few, although I know I’m missing quite a few.

== c386 ============================
Microsoft C 5 386 Compiler

Microsoft C 5.2 286/386 Compiler -- Driver

@(#)C Compiler Apr 19 1990 11:48:30

Copyright (c) Microsoft Corp
1984-1989. All rights reserved.
  (press <return> to continue)
Microsoft 386 C Compiler. Version 1.00.075
Quick C Compiler Version 2.00.000
1.00.075

== ddk12 ============================

C 6.00 (Alpha) Aug 24 1990 19:12:31

Copyright (c) Microsoft Corp
1984-1989. All rights reserved.
  (press <return> to continue)
Microsoft 386 C Compiler. Version 6.00.054
Quick C Compiler Version 2.00.000
6.00.054

== ddk20 ============================

C 6.00 (Alpha) Aug 16 1990 23:04:06

Copyright (c) Microsoft Corp
1984-1989. All rights reserved.
  (press <return> to continue)
Microsoft 386 C Compiler. Version 6.00.054
Quick C Compiler Version 2.00.000
6.00.054

== ddksrc ============================

C 6.00 (Alpha) Aug 24 1990 19:21:49

Copyright (c) Microsoft Corp
1984-1989. All rights reserved.
  (press <return> to continue)
Microsoft 386 C Compiler. Version 6.00.054
Quick C Compiler Version 2.00.000
6.00.054

== nt-sep ============================

@(#)C Compiler 6.00 Feb 06 1991 17:15:19
@(#)C Compiler 6.00 May 13 1991 23:54:12
@(#)C Compiler 6.00 Jun 03 1991 15:16:22


Copyright (c) Microsoft Corp
1984-1991. All rights reserved.
  (press <return> to continue)
Microsoft 386 C Compiler. Version 6.00.077
Quick C Compiler Version 2.00.000
6.00.077

== nt-oct ============================

@(#)C Compiler 6.00 Jun 03 1991 15:16:22
@(#)C Compiler 6.00 Jun 13 1991 22:07:23
@(#)C Compiler 6.00 Oct 10 1991 00:42:24

Copyright (c) Microsoft Corp
1984-1991. All rights reserved.
  (press <return> to continue)
Microsoft 386 C Compiler. Version 6.00.080
Quick C Compiler Version 2.00.000
6.00.080

== nt-dec ============================
@(#)C Compiler 6.00 Jun 03 1991 15:16:22
@(#)C Compiler 6.00 Jun 13 1991 22:07:23
@(#)C Compiler 6.00 Oct 10 1991 00:42:24

Copyright (c) Microsoft Corp
1984-1991. All rights reserved.
  (press <return> to continue)
Microsoft 386 C Compiler. Version 6.00.081
Quick C Compiler Version 2.00.000
6.00.081

== 73g  ============================
1984-1993. All rights reserved.
Copyright (c) Microsoft Corp
8.00.3200
32-bit C/C++ Optimizing Compiler Version
Microsoft (R)


== msvc32s ============================

Microsoft 8.00.0000 - Copyright (C) 1986-1993 Microsoft Corp.
Microsoft 8.00.0000 - Copyright (C) 1986-1993 Microsoft Corp.
@(#) Microsoft C/C++ 32 bits x86 Compiler Version 8.00.XXXX

8.00.000

== 13.10.6030 ============================

Microsoft (R) C/C++ Compiler Version 13.10.6030
From my install of Visual Studio 2003 Enterprise

As you can see many of these earlier OS/2 compilers report the same versions but are in fact different builds on the inside. I suspect Microsoft had to support one version, and an Alpha version of version 6 is as good as it got. I would have imagined there were internal 32bit versions of 6 or 7, but I haven’t seen them.

Compiling and running TREK

Hopefully this gives some idea of how I tried to made a probably too modular build system to try all kinds of different compilers. I might have to see if it’s possible to run the tools from the 1992 versions of Windows NT in this setup, perhaps they are interesting as well.

One thing in my porting GCC to OS/2 experience is that the usability of the C compilers from 1991 were dramatically better than what Microsoft had given IBM at the time of the divorce. No doubt the upcoming NTOS/2 project was placing a bigger demand on the tools team.

If anyone has any access to other ‘cl386’ compilers, or early OS/2 2.00 stuff, please let me know! I’d love to do build/tests and see if my idea of distributing objects ‘just works’!

Porting GCC to 32bit OS/2

I know what you are going to think, that it was already done, and it was called EMX. Or was it GCC/2? Well sure but what if you are not running the GA (General availability) version of OS/2. For example, years ago I had managed to get Citrix Multiuser 2.0, and it’s not at the GA level. All that is available is some ancient beta version of Microsoft C 5.2 from 1989?!

A little while back I had worked on getting GCC to build and run on the FPU enabled versions of Windows NT from 1991. I had mentioned that it turns out thanks to the Xenix assembler, that GCC had been basically available the entire time Windows NT had been available, but lamented that since the OS/2 compiler is 16/32bit, the 5.2 compiler couldn’t handle compiling GCC without blowing it’s heap. 16bit issues in a 64bit world.

However after doing some research on all the early cl386 compilers I could get my hands on, including the Windows NT Pre-release ones, I’d noticed that if I built CC1.EXE (the actual compiler) first for Win32, then rebuilt those object files with the December NT Pre-release compiler, that some versions of LINK386 from the OS/2 2.1 DDK would actually link with them. And sure enough it worked!

First life of GCC on OS/2

I have to admit I was pretty amazed, I had managed to ‘cross compile’ GCC using quite the tool chain.

First the compiler from the December NT Pre-release CD-ROM is shipped as a 16bit OS/2 compiler, but I’m using Windows 11. First I use the MS-DOS player with a quick fix from crazyc to allow Phar Lap 286|Dos Extender to run, which provides a basic enough OS/2 emulation to allow the compiler to run under ‘dos’. The linker on the DDK suffers the same fate as far as it also being 16bit. However the combination of MS-DOS player & Phar Lap gets stuff working! The only weird catch is that the 386 emulator causes strange floating point related crashes, while the 286 or 486 emulators work fine.

Now targeting OS/2 or running on OS/2 isn’t all that new, but building it from a Microsoft C compiler is. And now of course you’ll ask yourself, who cares? why is it interesting?

Well, the vast majority of the GCC ports to OS/2 don’t support the OMF object file binary standard, instead they used the much outdated a.out format, and rely on tools to convert the objects if needed. Additionally, they have DLL dependencies, and other startup issues with things needing to be setup. And of course they rely on a binary standard that is ‘GA’. *HOWEVER* by using a Microsoft compiler, I have OMF object files that the OS/2 built in system linker LINK386 can understand. So in plain English I can just relink the compiler and it’ll run on a new ‘version’ of unsupported OS/2.

I made a diskette image with my objects & a linker script and in a few moments I had it running!

GCC running on OS/2 2.00 6.123

The substantial thing here is that the binary format for OS/2 changed twice, and each release introduced changes that broke binary compatibility, in an effort to force people onto the new tools. So there is no way that the old ‘LE’ format would ever work. And you can see it’s running! In addition I could take the same object files, and copy them to my Citrix server, and likewise it was just a matter of linking, and it too now has GCC!

Converting a.out to OMF via emxomf

One annoying thing is that the LINK386 that ships with OS/2 2.00 GA doesn’t like the output of the Xenix assembler, so I built the a.out traditional assembler, and the emxomf tool to convert the a.out to OMF, and that worked well.

I still have much to mess with, including the pre-processor & main ‘gcc’ program. I have not built anything beyond a trivial program, so there is indeed much more work to be done before I can even try anything challenging. Some programs like emxomf have portions in the debug support that require the ‘long long’ type, which obviously Microsoft compilers from 1989-1991 don’t have, so I’ll have to re-build them with GCC.

Ive been putting my ports onto github (cl386-research) as it handles the rapid changes well enough. It’s a bit of a complex setup and it involves using a build system that I’ve put over on archive.org here: cl386-research-v2.

Not that I can imagine anyone wanting to try but I’ve uploaded some disks with the objects. Copy them to a hard drive, and run the ‘build.cmd’ command and it’ll link to a native freestanding executable.

I’ll explain it more with a post later, along with going over all the versions of cl386 I’ve acquired, over the years in more of a part 2: Targeting OS/2 with Visual Studio 2003!

Modernising the National Geographic CD-ROM collection

The fancy collector’s box set

I wanted to get some research into some early space flight, and look into that magical transition when everything went from Cowboys & Indians to moonmen & the race to space. Granted Toy Story covers cultural touchstone pretty well, reading period pieces is fun too. I had a few CD-ROM’s containing the 1980’s National Geographic CD-ROM’s when they were sold up in decade sets, but what always escaped me was the fancy collectors box with the whole thing.

$169!!

I always figured this was going to be one of those weird collectors’ items that probably was under produced, over sold, and lost to the winds of time. Looking on eBay for a 1950’s and 1960’s set .. and thinking about the 1970’s as well, and it was going to get close to £40. Ouch. So for the heck of it, I look for the fancy box set.

wow

I was surprised for as much as I was going to end up paying for one or two sets, I could get the entire thing. In the legendary fancy wooden box. I got mine, shipped for under £20. Much wow!

Okay what is the catch?

Wait a minute, these National Geographic CDs are obsolete!Christopher Elliott

I always was running mine on MacOS using Cockatrice III with the monitor resolution set to the absolutely absurd resolution of 1152×870 provided by the 1991 21″ monitor. I couldn’t imagine why these CD’s wouldn’t work. And of course the first step was to rip the CD-ROM’s. There was 31 National Geographic, and an additional clip art disc in my box. I fired up my XP machine to have it’s hard disk give up and die on me. Luckily since I had removed the mechanical disk from the iMac G5, I had a spare SATA disk handy. I didn’t feel like fighting the XP installer, and I’m impatient, so I made a netboot.xyz bootable flash drive, and installed Debian 10 over the internet. Very nice. Now I could get down to ripping CD’s. Luckily the drive from the DVD-RAM drive disaster reads at 48x, so it took me under 4 hours to rip them all. In case you are wondering:

32 File(s) 17,894,987,776 bytes

The flash drive I used is 32Gb. I got it in a 3 pack from Tesco. I think I paid £10 for it. That means UTZOO + NatGEO all fit one of the drives. I wonder if they’ll ever offer high resolution scans on a USB drive in a fancy wooden box?

For the hell of it, I used 7zip to decompress all the ISO’s and that’s when I noticed that although the files were spread over discs there was a clean decade break between volumes from the 1900’s, and that they had a logic to them.

On the NGS_1956_1959 CD-ROM there is a hierarchy something like this:

E:\IMAGES\256I

The 2 is for the 20th century, and 56 is the year. I is the month; in this case I is September. Since we live in the future, and rendering jpeg’s is quicker than real-time, 256IC01A.JPG can be shown to be the cover. The next pattern is for the adverts, 256IA02A.JPG – 256IA30A.JPG are the into adverts. Now, we get to the interior content 256I0287.JPG – 256I0426.JPG. Next is the closing/trailer advertisements 256IZ01Z.JPG – 256IZ13Z.JPG. And Finally the back of the issue, 256IB14Z.JPG is the rear of the magazine.

So we now have some understanding of the format. Putting this into order could be done with something simple like this:

find ./ -name '2[0-9][0-9]IC[0-9]*.JPG' > interior
find ./ -name '2[0-9][0-9]IA[0-9]*A.JPG' >> interior
find ./ -name '2[0-9][0-9]I[0-9]*.JPG' >> interior
find ./ -name '2[0-9][0-9]IZ[0-9]*Z.JPG' >> interior
find ./ -name '2[0-9][0-9]IB[0-9]*Z.JPG' >> interior

Doing so makes a nice list file of what images should go in which order. I could probably use ffmpeg and painstakingly check the images for ‘pullouts/double wide’ ones, and have it stitch the rest together as a two pager ( ffmpeg -i left.jpg -i right.jpg -filter_complex hstack combined.jpg ), but that still sounds like a lot of work. Also the images are very low quality, It’s a shame they didn’t use black & white on the text, and scan the images separately, but that’d require something like PDF, and no doubt a LOT of time. Although Kodak did sponsor the set, the developer, Mindscape didn’t go with fancy PDF technology of the late 1990s, instead it’s just the blurry jpeg scans we have today.

NG July 1981

That’s when I found out about Tesseract. Running it against this one paragraph reveals:

Voyager is watching two small moons
that-seem to be playing tag as they race
around Saturn in almost the same orbit. The
trailing moon is traveling faster than the
leader, and should catch up with the leader
in January 1982 (pages 20-21). The two pre-
sumably have been playing this game for
billions of years, Through what sleight of
physics do they avoid colliding?

National Geographic, July 1981

I have to admit, that’s pretty good! And how amazing that I have a LOT of files to scan.

188553 File(s) 11,061,111,690 bytes

That is a LOT of files. Okay that’s nice, but can Tesseract read the list that I generated per issue? YES. The only thing that I’d love to see Tesseract do is create PDF’s with the scanned text embedded. OH WAIT, IT ALREADY DOES THAT!

How on earth did I not know this?

I put together a few scripts, and I was able to separate out all the images into years & months, then I created the needed list files with all the images in the correct order. It’s not a fast process I think it may take me a week or so to do this.

My CPU hates me

So far, I’m up to 1903, so I’ll update with some rough idea of when this finished.

So, the applications needed are old and obsolete Win16 or Classic MacOS needed machines, with an optical drive. Yes they still work (with emulation) on modern machines, although you still need to read the physical discs. Thankfully the images are easily mapped into the right order, and you can map them as your own. Neat!